0x00 概述
XXE漏洞全称XML External Entity Injection 即XML外部实体注入
XXE也算是一种新秀漏洞
和流行的服务端SQL注入,和客户端的XSS、CSRF等不一样,危害大,甚至不需要绕过,一般有漏洞就可以做很多事,没有就没有
因为修复起来也简单,而且可以完全修复,修复也往往不影响业务,加个配置就可以
0x01 漏洞简介
我第一次碰到XXE漏洞,是在公司HR的招聘网站的上传简历的接口
触发的方式是在docx文件中的xml里加入XXE的payload
这个问题是SRC联系的白帽子发现的,之前我还不知道XXE这种漏洞,白帽子上报漏洞之后才知道原来XXE已经上了OWASP TOP 10
比如如下代码
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String result="";
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(request.getInputStream());
String username = getValueByTagName(doc,"username");
String password = getValueByTagName(doc,"password");
if(username.equals(USERNAME) && password.equals(PASSWORD)){
result = String.format("<result><code>%d</code><msg>%s</msg></result>",1,username);
}else{
result = String.format("<result><code>%d</code><msg>%s</msg></result>",0,username);
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
result = String.format("<result><code>%d</code><msg>%s</msg></result>",3,e.getMessage());
} catch (SAXException e) {
e.printStackTrace();
result = String.format("<result><code>%d</code><msg>%s</msg></result>",3,e.getMessage());
}
response.setContentType("text/xml;charset=UTF-8");
response.getWriter().append(result);
}
我们传入如下PoC
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE lltest[
<!ENTITY xxe SYSTEM "file:///C:/Windows/win.ini">
]>
<user><username>&xxe;</username><password>123456</password></user>
就会将C://Windows/win.ini
的文件传出
这样的现象和XML的DTD有关
XML (可扩展标记语言,EXtensible Markup Language),是一种标记语言,用来传输和存储数据,而非显示数据
DTD(文档类型定义,Document Type Definition)的作用是定义 XML 文档的合法构建模块,它使用一系列的合法元素来定义文档结构
ENTITY,XML中的实体类型,一般有下面几种:字符实体、命名实体(或内部实体)、外部普通实体、外部参数实体。除外部参数实体外,其它实体都以字符(&)开始,以字符(;)结束
命名实体(或内部实体)语法:<!ENTITY 实体名称 "实体的值">
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY x "First Param!">
<!ENTITY y "Second Param!">
]>
<root><x>&x;</x><y>&y;</y></root>
如下可以引用外部实体,可以加载文件<!ENTITY 实体名称 SYSTEM "URI/URL">
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPe root [
<!ENTITY outfile SYSTEM "outfile.xml">
]>
<root><outfile>&outfile;</outfile></root>
如下可以引入其他实体,可以引入其他DTD文件中的实体
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY % param1 "Hello">
<!ENTITY % param2 " ">
<!ENTITY % param3 "World">
<!ENTITY dtd SYSTEM "combine.dtd">
%dtd;
]>
<root><foo>&content</foo></root>
combine.dtd中的内容为:<!ENTITY content "%param1;%param2;%param3;">
如上,我们可以得知XXE可以做到的事情是
- 如SSRF一样任意访问URL,包含非HTTP/S的协议也可以
- 可以读取文件
0x02 威胁场景
- 有XML传输的地方,比如接口采用XML格式传输数据
- 有XML文件上传的地方,比如上传Word、Excel等
- XML配置文件的解析,比如Java框架的XML配置等
0x03 修复方式
因为一般来讲上面的两个威胁场景,业务的本意都不是使用XML的DTD,只是需要XML最普通的功能而已
所以业务使用的时候不需要考虑DTD功能,能禁用就禁用,不影响业务,所以修复就是禁用DTD
各种语言各个库的修复方式可以查看
0x04 深入攻防
这里讲一讲XXE的利用方式
我们上面说到XXE可以做到的事情是
- 如SSRF一样任意访问URL,包含非HTTP/S的协议也可以
- 可以读取文件
然后再根据它的生成方式,我们将XXE的利用分成2类
控制服务器发出请求
请求包含两类
一种是请求本地文件
一种是请求URL
而请求URL又根据协议的不同,可以又很多变种,甚至是<!ENTITY xxe SYSTEM "except://id"
,这种except扩展可以在PHP环境里执行系统命令,但是很少见
然后因为可以请求URL,所以这个漏洞就和SSRF几乎有完全相同的危害,包括可以用HTTP请求盲打内网,探测服务和直接对内网站点进行攻击
DoS攻击
这个比较少见,但是看了很多文章,发现还是有这种用法
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!NETITY lol2 "&lol;$lol;........$lol;">
<!NETITY lol3 "&lol2;$lol2;........$lol2;">
<!NETITY lol4 "&lol3;$lol3;........$lol3;">
<!NETITY lol5 "&lol4;$lol4;........$lol4;">
<!NETITY lol6 "&lol5;$lol5;........$lol5;">
<!NETITY lol7 "&lol6;$lol6;........$lol6;">
<!NETITY lol8 "&lol7;$lol7;........$lol7;">
<!NETITY lol9 "&lol8;$lol8;........$lol8;">
]>
<lolz>$lol9;</lolz>
如上这种Payload,lol实体有lol
字符,lol2实体引用了10次lol实体,lol3实体引用了10次lol2实体……lol9引用了10^8
个lol
字符串
这样对递归引用可能会耗尽内存,造成DoS漏洞
0x05 总结
导致XXE漏洞最大的问题还是程序员不了解这个漏洞,而且库没有默认禁用DTD,随着版本升级,库会渐渐支持默认禁用DTD,也会增加使用DTD的过滤,变成默认安全的库,相信XXE的问题会越来越少