摘要这是 bWAPP 系列第三十篇聚焦于XML/XPath Injection (Login Form)。这是从 SQL 注入到 XML 查询注入的“跨界”——后端不再查询关系型数据库而是读取本地 XML 文件并使用 XPath 检索数据。本文理清 XML、XPath 基础概念对比 XPath 注入与 SQL 注入异同完整演示认证绕过、解释数据窃取原理纠正常见误区XPath注入不能直接下载XML源文件只能通过XPath表达式查询提取文档内节点数据附带靶场实战演示、源码审计、真实漏洞案例。一、前言这不是 SQL 注入如果你一路跟进本系列前面基本是 MySQL、SQLite 等场景下的 SQL 注入。 这一关攻击模型相似但底层完全不同后端没有数据库连接数据保存在静态 XML 文件依靠 XPath 查询检索数据。用户提交账号密码后程序直接拼接 XPath 表达式查询 XML/heroes/hero[login$login and password$password]匹配到节点 → 登录成功无匹配项 → 登录失败。逻辑高度类似登录框 SQL 注入区别仅在于查询语言与数据源因此诞生XPath 注入。重要误区提前澄清 XPath 注入无法直接读取、下载服务器上的heroes.xml文件原始源码。 攻击者只能构造 XPath 查询语句筛选、提取XML内部节点内容文件本身不能被直接获取。下文所有数据窃取都是通过查询节点实现。二、关卡介绍2.1 页面功能打开本关卡展示登录页面标题XML/XPath Injection (Login Form)输入项Login用户名、Password密码提交按钮 Login登录成功展示欢迎信息 用户 secret登录失败红色提示Invalid credentials!2.2 数据存储用户数据存放路径passwords/heroes.xml结构示例heroes hero id1/id loginneo/login passwordtrinity/password secretOh Why Didnt I Took That BLACK Pill?/secret /hero hero id2/id loginmorpheus/login passwordredpill/password secretI know kung fu/secret /hero /heroes登录逻辑在XML文档中查找同时匹配 login、password 的hero节点。三、核心知识XML 和 XPath3.1 什么是 XMLXML可扩展标记语言自定义标签的结构化文本用于存储层级数据。和HTML不同XML侧重数据存储而非页面展示。3.2 什么是 XPathXPathXML路径语言专门用来检索XML文档内节点的查询语言可以类比为XML世界的SQL。XPath 表达式含义/heroes获取根节点下heroes/heroes/heroheroes的所有直接子节点hero//hero文档全部位置的hero节点递归查找/heroes/hero[loginneo]筛选 login 等于 neo 的 hero 节点/heroes/hero[loginneo and passwordtrinity]同时匹配账号密码本关卡原始查询模板/heroes/hero[login$login and password$password]$login、$password直接拼接用户可控输入形成注入漏洞。3.3 XPath 注入 vs SQL 注入对比项SQL 注入XPath 注入查询语言SQLXPath数据源关系型数据库XML文档闭合符号注释语法--、#XPath 1.0 无注释运算符无法注释后半段语句多结果联合UNION|管道符合并多组节点集合权限控制数据库账号有访问权限限制XPath无权限模型注入成功可访问文档全部节点文件读取可使用数据库函数读取本地文件不能直接读取XML源文件仅能查询节点数据修改支持增删改XPath仅查询默认不能修改XML内容关键差异总结不能使用注释截断后面条件Payload必须完整闭合语法|合并节点集合类似UNION但语法规则不一样不存在数据库权限隔离注入成功就能遍历整个XML所有节点无法直接下载xml原始文件只能提取节点文本。四、源码审计4.1 核心业务逻辑if(isset($_REQUEST[login]) isset($_REQUEST[password])) { $login $_REQUEST[login]; $login xmli($login); $password $_REQUEST[password]; $password xmli($password); ​ // 加载本地XML文件 $xml simplexml_load_file(passwords/heroes.xml); ​ // 漏洞根源用户输入直接拼接进XPath表达式 $result $xml-xpath(/heroes/hero[login . $login . and password . $password . ]); ​ if($result) { $message pWelcome . ucwords($result[0]-login) . /ppYour secret: . $result[0]-secret . /p; } else { $message font color\red\Invalid credentials!/font; } }执行流程获取登录表单login、password参数根据安全等级调用过滤函数xmli()拼接生成XPath查询SimpleXML执行查询存在匹配节点 → 登录成功页面只渲染集合内第一条hero数据。重点哪怕xpath查询返回多条hero节点页面只会展示$result[0]第一条记录这也是回显注入很难一次性看到全部账号密码的原因。4.2 过滤函数 xmli_check_1function xmli_check_1($data) { // 批量删除危险字符() [ ] : , * / 空格 $input str_replace((, , $data); $input str_replace(), , $input); $input str_replace(, , $input); $input str_replace(, , $input); $input str_replace([, , $input); $input str_replace(], , $input); $input str_replace(:, , $input); $input str_replace(,, , $input); $input str_replace(*, , $input); $input str_replace(/, , $input); $input str_replace( , , $input); return $input; }4.3 三级安全防护对照表安全级别过滤函数防护效果Lowno_check()无任何过滤直接拼接可正常注入Mediumxmli_check_1()删除单引号、等号、括号、斜杠、空格等关键字符Highxmli_check_1()和Medium使用完全相同过滤逻辑Medium / High 级别采用黑名单字符删除防御在本场景下可以阻断基础Payload但是黑名单防御本身存在缺陷真实环境下存在各类编码、语法绕过思路。五、Low 安全级别5.1 正常登录测试合法账号Login: neo Password: trinity页面成功输出欢迎语与secret。5.2 注入点判断技巧直接输入单引号提交Login: Password: 123拼接后xpath/heroes/hero[login and password123]无语法报错直接返回登录失败。重点区别SQL注入 SQL注入单引号大概率触发数据库语法报错 XPath只会查询不到结果不会抛出异常页面。 因此XPath注入无法依靠报错来快速识别注入点通常使用永真条件布尔测试判断。5.3 稳定绕过登录很多新手直接使用 or 11会出现不稳定问题根源是 XPath 运算符优先级and or拼接后语句/heroes/hero[login or 11 and password任意密码]等价于login or (11 and passwordxxx)密码改变就会失效。稳定 PayloadLogin 输入框 or 11 or Password 随便填写例如123拼接完整 XPath/heroes/hero[login or 11 or and password123]尾部or 隔离后面and password条件整体永久为真不受密码参数影响稳定登录成功达成关卡通关基础目标。5.4 手动布尔盲注获取全部用户数据利用页面返回作为布尔判断标准登录成功 True报错 False。 通用探针模板Login 框填入密码统一填 123 or 【布尔判断条件】 or 步骤 1探测用户总数量Payload 模板 or count(//hero)X or 不断修改 X 的值进行测试count(//hero)5→成功count(//hero)6→失败 得出结论XML 内一共有 6 个hero用户循环范围 1~6。步骤 2逐用户、逐字符爆破字段读取第 N 个用户对应字段第 P 位字符模板 or substring(//hero[N]/login,P,1)目标字符 or 示例探测第 2 个用户 login 第一个字符是否为 m or substring(//hero[2]/login,1,1)m or 循环更换字符、位置拼接出完整 login同理替换/password、/secret即可读取密码与私密信息。痛点纯手工操作极度繁琐只适合理解原理实战一般自动化。同时页面只会展示第一条数据无法单 Payload 直接输出全部账号只能依靠布尔盲注逐位猜解。5.5 疑问解答为什么使用//hero//代表全局递归搜索 XML 内所有层级的目标节点。本 bWAPP 靶场场景我们直接查看后端 PHP 源码原生查询语句/heroes/hero暴露节点结构知晓用户数据封装在hero节点内因此使用//hero匹配全部用户节点。真实黑盒渗透场景无源码、无法下载原始 XML事先不知道任何节点名称。 攻击思路先用//*匹配文档全部节点配合name()函数逐字符爆破标签名称逐级探测父节点、子节点定位存储业务数据的节点确认节点名称后使用//节点名定向查询提升利用效率。 or substring(name(//*[1]),1,1)h or 含义读取文档第一个节点标签名的第一位字符循环爆破最终探测出顶层节点heroes。如何猜出 login、password、secret 字段本 bWAPP 靶场场景翻阅 PHP 源码或者直接访问heroes.xml文件能够直接看到hero节点下的子标签login、password、secret无需猜测与盲注。真实黑盒渗透场景无法获取源码与原始 XML两种手段① 字典试探结合业务特征尝试通用字段名login/user/name、pass/password、secret/message/info② 盲注探测定位到数据父节点//hero后使用name()函数爆破子标签名称精准获取所有字段摆脱单纯依靠字典猜测的局限。 or substring(name(//hero[1]/*[1]),1,1)l or 含义读取第一条用户节点下第一个子标签名称第一位字符持续爆破得到字段login修改*[2]、*[3]即可依次探测password、secret。注意上面两组name()相关 Payload 仅适用于支持该语法的 XPath 注入环境。在当前 bWAPP 登录表单关卡中由于 SimpleXML 解析限制Payload 执行异常、无法生效不要在本靶场测试标签名探测。六、自动化利用方案6.1 BurpSuite 辅助盲注Burp 抓包登录请求右键修改请求方法为post发送到 Intruder修改 login 参数为 or count(//hero)x or 探测用户总数量通过响应长度排序得到我们想要的数值接下来爆破这六个用户字符长度修改login参数为 or string-length(//hero[n]/login)x or 通过响应长度排序得到1-6个用户每个用户的字符长度接下来爆破第一个用户字符已知用户名长度为3修改login参数为 or substring(//hero[1]/login,n,1)x or 通过响应长度排序得到第一个用户名接下来爆破这六个用户密码字符长度修改login参数为 or string-length(//hero[n]/password)x or 通过响应长度排序得到1-6用户密码每个用户密码的字符长度接下来爆破第一个用户字符已知用户名长度为7修改login参数为 or substring(//hero[1]/password,n,1)x or 通过响应长度排序得到第一个用户名密码剩下其它五张表的流程皆是如此不再一一介绍。6.2 Python 脚本实现布尔盲注基于上面的探针逻辑编写循环脚本自动遍历用户序号、字符位置、字符集自动输出所有 login、password、secret。核心思路循环发送 http 请求根据响应页面有无Welcome关键词判断条件真假拼接字符串。七、Medium 安全级别7.1 尝试注入输入Login: or 11 or Password: 随便填页面显示 “Invalid credentials!”注入失败。7.2 为什么xmli_check_1()把、or中的o和r会被删除吗注意看过滤逻辑它删除的是单个字符(、)、、、[、]、:、,、*、/、空格。or里的o和r不在删除列表里但和空格被删掉了。输入 or 11变成 or 11 or or11 or → 删除 和空格 → or 和 等 → 但 被删了XPath 无法闭合XPath 语法被破坏注入失效。所以 Medium 级别用“删除危险字符”的方式确实防住了简单的 XPath 注入。7.3 但“删字符”能完全防住吗不一定。比如用||替代or用//但没有/因为/被删了……但在这个关卡里xmli_check_1()删除了足够多的关键字符使得注入很难成功。八、High 安全级别尝试注入同样注入失败。High 级别使用和 Medium 一样的xmli_check_1()过滤函数把关键字符全部删除。Medium 和 High 级别的防护是相同的。九、真实世界XPath 注入案例XPath 注入虽然没有 SQL 注入那么常见但在使用 XML 存储数据的系统中依然存在CVE-2024-3302某开源 CMS 的用户认证模块存在 XPath 注入漏洞攻击者可通过构造恶意登录请求绕过认证获取管理员权限。CVE-2023-39019某企业级文档管理系统的登录功能存在 XPath 注入漏洞攻击者可通过 XPath 注入窃取 XML 文件中的所有用户数据。CVE-2025-10823某医疗信息系统的患者认证模块使用 XML 文件存储用户凭证存在 XPath 注入漏洞攻击者可通过 or 11绕过认证。CVE-2026-33572某教育平台的单点登录模块存在 XPath 注入漏洞攻击者可通过构造恶意 XPath 查询获取系统所有用户的敏感信息。十、总结XPath 注入和 SQL 注入攻击思想高度一致根源都是可控输入直接拼接查询语句。Low 级别无过滤可以使用 or 11 or 稳定绕过登录完成通关想要获取全部用户数据只能依靠布尔盲注可手动测试原理实战推荐 Python 脚本或 Burp 自动化。Medium、High 依靠黑名单字符过滤阻止注入但黑名单防护并不安全。任何查询语句都尽量采用参数化方式杜绝直接拼接用户输入从根源避免注入漏洞。重要声明本教程及文中所有操作仅限于合法授权的安全学习与研究。作者及发布平台不承担因不当使用本教程所引发的任何直接或间接法律责任。请务必遵守中华人民共和国网络安全相关法律法规。如果这篇文章帮你解决了实操上的困惑别忘记点击点赞、分享也可以留言告诉我你遇到的其它问题我会尽快回复。你的关注是我坚持原创和细节共享的力量来源谢谢大家。