文/張煜龍 陳越 包沉浮 夏良釗 鄭龍日 盧永強 韋韜
基于自適應熱補丁的Android內核漏洞生態修復方案
文/張煜龍 陳越包沉浮夏良釗鄭龍日盧永強 韋韜
學術專欄
Android內核漏洞嚴重影響了Android平臺的安全。一旦內核被攻破,所有依賴內核完整性的安全機制都岌岌可危(比如加密、進程隔離、支付、指紋驗證等)。作為Android平臺最后的防線,TrustZone也會受到威脅,因為內核可以從很多被信任的接口向TrustZone發起攻擊。因此,理想情況下Android生態圈應該及時消滅內核漏洞。然而從Google的Android Security Bulletin上看,Android內核漏洞的數量呈飛快上漲的趨勢(圖1所示)。雖然這代表著人們對內核安全的投入逐漸增大,但與此同時這些漏洞一旦公諸于眾,在很長一段時間都難以得到修復,導致越來越多的可以公開利用的漏洞變成了黑產手中的利器。縱觀近期幾起影響全世界的重大惡意malware事件[1-4],它們都攜帶了root工具,并且root的方法不是源自公開的PoC,就是直接重用了一些一鍵root工具的庫。
人們經常宣稱“Android容易被攻擊”或者“Android不如蘋果安全”。但是,表1列出了幾乎同時期iOS和Android內核漏洞數量的比較,不難發現Android漏洞公布的頻率甚至不如iOS多。雖然漏洞和漏洞并不能直接拿來比較(因為危害程度不一定一樣),但至少這可以提供一個參考基準——至少蘋果不是生來就安全的,而且也需要定期修復大量的內核漏洞。只是因為iOS修補漏洞比較全面和及時,讓人感覺它非常“安全”。同樣地,“Android不安全”并不是僅僅因為漏洞頻發,更重要的還是不能像iOS這樣及時地修復問題。
第一,Android的產業鏈過長:Android生態系統產業鏈非常長,從硬件廠商,到Google,到手機廠商,再到運營商。每一個環節都有自己的開發、質控、驗證等復雜流程,有時候還會相互沖突。這樣要消耗大量的時間和人力,而且有時甚至導致安全補丁無法下發給用戶。這個冗長的修補鏈條如圖2所示。

表1
第二,Android系統碎片化過于嚴重:Android系統的碎片化是指世界上所有Android用戶實際使用的Android版本、配置、驅動等等有著非常顯著的差異。Android系統碎片化已經成為了業界共識,由于系統的開源性,用戶、開發者、OEM廠商、運營商都可以按照自己的想法進行改造,這種“碎片化”的程度異常嚴重。在這種情況下,大多數手機設備廠商已經失去了為所有用戶使用的Android系統提供安全補丁的能力。圖3所示為繁多的Android品牌和機型。

圖1

圖2
根據Google官方發布于2016年7月的統計[6]:
1.Lollipop (Android 5.0) 發布于November 2014, 但是仍然有55% 的設備低于該版本
2.Google已經停止為低于4.4版本的Android提供補丁,但仍有23%的設備低于該版本
而在中國,由于對Google的訪問被阻隔,這一問題更加嚴重。通過隨機采樣大約200萬裝有Baidu App的設備的手機,我們發現:
1.80% 的設備低于Android 5.0
2.42% 的設備低于Android 4.4
第三,生態職能不匹配:其實最容易推進修復的是手機廠商,但大部分手機廠商自身的碎片化現象非常嚴重,導致了手機廠商沒有足夠的資源和精力去修復漏洞。而對于安全廠商來講,修復漏洞也是一件很尷尬的事情。在正常情況下,安全廠商是沒有系統授權的,除非先進行root。即使root,安全廠商仍然要面臨不同手機品牌更加嚴重的碎片化挑戰。
案例分析
具體看3個著名的能被用來進行跨平臺root的漏洞:第一個是CVE-2014-3153(Towelroot),公開和修補時間為June 3, 2014[7];第二個是CVE-2015-3636(Ping Pong Root),公開和修補時間為 September 9, 2015[8];第三個是CVE-2015-1805,公開時間為April 3, 2014[9],但直到March 18, 2016才在Android平臺上修復[10]。圖4 所示為這三個漏洞距今(2016年7月)的時間跨度。其中最短的也達到了120天。
圖5 所示為這三個漏洞在裝有百度App的手機上的隨機采樣結果。可見雖然這么長時間過去了,仍然有非常多的設備沒有得到漏洞修復。
AdaptKpatch: 自適應內核熱修補框架
如何解決Android漏洞得不到及時修補的問題?對于跳過冗長補丁鏈這個問題,學術界工業界已經給出了一些方案,比如kpatch[11], ksplice[12], kGraft[13], Linux upstream的livepatch[14],但是這些方案并沒有解決碎片化和能力失配的問題。更本質地說,這些方案都依賴源碼,對于沒有源碼的第三方不適用,更遑論補丁的廣泛適配。因此在第七屆HITB 會議上[15], 我們提出了內核自適配修補的方案,稱作AdaptKpatch。其大致流程如圖6所示。
簡單來說,該框架在手機上探測存在的內核漏洞,向用戶征詢是否修復。得到允許后,該框架root手機并收集必要的信息,包括kernel versions, symbol addresses, symbol CRCs等。取決于設備是否提供insmod或者(k)mem 設備,框架會下載對應的模板進行數據結構填充和symbol解析,并視情況對內核的一些動態校驗機制進行放寬。這些步驟完成后即完成補丁模板的適配,所生成的補丁即可插入該設備的內核執行修補操作。具體的修補操作和其他熱修補方案無異,比如函數替換、調用替換、原地修補等,此處不再贅述。 注意該框架只是熱修復,因此每次重啟都要重新加載熱補丁。如果某次啟動發現前次啟動因為熱補丁而出現崩潰,則放棄加載熱補丁回滾到正常啟動。

