본문 바로가기

Dreamhack/웹해킹

[LEVEL 1] type confusion

웹 서비스에 접속하면 비밀번호 입력창과 확인 버튼이 제공된 매우 단순한 화면이 나타납니다. 하단에는 소스 코드를 확인할 수 있는 view-source 링크가 함께 배치되어 있습니다.

 

 

앞서 살펴본 입력창에 직접 값을 넣어 동작을 확인해보았습니다. 예시로 test라는 문자열을 입력한 뒤 확인 버튼을 눌러보았습니다.

 

 

view-source 링크를 통해 소스 코드를 확인해 보겠습니다.

 

view-source 

<?php
 if (isset($_GET['view-source'])) {
     show_source(__FILE__);
    exit();
 }
 if (isset($_POST['json'])) {
     usleep(500000);
     require("./lib.php"); // include for FLAG.
    $json = json_decode($_POST['json']);
    $key = gen_key();
    if ($json->key == $key) {
        $ret = ["code" => true, "flag" => $FLAG];
    } else {
        $ret = ["code" => false];
    }
    die(json_encode($ret));
 }

 function gen_key(){
     $key = uniqid("welcome to wargame.kr!_", true);
    $key = sha1($key);
     return $key;
 }
?>

<html>
    <head>
        <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
        <script src="./util.js"></script>
    </head>
    <body>
        <form onsubmit="return submit_check(this);">
            <input type="text" name="key" />
            <input type="submit" value="check" />
        </form>
        <a href="./?view-source">view-source</a>
    </body>
</html>
  1. JSON 데이터 처리.
    • usleep(500000): 0.5초(500,000 마이크로초) 동안 실행을 지연시킵니다. 이는 공격자가 무작위 대입 공격(Brute-force attack)을 시도하는 것을 방해하거나 시간 기반 공격(Timing attack)의 단서를 제공하기 위한 의도일 수 있습니다.
    • require("./lib.php"): lib.php 파일을 포함하여 $FLAG 변수를 가져옵니다.
    • json_decode($_POST['json']): POST로 전송된 JSON 형식의 문자열을 PHP 객체로 디코딩합니다.
    • gen_key(): gen_key 함수를 호출하여 서버 측에서 새로운 키를 생성합니다.
    • if ($json->key == $key): 디코딩된 JSON 객체의 key 값과 서버가 생성한 $key 값을 비교합니다. 이 두 값이 일치하면 ["code" => true, "flag" => $FLAG]를 반환하여 플래그를 노출합니다.
  2. gen_key() 함수
    • uniqid("welcome to wargame.kr!_", true): 현재 시간의 마이크로초를 기반으로 고유한 문자열을 생성합니다. 접두사로 "welcome to wargame.kr!_"를 사용하고, true 인자를 통해 더 많은 엔트로피를 추가합니다. 중요한 점은 이 함수가 호출될 때마다 완전히 새로운, 예측 불가능한 문자열을 생성한다는 것입니다.
    • sha1($key): 생성된 고유 문자열을 SHA-1 해시 함수로 변환합니다. 최종 키는 이 SHA-1 해시값입니다.

요청·응답을 정밀하게 관찰하기 위해 프록시 도구 Burp Suite를 사용했습니다.

 

 

Burp Suite를 통해 요청을 확인한 결과, 클라이언트에서 입력한 값은 JSON 형식으로 서버에 전달되는 것을 확인할 수 있었습니다. 실제로는 { "key": 입력값 } 형태로 POST 요청이 전송되며, 이 값이 서버 측에서 생성된 키와 비교되는 구조임을 알 수 있습니다.

 

 

저는 이번 문제에서 Type Confusion(자료형 혼동) 취약점에 대해 직접 확인을 진행했습니다. 핵심은 PHP의 느슨한 비교 연산자(==)가 서로 다른 자료형을 비교할 때 자동 형변환을 수행한다는 점입니다.

 

🔎 Type Confusion 이란?

Type Confusion은 프로그램이 자료형(Type) 을 잘못 해석하거나 혼동하도록 만들어, 의도치 않은 동작을 유발하는 취약점입니다. 주로 동적 타입 언어(PHP, JavaScript 등) 나 자동 형변환이 느슨한 언어에서 자주 발생합니다.

 

 

그래서 저는 아래와 같이 페이로드를 전송해보았습니다.

{"key": true}

왜 이렇게 보냈는가?

원래 코드에서는 서버가 생성한 SHA-1 문자열과 클라이언트가 전송한 key 값을 비교합니다.
처음에는 "key": "test"처럼 문자열을 넣어보았지만, 이 경우에는 서버에서 만든 해시 문자열과 절대 같을 수 없어 조건이 실패했습니다. 여기서 Type Confusion을 유도하기 위해 문자열이 아닌 불리언 값을 전송했습니다.

{"key": true}

PHP의 비교 규칙상, 불리언과 문자열을 비교할 경우 문자열은 불리언으로 변환됩니다. 해시 문자열은 비어 있지 않으므로 true로 변환되고, 결과적으로 true == true가 되어 조건이 항상 만족하게 됩니다.

 

 

이렇게 "key": true를 전송하면, 서버가 어떤 해시 값을 생성하더라도 무조건 조건을 만족하게 되어 플래그를 획득할 수 있었습니다.

 

 

 

'Dreamhack > 웹해킹' 카테고리의 다른 글

[LEVEL 1] Command Injection Advanced  (0) 2026.01.06
[LEVEL 1] error based sql injection  (0) 2026.01.05
[LEVEL 1] [wargame.kr] strcmp  (1) 2025.09.08
[LEVEL 1] [wargame.kr] fly me to the moon  (0) 2025.09.08
[LEVEL 1] csrf-2  (1) 2025.09.08