XXE
什么是XXE
XXE(XML External Entity Injection) 全称为 XML 外部实体注入 XML注入 在极客2025里面做过的 用svg标签来得到 当然太局限局限了 继续往下看 XML 文件可以通过 “外部实体”(DOCTYPE 声明中的 ENTITY)引用外部资源,但如果服务器的 XML 解析器未禁用外部实体加载,攻击者就能构造恶意 XML 内容,诱导解析器执行非法操作(比如读取服务器本地文件、访问内部网络等)。
基础知识
- DTD 简单说简单说,DTD 是 XML 的 “格式说明书”:
规定 XML 里能出现哪些元素、属性;
定义元素的嵌套顺序、次数;
统一不同 XML 文档的格式(比如数据交换时保证双方的 XML 结构一致) - 分为 内部 DTD:直接写在 XML 文档里(用
<!DOCTYPE>声明)和 外部 DTD:写在单独的文件里,XML 通过SYSTEM或PUBLIC引用 - ENTITY 可被替换展开的占位符 其实就相当于
1 | <!DOCTYPE test [ |
把name换成了Alice 下面的&是引用前面的
- SYSTEM —— “直接指定位置”
1 | <!ENTITY 实体名 SYSTEM "URI"> |
其实就是
1 | <!ENTITY xxe SYSTEM "file:///etc/passwd"> |
等于直接读取 /etc/passwd 内容
还可以发送http请求 比如
1 | <!ENTITY xxe SYSTEM "http://127.0.0.1:8080/admin"> |
是向 127.0.0.1 发起 HTTP 请求
PUBLIC —— 给一个名字,你自己找(xxe基本用不到 了解一下)
1 | <!ENTITY 实体名 PUBLIC "公共标识符" "URI"> |
一般的例子
1 | <!DOCTYPE html PUBLIC |
前面是一套公共的标准 大概就是规范化命名格式 后面就是System Identifier(系统标识符)给一个找东西的参考地址
- 通用实体 用 &实体名; 引用的实体
- 参数实体 使用 % 实体名(这里面空格不能少) 在 DTD 中定义,并且只能在 DTD 中使用 %实体名 文章里面讲的没有太细 看输了概念觉得也不需要很细 毕竟攻击的源头其实是他们的外部引用 但是这里文章说 参数实体在我们 Blind XXE 中起到了至关重要的作用 边看边记录了
XXE攻击
- 有回显读本地敏感文件(Normal XXE)
其实就是用简单的引用外部实体去得到服务器上的文件 需要满足
服务器 解析了 XML
实体被展开
展开的内容 被返回给你看
1 | <?xml version="1.0" encoding="UTF-8"?> |
假设 然后后端发现 &xxe;
查实体表
发现是 外部实体
读取 file:///etc/passwd
把读取到的内容 当成普通文本插进去
文章这里提到的情况 如果要读取的是有一些特殊情况的文件 比如在XML中,有时实体内包含了些字符,如&,<,>,”,’等。这些均需要对其进行转义,否则会对XML解释器生成错误
用到CDATA
CDATA 是:
告诉 XML 解析器——“这里面的内容当作纯文本,不要当成 XML 语法来解析”
1 | <
这里记一下支持的协议
文章下面与一些常可探测且有价值的文件相关 下面记一下敏感文件
/etc/network/interfaces
网络接口配置文件(Debian / Ubuntu)
包含:IP、网关、网卡名称、DHCP 配置
价值:
判断内网网段
判断是否在云 / 容器 / 内部网络
/proc/net/arp
ARP 缓存表
包含:内网 IP ↔ MAC 映射
价值:
枚举内网存活主机
判断是否存在网关、网桥、容器网络
/etc/hosts
本地域名解析文件
包含:内部域名 → 内网 IP
价值:
泄露内部服务名称(db、redis、api)
为 SSRF / 内网访问提供指引
Linux 常见敏感文件分类(重点)
1️⃣ 用户与身份信息
| 文件 | 说明 |
|---|---|
/etc/passwd |
用户列表 |
/etc/group |
用户组 |
/etc/shadow |
密码哈希(高权限) |
2️⃣ 系统与基础环境信息
| 文件 | 说明 |
|---|---|
/etc/hostname |
主机名 |
/etc/os-release |
系统版本 |
/proc/version |
内核信息 |
/proc/cpuinfo |
CPU 信息 |
3️⃣ 网络与内网结构(侦察核心)
| 文件 | 说明 |
|---|---|
/etc/resolv.conf |
DNS 服务器 |
/proc/net/route |
路由表 |
/proc/net/arp |
内网主机 |
/etc/network/interfaces |
网卡配置 |
4️⃣ 进程 / 容器 / 云环境判断(非常重要)
| 文件 | 说明 |
|---|---|
/proc/1/cgroup |
判断 Docker / K8s |
/proc/self/cgroup |
当前进程环境 |
/proc/1/environ |
PID 1 环境变量(核心) |
5️⃣ 配置文件与凭据(价值最高)
| 文件 | 说明 |
|---|---|
/var/www/html/.env |
Web 应用环境变量 |
/app/.env |
容器应用配置 |
/root/.ssh/id_rsa |
SSH 私钥 |
/home/*/.ssh/authorized_keys |
登录授权 |
| 文章里脚本的原理就是将目标服务器当作“内网代理”,通过 SSRF 扫描内网 HTTP 服务 然后还套了base64 保证外带正常 脚本先记一下吧 |
1 | import requests |
还有利用bp的端口遍历 和前面扫整个网段原理没大区别
文章下面的那道题只能看的懂原理 主要记录一下
libxml(PHP 默认 XML 解析器)的读取文件不能过大的特殊性 以及破解的方法
1 | 压缩:php://filter/zlib.deflate/convert.base64-encode/resource=/etc/passwd |
jar:{url}!{path}
jar 能从远程获取 jar 文件,然后将其中的内容进行解压
jar 协议处理文件的过程:
(1) 下载 jar/zip 文件到临时文件中
(2) 提取出我们指定的文件
(3) 删除临时文件
首先对于有回显的xxe jar可以作为得到文件回显的一种方式 文章这里的 看的有些乏力 结合出的题
大概就是Java 会把 jar.zip 完整下载 写入 本地临时目录 最后利用不存在的文件去报错得到zip的真正所在的目录
一些特殊的xxe
- PHP 的 expect 并不是默认安装扩展,如果安装了这个expect 扩展我们就能直接利用 XXE 进行 RCE
1 | <?xml version="1.0"?> |
expect://后面的就是可以直接执行的系统命令
2. DOS攻击 这个貌似在ctf里面很难能出题(只是我的猜想 毕竟服务都打挂了….)
不过了解到了这种基于xxe的dos攻击
Billion Laughs(指数级爆炸)
1 | <?xml version="1.0"?> |
Quadratic Blowup(平方级膨胀)
1 | <?xml version="1.0"?> |
External Entity Bomb(外部实体 DoS)
1 | <?xml version="1.0"?> |
去加载一个超大的资源
或者是自己访问/dev/zero 永远不返回 EOF
关于防御
禁止回显(但是其实没啥大作用 外带情况太多了) 禁掉外部实体 这个太重要了 几乎能ban完了 貌似除了DOS 后端再加上一些黑名单的话 攻击者基本不能做什么