웹 서비스에 접속하면 비밀번호 입력창과 확인 버튼이 제공된 매우 단순한 화면이 나타납니다. 하단에는 소스 코드를 확인할 수 있는 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>
- 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]를 반환하여 플래그를 노출합니다.
- 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 |