圖3

圖4

圖5

圖6
如果手機廠商愿意和第三方協作修復時,該框架可以最大化發揮效益。廠商不再需要花資源和精力修補漏洞,只需要提供預制的內核修補機制/能力,而安全廠商不需要再root手機和探測漏洞,可以專注在修補漏洞上。這一合作模式如圖7所示。基于這一合作聯盟,可有如下安全機制保證補丁的安全。
1.廠商資質校驗:只有有能力和名聲好的廠商方可進入合作聯盟,各廠商所發補丁需簽名驗證;
2.補丁審計:補丁發放前需要經過聯盟里別的廠商進行安全審計,防止引入新的漏洞或者后門;
3.評價排名:類似于App Store,用戶可以對某個補丁進行穩定性等方面的評價。其他用戶可以根據補丁的既有評價選擇打還是不打。
設計原理
AdaptKpatch已經能很好地解決Android內核漏洞長期得不到修復的問題了,但補丁仍然需要通過審計才能保證安全。因此我們還提出了另一個方案:LuaKpatch。其原理是用類型安全(type-safe)的動態語言引擎(比如Lua)來執行補丁。這樣一來補丁靈活易維護,同時其執行可以嚴格控制在引擎所允許的范圍內,也不擔心因為溢出、空指針引用等問題被攻擊劫持。

圖7

圖8

圖9
圖8 所示為絕大部分kernel漏洞攻擊的原理。一般而言攻擊者都需要灌入惡意的輸入來實現控制流劫持。因此LuaKpatch只需要在函數入口和函數中讀數據的位置插入檢查即可,不需要給予補丁任意hook的能力。
具體來說,我們有如下限制:
1.補丁可以hook函數入口,檢查參數和環境。
2.補丁也可以hook函數中的調用,前提是該調用返回的是狀態值(下文只有條件依賴),而不是指針等有數值依賴的返回值(copy_from_user滿足這一條件,返回是成功或失敗的狀態值)。
3.補丁可以任意讀,但不可寫,更不能發送數據出去。
4.補丁完成條件判斷后,可返回正常或異常。這樣當遇到攻擊輸入時,內核隨后的執行不會觸及會被exploit的代碼。
為了更直觀地理解,圖9給出了一個具體的例子。fun調用了foo 和bar。其中fun的入口是允許被hook的,fun中foo的調用前和調用后也是允許被hook的,因為foo返回值只有條件依賴,而bar是不能被hook的,因為下文產生了數值依賴(其中一個域被用作函數指針進行調用)。這樣一來,攻擊者即使控制了補丁,也沒法通過返回惡意數值來實現任意代碼執行。
我們為返回值只有條件依賴的函數生成了一個白名單,對于一個目標函數,其調用只有在落在這個集合里時才能被hook檢查。而且注意hook發生在目標函數調用處,而不是被調用函數的入口和返回處。我們稱能在函數口作檢查即可修復的漏洞為Type I vulnerabilities,而如果還需要在函數體內對調用做hook檢查的,則稱為Type II vulnerabilities。稍后我們會給出兩種漏洞的數目。

圖10

表2

