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

  • A+
所属分类:网络安全文章
阿里


推广者专属福利,新客户无门槛领取总价值高达2775元代金券,每种代金券限量500张,先到先得。

一、漏洞描述

微信在JAVA版本的SDK中提供callback回调功能,用来帮助商家接收异步付款结果,该接口接受XML格式的数据,攻击者可以构造恶意的回调数据(XML格式)来窃取商家服务器上的任何文件,一般支付服务器均为核心服务器,出现XXE导致任意文件。另外,一旦攻击者获得了关键支付的安全密钥(md5-key和商家信息,将可以直接实现0元支付购买任何商品)。

二、漏洞分析

相关漏洞代码

  1. public class WXPayUtil {
  2.     /**
  3.      * XML格式字符串转换为Map
  4.      *
  5.      * @param strXML XML字符串
  6.      * @return XML数据转换后的Map
  7.      * @throws Exception
  8.      */
  9.     public static Map<String, String> xmlToMap(String strXML) throws Exception {
  10.         try {
  11.             Map<String, String> data = new HashMap<String, String>();
  12.             DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
  13.             DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
  14.             InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));
  15.             org.w3c.dom.Document doc = documentBuilder.parse(stream);
  16.             doc.getDocumentElement().normalize();
  17.             NodeList nodeList = doc.getDocumentElement().getChildNodes();
  18.             for (int idx = 0; idx < nodeList.getLength(); ++idx) {
  19.                 Node node = nodeList.item(idx);
  20.                 if (node.getNodeType() == Node.ELEMENT_NODE) {
  21.                     org.w3c.dom.Element element = (org.w3c.dom.Element) node;
  22.                     data.put(element.getNodeName(), element.getTextContent());
  23.                 }
  24.             }
  25.             try {
  26.                 stream.close();
  27.             } catch (Exception ex) {
  28.                 // do nothing
  29.             }
  30.             return data;
  31.         } catch (Exception ex) {
  32.             WXPayUtil.getLogger().warn("Invalid XML, can not convert to map. Error message: {}. XML content: {}", ex.getMessage(), strXML);
  33.             throw ex;
  34.         }
  35.     }

微信SDK的xmlToMap方法接收并处理XML数据,但是默认支持外部实体解析,所以只要可以控制strXML那么这边就存在XXE漏洞。

根据README可以看到,微信SDK的支付逻辑如下:

1、首先进行统一下单

  1. import com.github.wxpay.sdk.WXPay;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. public class WXPayExample {
  5.     public static void main(String[] args) throws Exception {
  6.         MyConfig config = new MyConfig();
  7.         WXPay wxpay = new WXPay(config);
  8.         Map<String, String> data = new HashMap<String, String>();
  9.         data.put("body""腾讯充值中心-QQ会员充值");
  10.         data.put("out_trade_no""2016090910595900000012");
  11.         data.put("device_info""");
  12.         data.put("fee_type""CNY");
  13.         data.put("total_fee""1");
  14.         data.put("spbill_create_ip""123.12.12.123");
  15.         data.put("notify_url""http://www.example.com/wxpay/notify");
  16.         data.put("trade_type""NATIVE");  // 此处指定为扫码支付
  17.         data.put("product_id""12");
  18.         try {
  19.             Map<String, String> resp = wxpay.unifiedOrder(data);
  20.             System.out.println(resp);
  21.         } catch (Exception e) {
  22.             e.printStackTrace();
  23.         }
  24.     }
  25. }

其中notify_url是通知地址,即接入方自己构建的web接口,用于异步接收微信支付结果通知的回调地址。

2、处理微信回调

  1. import com.github.wxpay.sdk.WXPay;
  2. import com.github.wxpay.sdk.WXPayUtil;
  3. import java.util.Map;
  4. public class WXPayExample {
  5.     public static void main(String[] args) throws Exception {
  6.         String notifyData = "...."// 支付结果通知的xml格式数据
  7.         MyConfig config = new MyConfig();
  8.         WXPay wxpay = new WXPay(config);
  9.         Map<String, String> notifyMap = WXPayUtil.xmlToMap(notifyData);  // 转换成map
  10.         if (wxpay.isPayResultNotifySignatureValid(notifyMap)) {
  11.             // 签名正确
  12.             // 进行处理。
  13.             // 注意特殊情况:订单已经退款,但收到了支付结果成功的通知,不应把商户侧订单状态从退款改成支付成功
  14.         }
  15.         else {
  16.             // 签名错误,如果数据里没有sign字段,也认为是签名错误
  17.         }
  18.     }
  19. }

String notifyData这边实际上就是微信给用户的接口返回的数据。

通过流程梳理可以看出,攻击点在于用户的回调接口notify_url,攻击者只需要往notify_url发送精心构造的payload就可以进行XXE攻击,另外,通过README中示例代码可以看出,签名校验是在xmlToMap之后的,所以无需完成签名校验即可完成攻击。
微信SDK支付漏洞 微信XXE漏洞分析

综上,只要使用了漏洞版本SDK&notify_url泄露就可以被XXE攻击

三、漏洞修复

禁用外部实体解析

CE安全网

发表评论

您必须登录才能发表评论!