昨天(2018-07-04)微信支付的SDK曝出重大漏洞(XXE漏洞),通過該漏洞,攻擊者可以擷取伺服器中目錄結構、檔案内容,如代碼、各種私鑰等。擷取這些資訊以後,攻擊者便可以為所欲為,其中就包括衆多媒體所宣傳的“0元也能買買買”。
漏洞報告位址;http://seclists.org/fulldisclosure/2018/Jul/3
此次曝出的漏洞屬于XXE漏洞,即XML外部實體注入(XML External Entity Injection)。
XML文檔除了可以包含聲明和元素以外,還可以包含文檔類型定義(即DTD);如下圖所示。

在DTD中,可以引進實體,在解析XML時,實體将會被替換成相應的引用内容。該實體可以由外部引入(支援http、ftp等協定,後文以http為例說明),如果通過該外部實體進行攻擊,就是XXE攻擊。
可以說,XXE漏洞之是以能夠存在,本質上在于在解析XML的時候,可以與外部進行通信;當XML文檔可以由攻擊者任意構造時,攻擊便成為可能。在利用XXE漏洞可以做的事情當中,最常見最容易實作的,便是讀取伺服器的資訊,包括目錄結構、檔案内容等;本次微信支付爆出的漏洞便屬于這一種。
本次漏洞影響的範圍是:在微信支付異步回調接口中,使用微信支付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請求,便可以對伺服器進行攻擊。下面通過執行個體介紹攻擊的方法。
下面在本機環境下進行複現。
假設本地的web伺服器127.0.0.1:8080中存在POST接口:/wxpay/callback,該接口中接收xml字元串做參數,并調用前述的WXPayUtil.xmlToMap(strXml)對xml參數進行解析。此外,/etc/password中存儲了重要的密碼資料(如password1234)。
攻擊時構造的請求如下:
其中xml内容如下:
其中/etc/password為要竊取的對象,http://127.0.0.1:9000/xxe.dtd為攻擊者伺服器中的dtd檔案,内容如下:
通過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中修複代碼如下:
加入了如下兩行代碼:
更新:微信重新發表聲明,上述2條語句無法禁止該漏洞,再次更新了官方SDK,加了以下語句:
此外,微信官方也給出了關于XXE漏洞的最佳安全實踐,可以參考:
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=23_5
筆者本人使用上述方案中建議的如下代碼修複了該漏洞:
在很多媒體的報道中,強調該漏洞的風險在于攻擊者可以不支付也可以獲得商品。确實,攻擊者在通過上述漏洞獲得微信支付的秘鑰以後,有不止一種途徑可以做到不支付就獲得商品:例如,攻擊者首先在系統中下單,獲得商戶訂單号;然後便可以調用微信支付的異步回調,其中的簽名參數便可以使用前面擷取的秘鑰對訂單号等資訊進行MD5獲得;這樣攻擊者的異步回調就可以通過應用伺服器的簽名認證,進而獲得商品。不過,在很多有一定規模的購物網站(或其他有支付功能的網站),會有對賬系統,如定時将系統中的訂單狀态與微信、支付寶的背景對比,如果出現不一緻可以及時報警并處理,是以該漏洞在這方面的影響可能并沒有想象的那麼大。
然而,除了“0元也能買買買”,攻擊者可以做的事情還有很多很多;理論上來說,攻擊者可能獲得應用伺服器上的目錄結構、代碼、資料、配置檔案等,可以根據需要進行進一步破壞。
雖然微信支付曝出該漏洞受到了廣泛關注,但該漏洞絕不僅僅存在于微信支付中:由于衆多XML解析器預設不會禁用對外部實體的通路,是以應用的接口如果有以下幾個特點就很容易掉進XXE漏洞的坑裡:
(1)接口使用xml做請求參數
(2)接口對外公開,或容易獲得:例如一些接口提供給外部客戶調用,或者接口使用http很容易抓包,或者接口比較容易猜到(如微信支付的異步回調接口)
(3)接口中解析xml參數時,沒有禁用對外部實體的通路
建議大家最好檢查一下自己的應用中是否有類似的漏洞,及時修複。
xml 與 json是系統間互動常用的兩種資料格式,雖然很多情況下二者可以互換,但是筆者認為,json 作為更加輕量級更加純粹的資料格式,更适合于系統間的互動;而xml,作為更加重量級更加複雜的資料格式,其 DTD 支援自定義文檔類型,在更加複雜的配置場景下有着更好的效果,典型的場景如 spring 相關的配置。
在前面曾經提到,應用中存儲的秘鑰一旦洩露,攻擊者便可以完全繞過簽名認證,這是因為微信支付使用的是對稱式的簽名認證:微信方和應用方,使用相同的秘鑰對相同的明文進行MD5簽名,隻要應用方的秘鑰洩露,簽名認證就完全成了擺設。
在這方面支付寶的做法更規範也更安全:支付寶為應用生成公私鑰對,公鑰由應用方儲存,私鑰由支付寶儲存;在回調時,支付寶使用私鑰進行簽名,應用方使用公鑰進行驗證;這樣隻要支付寶儲存的私鑰不洩露,攻擊者隻有公鑰則難以通過簽名認證。
http://seclists.org/fulldisclosure/2018/Jul/3
https://www.cnblogs.com/tongwen/p/5194483.html
創作不易,如果文章對你有幫助,就點個贊、評個論呗~