Wargame.kr 포스트는 이해한 내용과 복습을 위한 목적으로 작성되었습니다.

이번 포스트에서는 type_confusion 문제에 대한 이해와 풀이를 진행해보도록 하겠습니다.


이번에는 생각해보면 간단한 문제이면서, 생각만으로는 어려운 문제입니다.


여기서는 JSON의 타입 오류를 이용하여 풀어야 합니다.




 

 문제 이해


문제는 다음과 같습니다.


문제를 보면, 단순 비교하는 문제라고 나타나 있습니다.


문제를 들어가면 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 auth_code function.
    $json = json_decode($_POST['json']);
    $key = gen_key();
    if ($json->key == $key) {
        $ret = ["code" => true, "flag" => auth_code("type confusion")];
    } 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>


위의 소스에서 php 영역보다는 html 영역 먼저 살펴보도록 해야 합니다.


일단 submit을 했을 경우 submit_check() 함수를 onsubmit()함수로 실행하는 것을 볼 수 있습니다.

submit_check() 함수를 찾아보려는데, 위의 소스에는 없는 것 같습니다.

잘 보면 29번 라인에 같은 디렉토리에 util.js 파일이 있는 것을 볼 수 있습니다.


해당 파일을 살펴보면 다음과 같습니다.

var lock = false;
function submit_check(f){
	if (lock) {
		alert("waiting..");
		return false;
	}
	lock = true;
	var key = f.key.value;
	if (key == "") {
		alert("please fill the input box.");
		lock = false;
		return false;
	}

	submit(key);

	return false;
}

function submit(key){
	$.ajax({
		type : "POST",
		async : false,
		url : "./index.php",
		data : {json:JSON.stringify({key: key})},
		dataType : 'json'
	}).done(function(result){
		if (result['code'] == true) {
			document.write("Congratulations! flag is " + result['flag']);
		} else {
			alert("nope...");
		}
		lock = false;
	});
}


위의 소스에서 submit_check() 함수와 submit() 함수가 있는 것을 볼 수 있습니다.


분석해보니, 우리가 입력받은 값(정확히는 POST로 전송받은 값)을 submit_check의 변수인 f로 받게 되고,

이 값이 존재하는지 먼저 체크하고, 존재한다면 submit 함수로 보내게 됩니다.


그리고 submit 함수에서는 우리가 입력받은 값을 json으로 인코딩하여,

{key: 입력받은 값}과 같은 형태로 처음 우리가 열었던 index.php 파일로 전송하게 됩니다.


값을 전달받은 index.php 파일은 우리가 입력한 값과 임의로 생성한 문자열 값이 동일한지 확인하게 됩니다.

sha1으로 해쉬화하여 전송하기 때문에 같은지 다른지 알 길이 없지요...


그렇다면 우리가 입력한 값이 무엇이든 문자열과 비교하게 된다는 것을 알 수 있습니다.

이 부분은 타입 에러에서 살펴보도록 해야 할 것 같습니다.



 

 문제 풀이



여러 타입과 관련하여 PHP에서는 위와 같은 리턴 값을 가지고 있습니다.

우리는 문자열과 비교하여 어떤 값이 참을 내뱉는지 살펴보도록 해야 할 것 같습니다.


위의 표에서 문자열은 "php"라고 써두었습니다.


"php"와 true, 0, 그리고 동일한 문자열일 경우에는 참을 리턴하는군요.


그렇다면 이제 참을 리턴할 수 있도록 값을 전송하도록 합시다.



입력 창에서 true를 입력하면, "true" 라는 문자열이 전송되기 때문에 저는 fiddler로 값을 따로 입력해주었습니다.

0 값도 시도해보았으나 true를 뱉지 않더라구요.. 


phptester.net에서 그냥 테스트를 해봤는데, true일 경우는 문자열과 일치하는 결과를 보여주지만, 0일 경우에는 일치하지 않는다는 결과를 보여주는군요. 저 표가 잘못된 건 아니지만, 0과 hash 값을 비교했을 때는 어째서인지 false를 뱉어냅니다.


 

 phptester에서 알아낸 내용


no를 뱉어내는 문자열

9b38360c57ba1a4688527cd4d9f58e3deaacccb6

7363e885238bb05b960a6f02c8bf464f7f413502


yes를 뱉어내는 문자열

e8cea42b73ba481a854368ad4827ec577c783059

beee587d9273f7570541e1ef2769a4d56cec4027



위의 두 종류의 해쉬는 문자열로 먼저 시작했는지, 숫자로 먼저 시작했는지에 따라 0과 비교했을 때 true 혹은 false로 나뉘어지는 것 같습니다.

제아무리 문자열이라고 하더라도 숫자로 먼저 시작할 경우에는 0과 비교할 때 false인 것 같습니다.


이는 atoi와 비슷한 형태를 보여준다고 합니다.




+ Recent posts