天天看點

從最近的微信支付看XXE漏洞

先說下寫這篇文章的初衷吧,最近微信支付java_sdk剛爆發了一次xxe漏洞,然後上司趕快用自家的靜态代碼審計工具做了審計(這裡我就不報名字,本來可以幫公司推廣下産品是很好的,但我怕本文過于基礎會被各位大佬噴出翔來,到時候有辱“司”門就真是罪過罪過了)。

發現能成功找出漏洞點,如下圖。

從最近的微信支付看XXE漏洞

到目前本來是件極好的事情,但是發現使用自己規則修複後依然能掃描出漏洞,這就很能說明問題,于是老大讓我對微信支付漏洞做漏洞研究并找出産品出問題的原因。是以才有了這篇文章。由于本文的初衷是為了改進産品,是以本文并不是為了深入研究xxe漏洞,更加适合開發人員看。

微信支付的sdk中提供了WXPayUtil這個工具類,該類中實作了xmltoMap和maptoXml這兩個方法,而這次的微信支付的xxe漏洞爆發點就在xmltoMap方法中。

從最近的微信支付看XXE漏洞
從最近的微信支付看XXE漏洞

該方法是為了将xml格式的字元串strXML轉化為map。由于strXML可由攻擊者控制,且程式未作任何防護措施(如禁止引用外部實體;過濾關鍵字元串等),導緻惡意攻擊者可利用外部實體注入讀取伺服器上的檔案。當攻擊者擷取支付加密所用的安全密匙後,完全可以實作0元支付商品。

這裡先以微信sdk中的xmlToMap方法為例,複現該xxe漏洞。(由于要完整的實作微信零元支付,需要寫比較完整的程式對接微信支付接口,比較耗時間,暫時先不做)。

出現問題的代碼是:

DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();org.w3c.dom.Document doc = documentBuilder.parse(stream);           

複制

生成documentBuilderFactory後直接去解析流。

構造xml格式的字元串如下:

<?xml version='1.0' encoding='utf-8'?><!DOCTYPE xdsec [<!ELEMENT methodname ANY><!ENTITY xxe SYSTEM 'file:///c:/windows/win.ini'>]><methodcall><methodname>&xxe;</methodname></methodcall>           

複制

這樣mapToXml中DOM解析器解析該字元串時,會通路外部實體中的SYSTEM屬性中辨別的URL,并将讀取的檔案内容放入methodccall節點中。然後取出放入map中(實際場景中map中的值最後會被攻擊者所擷取,我們這裡以在控制台輸出為例),能成功讀取系統檔案。

從最近的微信支付看XXE漏洞

一、完全禁用DTDs,生成documentBuilderFactory後對feature進行設定

documentBuilderFactory.setFeature(“http://apache.org/xml/features/disallow-doctype-decl“,true);

效果如下:

從最近的微信支付看XXE漏洞

程式會報錯,提示将該屬性設為true。

二、生成documentBuilderFactory後對feature進行設定

documentBuilderFactory.setXIncludeAware(false);          documentBuilderFactory.setExpandEntityReferences(false);                                        documentBuilderFactory.setFeature("http://xml.org/sax/features/external-parameter-entities",false);                                 documentBuilderFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);           

複制

效果如下:

從最近的微信支付看XXE漏洞

程式雖然不會報錯,但是已經讀取不出系統檔案中的内容了。

三、對關鍵詞做過濾,如ENTITY、 DOCTYPE

對以上三種防範方式做分析:推薦使用第一種,能處理掉絕大多數的xxe漏洞;當有需求不能全部禁用掉DTD時,使用第二種方法;不建議使用第三種方法,如果不然很容易被繞過,如使用ENTIENTITYTY等等情況來繞過。

微信支付sdk中使用的是原生的dom解析xml,接下裡分别複現使用原生SAX解析xml、使用dom4j解析xml、使用jdom解析xml這三種實作方式的xxe漏洞以及修複方法(修複原理是一樣的,方法都類似的,但為了友善之後産品規則的完善,這裡全部列舉出來)

使用原生SAX解析xml

從最近的微信支付看XXE漏洞

問題在于生成SAXParserFactory後直接去解析xml了,修複方法添加屬性

sf.setFeature(“http://apache.org/xml/features/disallow-doctype-decl“,true);

效果如下:

從最近的微信支付看XXE漏洞

使用dom4j解析xml:

SAXReader reader  = new SAXReader();InputStream stream = new ByteArrayInputStream(strXML.getBytes("UTF-8"));Document doc = reader.read(stream);           

複制

從最近的微信支付看XXE漏洞

修複方法:

reader.setFeature(“http://apache.org/xml/features/disallow-doctype-decl“,true);

效果如下:

從最近的微信支付看XXE漏洞

使用Jdom解析xml

SAXBuilder  builder = new SAXBuilder();Document doc = builder.build(stream);           

複制

從最近的微信支付看XXE漏洞

修複方法如下:

builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);           

複制

效果如下:

從最近的微信支付看XXE漏洞

最後是對SkyJava審計WxPayAPI結果的分析:

SkyJava是報了兩個xxe漏洞,分别是WXpayUtil.java中的mapToXml和xmlToMap這兩個方法。其中這次的微信支付xxe漏洞爆發點是在xmlToMap,是以兩個中一個是正确的一個是誤報。先分析誤報:

從最近的微信支付看XXE漏洞

該方法是實作将map中的鍵值對取出後生成xml的節點,并将其放在根節點中,像這種情況,就算map是受攻擊者控制的,生成xml的時候也不會構造出外部實體的引入。其實xxe漏洞都是解析的時候出現問題,單單隻是生成有問題的xml,并不能确定是否存在xxe漏洞,關鍵還是得看程式去解析它的時候是否有安全措施(如上面所說的添加禁止外部實體引入的屬性等)。

對于該種誤報我的建議是:不能僅僅因為沒有設定安全屬性就判斷存在漏洞,盡量是先判斷存在解析xml的情況下再根據

  1. 是否有設定安全屬性
  2. Source是否安全

來判斷是否存在漏洞。(感覺不是很好實作,以上兩段話主觀性比較強,僅做參考…..)

再說下SkyJava報的另外一個點,爆發點确定的是正确的。

從最近的微信支付看XXE漏洞

但頭說修複之後還是會報xxe漏洞,是以我看了下修複之後的方法。

從最近的微信支付看XXE漏洞

修複的方法中将http://javax.xml.XMLConstants/feature/secure-processing屬性設為true。在本地測試效果如下,發現并不能防禦xxe漏洞,是以不建議使用該方法。

從最近的微信支付看XXE漏洞

再看官方微信支付sdk修複這個xxe漏洞之後的方法是怎麼樣的

從最近的微信支付看XXE漏洞

是使用了一個專門的xml工具類來生成DocumentBuilder

從最近的微信支付看XXE漏洞

該類中設定了一些安全屬性,應該是微信支付為了保險起見吧,同時采用我上面所說的修複方法一和二(畢竟沒有絕對的安全)。但在SkyJava的規則上,我認為審計的時候隻要采舉了其中的一種就可以認為不存在xxe漏洞,如果規則上認為兩種措施都用才算不存在漏洞的話可能會導緻誤報率較高(畢竟很多程式都隻采用第一種方法防範xxe)。

最後,我還是想說我第一次在FreeBuf上發表文章,望各位大佬站在培養新人的點上,輕噴輕噴!

*本文作者:路上路人路過,屬于FreeBuf原創獎勵計劃,未經許可禁止轉載