因為zip壓縮封包件中允許存在“../”的字元串,攻擊者可以利用多個“../”在解壓時改變zip包中某個檔案的存放位置,覆寫掉應用原有的檔案。如果被覆寫掉的檔案是動态連結so、dex或者odex檔案,輕則産生本地拒絕服務漏洞,影響應用的可用性,重則可能造成任意代碼執行漏洞,危害使用者的裝置安全和資訊安全。比如近段時間發現的“寄生獸”漏洞、海豚浏覽器遠端指令執行漏洞、三星預設輸入法遠端代碼執行漏洞等都與zip檔案目錄周遊有關。
阿裡聚安全的應用漏洞掃描服務,可以檢測出應用的zip檔案目錄周遊風險。另外我們發現日本計算機應急響應小組(jpcert)給出的修複方案存在缺陷。如果使用不當(它提供的示例文檔就使用錯誤),可能起不到防止zip檔案目錄周遊的作用,并且國内有修複方案參考了此方案。
在linux/unix系統中“..”代表的是向上級目錄跳轉,如果程式在處理到諸如用“../../../../../../../../../../../etc/hosts”表示的檔案時沒有進行防護,則會跳轉出目前工作目錄,跳轉到到其他目錄中。
java代碼在解壓zip檔案時會使用到zipentry類的getname()方法。如果zip檔案中包含“../”的字元串,該方法傳回值裡面會原樣傳回。如果在這裡沒有進行防護,繼續解壓縮操作,就會将解壓檔案建立到其他目錄中。
如我們構造的zip檔案中有如下檔案:
進行解壓的代碼如下,沒有對getname進行過濾:
解壓操作時的日志:
此zip檔案存放在sd卡中,想讓解壓出來的所有檔案也存在sd卡中,但是a_poc.txt檔案卻存在了應用的資料目錄中:
以海豚浏覽器遠端代碼執行漏洞為例。
海豚浏覽器的主題設定中允許使用者通過網絡下載下傳新的主題進行更換,主題檔案其實是一個zip壓縮檔案。通過中間人攻擊的方法可以替換掉這個zip檔案。替換後的zip檔案中有重新編譯過的libdolphin.so。此so檔案重寫了jni_onload()函數:
此so檔案以“../../../../../../../../../../data/data/mobi.mgeek.tunnybrowser/files/libdolphin.so”的形式存在惡意zip檔案中。海豚浏覽器解壓惡意zip檔案後,重新的libdolphin.so就會覆寫掉原有的so檔案,重新運作海豚浏覽器會彈出toast提示框:
能彈出toast說明也就可以執行其他代碼。
這裡分析下此漏洞産生的原因是:
1、主題檔案其實是一個zip壓縮包,從伺服器下載下傳後進行解壓,但是解壓時沒有過濾getname()傳回的字元串中是否有“../”:
2、動态連結庫檔案libdolphin.so,并沒有放在應用資料的lib目錄下,而是放在了files目錄中:
加載使用的地方是com.dolphin.browser.search.redirect包中的searchredirector:
應用使用的是system.load()來加載libdolphin.so而非system.loadlibrary(),在android中,system.loadlibrary()是從應用的lib目錄中加載.so檔案,而system.load()是用某個.so檔案的絕對路徑加載,這個.so檔案可以不在應用的lib目錄中,可以在sd卡中,或者在應用的files目錄中,隻要應用有讀的權限目錄中即可。
在files目錄中,應用具有寫入權限,通過網絡中間人攻擊,同時利用zip檔案目錄周遊漏洞,替換掉檔案libdolphin.so,達到遠端指令執行的目的。
應用的lib目錄是軟連結到了/data/app-lib/應用目錄,如果libdolphin.so檔案在lib目錄下就不會被覆寫了,第三方應用在執行時沒有寫入/data/app-lib目錄的權限:
在研究中我們發現jpcert提供的修複方案存在缺陷。它是利用java的file類提供的getcanonicalpath()方法過濾掉zipentry.getname()傳回的字元串中所包含的“../”,然後檢查這個字元串是否是以要解壓到的目标目錄字元串為開頭,如果是,傳回getcanonicalpath()擷取到的字元串,如果不是,則抛出異常:
但是在jpcert給出的示例代碼中,對validatefilename()的調用對于app來說不會達到防止任意目錄周遊的目的:
其使用“.”,作為要解壓到的目的目錄,“.”表示目前目錄,經測試app程序的目前工作目錄是根目錄“/”:
檢視程序狀态,得到的app程序的目前工作目錄cwd是連結到了根目錄:
如下的demo,如果采用jpcert示例中validatefilename(entry.genname(), “.”)的調用方式,還是會産生目錄周遊讀到系統配置檔案:
讀到的hosts檔案内容:
正确的調用validatefilename()形式是傳入的要解壓到的目的目錄不要用“.”,而是指定一個絕對路徑。
1 對重要的zip壓縮封包件進行數字簽名校驗,校驗通過才進行解壓。
2 檢查zip壓縮包中使用zipentry.getname()擷取的檔案名中是否包含”../”或者”..”,檢查”../”的時候不必進行uri decode(以防通過uri編碼”..%2f”來進行繞過),測試發現zipentry.getname()對于zip包中有“..%2f”的檔案路徑不會進行處理。
3 在應用上線前使用阿裡聚安全的安全掃描服務,盡早發現應用的安全風險。
阿裡聚安全掃描器建議修複方案:
在使用java.util.zip包中zipinputstream類的進行解壓操作時,進行檢查,示例如下:
也可以使用java.util.zip包中的zipfile類,直接讀取zip包中的所有entries,然後檢查getname()的傳回值是否包含“../”:
[1] https://www.jpcert.or.jp/present/2014/20140910android-sc.pdf
[2]《海豚浏覽器與水星浏覽器遠端代碼執行漏洞詳解》http://drops.wooyun.org/mobile/8293
[3]《影響數千萬app的安卓app“寄生獸”漏洞技術分析》http://drops.wooyun.org/mobile/6910
[4]《三星預設輸入法遠端代碼執行》http://drops.wooyun.org/papers/6632
[5] http://www.oracle.com/technetwork/articles/java/compress-1565076.html
[6] http://stackoverflow.com/questions/1099300/whats-the-difference-between-getpath-getabsolutepath-and-getcanonicalpath
[7] http://stackoverflow.com/questions/7016391/difference-between-system-load-and-system-loadlibrary-in-java
目錄
android安全開發之provider元件安全
android安全開發之淺談密鑰寫死
android安全開發之淺談網頁打開app
android應用安全開發之淺談加密算法的坑
阿裡聚安全由阿裡巴巴移動安全部出品,面向企業和開發者提供企業安全解決方案,全面覆寫移動安全、資料風控、内容安全、實人認證等次元,并在業界率先提出“以業務為中心的安全”,賦能生态,與行業共享阿裡巴巴集團多年沉澱的專業安全能力。