<?php include "./config.php"; login_chk(); dbconnect(); if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~"); if(preg_match('/\'|\"|\`/i', $_GET[no])) exit("No Quotes ~_~"); $query = "select id from prob_goblin where id='guest' and no={$_GET[no]}"; echo "
query : {$query}
"; $result = @mysql_fetch_array(mysql_query($query)); if($result['id']) echo "Hello {$result[id]}
"; if($result['id'] == 'admin') solve("goblin"); highlight_file(__FILE__); ?>
6번째 줄에 preg_match를 보면 ', ", ` 를 사용하지 못하게 되어있습니다. (확인결과 %27도 필터링된다.)
7번째 줄에 id값에 guest가 들어가있고, no의 값을 받습니다.
10번째 줄에 id가 admin이면 문제가 풀립니다.
따라서 싱글쿼터(')를 사용하지 않고 id값에 admin을 넘겨주어야 합니다.
no값에 1을 넣어보니 Hello huest 라고 출력되는것 보니 guest의 no값은 1인것 같다.
(지금은 운이 좋아서 huest의 no값이 1이라는 것을 알아서 id='guest' and no={$_GET[no]} 부분을 무력화 시킬 수 있겠지만, no의 값을 모르는 상태에서 쿼리문을 확실히 무력화시키기 위해서는 의미없는 값을 집어넣는게 좋다.
만약 no에 '138974189374981'값을 넣으면 해당 DB에 no가 '138974189374981'값이 있을 확률이 얼마나 될까...
거의 없을 것이다.)
[풀이1] - string우회법
'admin'문자를 hex코드(string 우회법)로 넘겨보기로 했습니다. (참고, guest의 no값이 1이므로 no값에 1을 넣으면 안됨.)
hex값으로 넘겨줄때는 '0x'를 붙여야 한다.
hex값으로 넘겨주면 문자 admin으로 인식하므로 싱글쿼터('), 더블쿼터(") 를 사용하지 않아도 된다.
[풀이2]
[*] MySQL의 문자열 함수 MySQL에서 SQL Injection을 시행할 때 많이 쓰이는 문자열 함수들이 있습니다. http://bizadmin.tistory.com/entry/%EB%AC%B8%EC%9E%90%EC%97%B4-%ED%95%A8%EC%88%98 이번 문제에서는 ord()함수를 이용하겠습니다. |
ord()함수는 문자열의 가장 왼쪽의 문자를 ASCII의 10진수로 변환합니다.
ord(id)라고 하면 id에 있는 문자열들의 왼쪽 값이 됩니다.
이 때 'admin'의 시작인 a의 10진수 ASCII코드 '97'을 사용합니다.
ord(id)=97 : id에서 가장 왼쪽 값이 'a(97)'인 값을 찾아라.
select id from prob_goblin where id='guest' and no=0 or ord(id)=97
select id from prob_goblin where id='guest' and no=0 or id='admin'
결과적으로 두 쿼리는 똑같다.