安全研究 >> 安全研究详情

基于时间的盲注

作者: 美创科技安全实验室发布日期: 08月23日


No.1

盲注简介

盲注就是在sql注入过程中,sql语句执行的选择后,选择的数据不能回显到前端页面。此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注。


No.2

盲注原理

盲注的本质就是猜解,在没有回显数据的情况下,我们只能靠‘感觉’来体会每次查询时一点点细微的差异,而这差异包括运行时间的差异和页面返回结果的差异。


对于基于布尔的盲注来说,我们可以构造一条注入语句来测试我们输入的布尔表达式,而这布尔表达式结果的真假,决定了每次页面有不同的反应。


对于基于时间的盲注来说,我们构造的语句中,包含了能否影响系统运行时间的函数,根据每次页面返回的时间,判断注入的语句是否被成功执行。


No.3

盲注分类

  • 基于布尔SQL盲注

  • 基于时间的SQL盲注

  • 基于报错的SQL盲注


No.4

盲注的流程

  1. 找寻并确认sql盲注点

  2. 强制产生通用错误界面

  3. 注入带有副作用的查询

  4. 根据布尔表达式的真假结果,结合不同的返回结果确认注入是否成功


No.5

基于时间的盲注

常用函数

If(exp,v1,v2):如果表达式 expr 成立,返回结果 v1;否则,返回结果 v2  

Substring(s,n,len):获取从字符串 s 中的第 n 个位置开始长度为 len 的字符串

Sleep(duration):在duration参数给定的秒数之后运行


(注意):sleep 函数是只要存在一个满足条件的行就会延迟指定的时间,比如sleep(5),但是实际上查找到两个满足条件的行,那么就会延迟10s,这其实是一个非常重要的信息,在真实的渗透测试过程中,我们有时候不清楚整个表的情况的话,可以用这样的方式进行刺探,比如设置成 sleep(0.001) 看最后多少秒有结果,推断表的行数。


常用语法格式

Select * from table where id = 1 and if(布尔表达式,sleep(5),1);


注入思路

基于时间盲注的一般思路是延迟注入,说白了就是利用sleep()或benchmark()等函数让mysql执行时间变长并结合判断条件语句if(expr1,expr2,expr3),然后通过页面的响应时间长短来判断语句返回的值是TRUE还是False,从而猜解一些未知的字段。


注入流程(以获取数据库版本信息为例)

  1. 确定注入点及注入类型

  2. 使用if判断语句,猜测version()的长度并用sleep函数作为判断依据

  3. 重复步骤2直至获取真正长度

  4. 使用if判断语句,猜测version()的第一个字符的ascii码并使用sleep函数作为判断依据构造注入语句,

  5. 重复步骤4,直至获取全部长度的版本字符的ascii码


注入测试

首先寻找注入点,看到id=1,猜想可能存在sql注入;


其次确定注入类型,在1后面增加符号‘报错,说明存在字符注入;


由于没有回显数据,尝试时间盲注

Payload如下:

Id = 1’ and sleep(2);

可以看到sleep成功执行,返回时间2秒,说明sleep()没有被过滤


尝试获取数据库版本信息,首先确定版本信息的长度

Id = 1’and if(length(version())=23,sleep(3),1) --+

如果长度为23个字符则返回时间为3s若不是则立即返回。



确定了长度后,依次查找每一位的ascii码

例如:id=1’and if(ascii(substring(version(),1,1))=53,sleep(3),1) --+

尝试第一位的ascii码是不是53也就是十进制的5


重复以上步骤最终获得全部的版本信息


No.6

绕过方法

当sleep函数和benchmark函数被屏蔽时我们可以使用以下两种方法绕过限制策略。


1

叠加全排列

所谓叠加全排列就是对多个表做笛卡尔积连接,使之查询时间呈指数增长,也就是说,攻击者将简单的表查询不断地叠加,不断增加系统执行sql语句的负荷,直到产生攻击者想要的时间延迟。


例如针对系统表information_schema.columns的多表查询结果如下:


单表查询结果为3083,所用时间是0.05s。


两个表查询结果为9504889,所用时间是0.44。


以此类推控制好查询的表数,表数查询过大注入时间会长到离谱,过小又会感觉不到,所以要多次尝试。


2

get_lock()加锁机制

基本语句:

Select get_lock(key,timeout) from test;

Select release_lock(key) from test;


(1)GET_LOCK有两个参数,一个是key,表示要加锁的字段,另一个是加锁失败后的等待时间(s),一个客户端对某个字段加锁以后另一个客户端再想对这个字段加锁就会失败,然后就会等待设定好的时间;


(2)当调用 RELEASE_LOCK来释放上面加的锁或客户端断线了,上面的锁才会释放,其它的客户端才能进来。


测试过程:

首先对name字段进行加锁,返回结果为1且时间为0证明加锁成功;


建立另一个mysql连接,对同样的字段进行加锁,返回结果为0且时间是自定义的5,证明加锁失败;


利用上面的基础理论加上时间盲注原理,实现利用get_lock()构造时间盲注语句:


1、首先通过注入实现对字段的加锁

Select * from xxx where id = 1 and get_lock(‘column_name’,1);


2、然后构造盲注语句

Select * from xxx where id = 1 and 1 and get_lock(‘column_name’,5);

Select * from xxx where id = 1 and 0 and get_lock(‘column_name’,5);


值得注意的是,这种绕过方法是存在限制条件的,即数据库的连接必须是持久连接,我们所利用的也是前一个连接对后一个连接的阻碍作用从而导致延时产生。因此,只有那些在php中使用mysql_pconnect()方法链接数据库的网站,才有可能使用这种方法。


No.7

时间盲注的优缺点

利用时间盲注的最大优点是对日志几乎没有影响,特别是与基于错误的攻击相比。但是,在必须使用大量查询或 CPU密集型函数(如MySQL的BENCHMARK())的情况下,系统管理员可能会意识到正在发生的事情。


另一件需要考虑的事情是你注入的延迟时间。在测试Web应用程序时,这一点尤其重要。因为该服务器负载和网络速度可能对响应时间产生巨大的影响。你需要暂停查询足够长的时间,以确保这些不确定因素不会干扰你的测试结果。另一方面,你又会希望延迟足够短以在合理的时间内测试应用程序,所以把握这个时间长短的度是很困难的。



服务热线:400-711-8011
Copyright ©2005-2018 杭州美创科技有限公司. All Rights Reserved. 浙ICP备 09009762号-1