XXE&XML之利用检测绕过

简介
XML基础概念
- XML被设计为传输和存储数据,XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素,其焦点是数据的内容,其把数据从HTML分离,是独立于软件和硬件的信息传输工具。
XXE概念
- XXE漏洞全称XMLExternal Entity Injection,即xml外部实体注入漏洞,XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、攻击内网网站等危害。
- 例如PHP中的simplexml_load默认情况下会解析外部实体,有XXE漏洞的标志性函数为
simplexml_load_string()。
XML与HTML的主要差异
- XML被设计为传输和存储数据,其焦点是数据的内容。
- HTML被设计用来显示数据,其焦点是数据的外观。
- HTML旨在显示信息,而XML旨在传输信息。
XML外部实体
1 | <!--文档类型定义--> |
- 主要看一下DTD-实体。首先让我们了解一下基本的PAYLOAD结构:

- DTD:Document Type Definition 即文档类型定义,用来为XML文档定义语义约束。可以嵌入在XML文档中(内部声明),也可以独立的放在另外一个单独的文件中(外部引用)。
实体分为一般实体和参数实体
- 一般实体的声明:
<!ENTITY 实体名称 "实体内容">
引用一般实体的方法:&实体名称;
p.s.经实验,普通实体可以在DTD中引用,可以在XML中引用,可以在声明前引用,还可以在实体声明内部引用。 - 参数实体的声明:
<!ENTITY % 实体名称 "实体内容">
引用参数实体的方法:%实体名称;
p.s.经实验,参数实体只能在DTD中引用,不能在声明前引用,也不能在实体声明内部引用。
- 一般实体的声明:
- 如果实体名称中出现如
<的特殊字符,解析就会失败。为了避免这种情况,XML用实体引用替换特殊字符。XML预定义了五个实体引用,即用<、>、&、&apos、"替换<、>、&、'、"。
DTD实体声明
内部实体声明
<!ENTITY 实体名称 "实体的值">- 当引用一般实体时,由三部分构成:
&、实体名、;,当是用参数传入xml的时候,&需URL编码,不然&会被认为是参数间的连接符号。 - 示例:
1
2
3
4
5
6
<test>&writer;©right;</test>
外部实体声明
<!ENTITY 实体名称 SYSTEM "URI/URL">- 外部实体可支持http、file等协议。不同程序支持的协议不同,如下图:

- 其中PHP支持的协议会更多一些,但是需要一定的扩展支持:

- 示例:
1
2
3
4
5
6
<author>&file;©right;</author>
XXE检测
- 以pikachu靶场为例
- 主要的方法是检测所有接受XML作为输入内容端点,抓包观察其是否会返回我们想要的内容。
- 首先检测XML是否会被解析
1
2
3
4<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY words "Hello XXE !">]>
<a>&words;</a>
- 如果数据包或者页面显示“Hello XXE”的字样,说明表单实体被成功解析

XXE利用
- 以下利用主要基于
libxml2版本,其中libxml是PHP的xml支持。 - 而libxml版本在2.9.1及以后,默认不解析外部实体,很多利用将无法实现。
文件读取
- 最简单也是最常用的利用方式
- 一般xxe利用分为两大场景:有回显和无回显。有回显的情况可以直接在页面中看到Payload的执行结果或现象,无回显的情况又称为Blind XXE,可以使用外带数据通道提取数据。
有回显
引入外部实体
- 文件读取的利用就是使用file协议读取文件内容,并输出到页面上
1
2
3
4
5
<root>&xxe;</root>
引入外部参数实体
1 |
|
无回显
OOB
- 带外数据OOB(out—of—band data),有时也称为加速数据(expedited data)
- 是指连接双方中的一方发生重要事情,想要迅速地通知对方。这种通知在已经排队等待发送的任何“普通”(有时称为“带内”)数据之前发送。带外数据设计为比普通数据有更高的优先级。带外数据是映射到现有的连接中的,而不是在客户机和服务器间再用一个连接。
- 先使用php://filter获取目标文件的内容,然后将内容以http请求发送到接受数据的服务器(攻击服务器)xxx.xxx.xxx。
evil.dtd的内容,内部的%号要进行实体编码成%。1
2
3
4
5
6
7
8
9
10
11
12
<root>$send;</root>
<!-- evil.dtd -->
%all;- 首先对dtd引用目的是将外部文件
evil.dtd引入到解释上下文中,然后执行%all,这时会检测send实体,在root节点中引用send,就可以成功实现数据转发了。 - 访问接受数据的服务器中的日志信息,可以看到经过base64编码过的数据,解码后便可以得到数据。
基于报错
- 基于报错的原理和OOB类似,OOB通过构造一个带外的url将数据带出,而基于报错是构造一个错误的url并将泄露文件内容放在url中,通过这样的方式返回数据。
- 所以和OOB的构造方式几乎只有url处不同,其他地方一模一样。
通过引入服务器文件
1 | <!-- evil.dtd --> |
通过引入本地文件
- 如果目标主机的防火墙十分严格,不允许我们请求外网服务器dtd呢?由于XML的广泛使用,其实在各个系统中已经存在了部分DTD文件。按照上面的理论,我们只要是从外部引入DTD文件,并在其中定义一些实体内容就行。
1
2
3
4
5
6
7
8
9
10
11
12
13
<message>1234</message> - 第一个调用的参数实体是%remote,在/usr/share/yelp/dtd/docbookx.dtd文件中调用了%ISOamso;,在ISOamso定义的实体中相继调用了eval、和send
内网探测
- 和读文件差不多,只不过把URI改成内网机器地址
- 通过有xxe漏洞的网站,向其服务器内网进行判断是否开放,并且index.txt是否存在
1
2
3
4
5
6
<x>&test;</x>
RCE
- 在安装expect扩展的PHP环境里执行系统命令,当然其他协议也有可能可以执行系统命令
1
2
3
4
5
6
<root><name>&xxe;</name></root>
DDoS
- 支持实体测试:
1
2
3
4
5
6
7
<data>&a2;</data> - 如果解析过程变的非常缓慢,则表明测试成功,即目标解析器配置不安全可能遭受至少一种 DDoS 攻击。
绕过姿势
- 若
ENTITY、SYSTEM、file等关键词被过滤 - 使用编码方式绕过
评论
