今天公司收到漏洞预警,微信支付SDK存在XXE漏洞,下载到本地验证了一下
漏洞信息来源
http://seclists.org/fulldisclosure/2018/Jul/3
https://xz.aliyun.com/t/2426
漏洞描述
微信支付提供了一个接口,供商家接收异步支付结果,微信支付所用的java sdk在处理结果时可能触发一个XXE漏洞,攻击者可以向这个接口发送构造恶意payloads,获取商家服务器上的任何信息,一旦攻击者获得了敏感的数据 (md5-key and merchant-Id etc.),他可能通过发送伪造的信息不用花钱就购买商家任意物品
影响范围
使用微信提供的java SDK,WxPayAPI_JAVA_v3 进行支付开发的商家
[Detail]
The SDK in this page: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php
chapter=11_1
Just in java vision:
https://pay.weixin.qq.com/wiki/doc/api/download/WxPayAPI_JAVA_v3.zip
or
https://drive.google.com/file/d/1AoxfkxD7Kokl0uqILaqTnGAXSUR1o6ud/view(
Backup )
漏洞利用细节
将WxPayAPI_JAVA_v3.zip下载到本地,导入到IntelliJ IDEA
src/main/java/com/github/wxpay/sdk/WXPayUtil文件
/**
* XML格式字符串转换为Map
*
* @param strXML XML字符串
* @return XML数据转换后的Map
* @throws Exception
*/
public static Map<String, String> xmlToMap(String strXML) throws Exception {
try {
Map<String, String> data = new HashMap<String, String>();
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
org.w3c.dom.Document doc = documentBuilder.parse(stream);
doc.getDocumentElement().normalize();
.........
}
可以看出xmlToMapy方法用作将string转换成map,所用的xml解析器直接处理了xml字符串
通常情况下,xml解析器可以引用外部实体,如果构造恶意的xml文件,如下:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xdsec [
<!ELEMENT methodname ANY>
<!ENTITY xxe SYSTEM "file:///c:/windows/win.ini">
]>
<methodcall>
<methodname>&xxe;</methodname>
</methodcall>
xml解析器可读取到我指定的文件 c:/windows/win.ini 的信息
在本地验证过程中,将 /test/java/com/github/wxpay/sdk/TestWXPay文件test001方法中的xmlStr字符串替换为上述XML, 可成功读取win.ini文件
XXE漏洞修复
防护思路:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true); //防止可能的SSRF
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities",false); dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
实际的防护建议1:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
// 这是优先选择. 如果不允许DTDs (doctypes) ,几乎可以阻止所有的XML实体攻击
String FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
dbf.setFeature(FEATURE, true);
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 does not exist
logger.error("IOException occurred, XXE may still possible: " + e.getMessage());
...
}
实际防护建议2:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
// 如果不能完全禁用DTDs,最少采取以下措施
FEATURE = "http://xml.org/sax/features/external-general-entities";
dbf.setFeature(FEATURE, false);
FEATURE = "http://xml.org/sax/features/external-parameter-entities";
dbf.setFeature(FEATURE, false);
// and these as well, per Timothy Morgan 2014 paper: "XML Schema, DTD, and Entity Attacks" (see reference below)
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."
...
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());
...
}
参考
http://seclists.org/fulldisclosure/2018/Jul/3
https://xz.aliyun.com/t/2426
https://blog.csdn.net/u013224189/article/details/49759845
https://www.vsecurity.com//download/papers/XMLDTDEntityAttacks.pdf