圖11
我們基于Lua實現了LuaKpatch,為了將Lua集成在內核里,很多改變借鑒了lunatik-ng[16]. 比如數值應該修改為整型而非浮點型。LuaKpatch的代碼大約1萬1千行,其中核心的與修補有關的代碼大概600行。編譯后LuaKpatch模塊大小為800KB。廠商可以提前將這一模塊集成于內核里,或者可以借用AdaptKpatch里所介紹的內核模塊自適應加載方法,后天由第三方root手機后插入內核。
LuaKpatch為Lua形式的內核補丁提供了如下接口:符號搜索、hook(在指定位置插入trampoline,保存現場并調用Lua補丁的handler進行判定,然后回到指定位置的下一指令)、內存讀取、thread信息獲取。 圖10 為利用LuaKpatch修補Towelroot漏洞的實例。
有效性分析
如表2所示,近年幾乎有代表性的能用來root手機的內核漏洞LuaKpatch都能修補。前面提到的能在函數口作檢查即可修復的漏洞為Type I vulnerabilities,而如果還需要在函數體內對調用做hook檢查的,則稱為Type II vulnerabilities。圖11提供了這兩類漏洞的比例,大部分漏洞還是可以簡單地通過在函數口進行檢查來修補的。萬一遇到LuaKpatch不能修補的漏洞,可以回滾到AdaptKpatch方案進行修補。
性能測試
我們用CF-Bench[17]在裝有Android 4.4的Nexus 5 上測了四種情況:不打補丁,用LuaKpatch修補Towelroot,用LuaKpatch修補Ping Pong Root,用LuaKpatch修補二者。 結果如圖12 所示——LuaKpatch完全沒有帶來任何性能損耗。這是預料之中的,因為提權內核漏洞往往出現在平時無法觸及的執行路徑上,修補后并不對正常執行產生影響。

圖12

圖13

圖14
盡管如此,我們還是想知道一旦被觸及,LuaKpatch的開銷是多少。因此我們測試了chmod 系統調用的原始執行時間、打上補丁但是補丁直接return的執行時間(相當于只是現場保存恢復和Lua進出的開銷)、打上補丁且補丁做一次條件判斷的執行時間、打上補丁且補丁做一次內存地址讀的執行時間、打上補丁且補丁做一些列綜合操作(變量操作、內存讀、條件判斷等,模擬一個比Towelroot和Ping Pong Root補丁更復雜的補丁的操作)的執行時間,其結果如圖13所示。可見即使在復雜補丁的執行下,也只多了3.74微秒的開銷。這僅僅是chmod正常執行的4%。
基本上,在我們的測試里,LuaKpatch補丁都能在5微秒的開銷里完成任務。未來會把LuaKpatch的引擎換成LuaJIT[19],性能會得到進一步提升。
基于本文所述AdaptKpatch和LuaKpatch技術,Android修補流程可以改進成如圖14所示。對于非常嚴重的問題、需要幾天內推出補丁的,可以用LuaKpatch;對于LuaKpatch不能解決的問題,可以經過補丁審計后用AdaptKpatch方案推出;最終冷補丁可以永久性地修補相應問題。基于這一流程,Android內核漏洞長期難以被修復的問題可以得到妥善解決。
我們呼吁Android生態圈建立一個開放協作的聯盟,包括手機廠商、安全廠商和其他Android社區的成員。這個聯盟將具有非常重要的意義:
一是漏洞越來越多也越來越復雜,在LuaKpatch和AdaptKpatch提供的和作平臺上,大家可以分擔修補的難題,共享其成;
二是對于AdaptKpatch的場景,越多的參與者意味著更多更安全的補丁審計;
三是整個Android生態圈應該一起將這個熱修補流程維護成統一的標準,防止在當前設備碎片化之上又引入了修補方案的碎片化,導致最終還是各方分散力量修補漏洞、難以規模化有效地解決問題。
[1] http://www.cmcm.com/blog/en/security/2015-09-18/799. html
[2] https://www.fireeye.com/blog/threat-research/2015/10/ kemoge_another_mobi.html
[3] https://www.bluecoat.com/security-blog/2016-04-25/ android-exploit-delivers-dogspectus-ransomware
[4] https://blog.checkpoint.com/wp-content/uploads/2016/07/ HummingBad-Research-report_FINAL-62916.pdf
[5] http://opensignal.com/reports/2015/08/androidfragmentation
[6] https://developer.android.com/about/dashboards/index.html
[7] https://github.com/torvalds/linux/commit/e9c243a5a6de0be 8e584c604d353412584b592f8
[8] https://source.android.com/security/bulletin/2015-09-01. html
[9] https://github.com/torvalds/linux/commit/f0d1bec9d58d4c0 38d0ac958c9af82be6eb18045
[10] http://source.android.com/security/advisory/2016-03-18. html
[11] https://github.com/dynup/kpatch
[12] https://www.ksplice.com/doc/ksplice.pdf
[13] http://events.linuxfoundation.org/sites/events/files/slides/ kGraft.pdf
[14] http://lxr.free-electrons.com/source/include/linux/ livepatch.h
[15] https://conference.hitb.org/hitbsecconf2016ams/sessions/ adaptive-android-kernel-live-patching
[16] https://github.com/lunatik-ng/lunatik-ng
[17] https://play.google.com/store/apps/details?id=eu.chainfire. cfbench&hl=en
[18] https://httpd.apache.org/docs/2.4/programs/ab.html
[19] http://luajit.org