鄒圳,周安民
(四川大學(xué)電子信息學(xué)院,成都610065)
近年來,隨著移動互聯(lián)網(wǎng)與信息技術(shù)的不斷發(fā)展,智能手機(jī)得到了迅猛的發(fā)展和廣泛的應(yīng)用。在當(dāng)前智能手機(jī)市場份額中,Android 系統(tǒng)占據(jù)了主要部分。根據(jù)國際數(shù)據(jù)中心(IDC)2018 年第三季度的報告[1],Android 在全球市場的占比達(dá)到了86.8%。因此,針對Android 平臺的安全性研究得到了普遍的關(guān)注。
作為Android 系統(tǒng)的核心組件,系統(tǒng)服務(wù)(System Service)是指在后臺運(yùn)行的系統(tǒng)級進(jìn)程或應(yīng)用程序,例如窗口管理服務(wù)WindowManager、通知管理服務(wù)NotificationManager、電源管理服務(wù)PowerManager 等。系統(tǒng)服務(wù)對系統(tǒng)功能進(jìn)行了封裝,并通過接口的形式為上層的應(yīng)用程序提供服務(wù)。對于應(yīng)用開發(fā)者而言,只需要了解這些接口的使用方式,通過Binder 通信機(jī)制即可與系統(tǒng)服務(wù)進(jìn)行交互,方便地獲取系統(tǒng)信息與進(jìn)行系統(tǒng)控制。然而對于攻擊者而言,系統(tǒng)服務(wù)也成為了攻擊Android 系統(tǒng)的一個突破口。因此,系統(tǒng)服務(wù)安全的重要性不言而喻。
為了系統(tǒng)地對Android 平臺的各種系統(tǒng)服務(wù)進(jìn)行安全性分析,本文在研究Binder 通信機(jī)制的基礎(chǔ)上提出了一種面向Android 系統(tǒng)服務(wù)的自動化漏洞挖掘框架。針對Android 不同版本系統(tǒng)的實(shí)驗(yàn)結(jié)果表明,該框架能夠有效識別Android 中存在的系統(tǒng)服務(wù),并構(gòu)造帶有畸形參數(shù)的請求進(jìn)行模糊測試,具有一定實(shí)用價值。
由于開源和開放的特點(diǎn),Android 系統(tǒng)的安全性一直吸引著眾多研究人員的關(guān)注。在Android 漏洞挖掘技術(shù)方面,目前常用的方法主要分為靜態(tài)分析技術(shù)和動態(tài)檢測技術(shù)。靜態(tài)分析技術(shù)[2-4]主要采用代碼審計的思想,通過逆向工程等手段獲取程序源代碼,并結(jié)合程序的函數(shù)調(diào)用關(guān)系、數(shù)據(jù)流和控制流等特征對程序代碼進(jìn)行分析,從中找出潛在的安全問題。靜態(tài)分析技術(shù)具有簡單高效、易于實(shí)現(xiàn)自動化等優(yōu)點(diǎn),可用于組件劫持、信息泄露、權(quán)限提升等漏洞挖掘的相關(guān)研究工作。靜態(tài)分析技術(shù)的缺點(diǎn)在于過于依賴漏洞特征,存在漏報和誤報問題。動態(tài)檢測技術(shù)[5]目前主要以模糊測試技術(shù)為主,該技術(shù)被廣泛地應(yīng)用于Android 系統(tǒng)與應(yīng)用程序的組件間通信機(jī)制的安全性研究中。例如Mulliner 等[6]通過構(gòu)造異常輸入數(shù)據(jù)來對Android 系統(tǒng)的短信模塊進(jìn)行模糊測試。Intent Fuzzer 及其相關(guān)改進(jìn)工具[7-9]通過發(fā)送Intent 命令的方式來測試Android應(yīng)用程序中Activity、Service、Broadcast Receiver 這3 類暴露組件的健壯性。DroidFuzzer[10]通過構(gòu)建MIME 數(shù)據(jù)來對Android 應(yīng)用程序的Activity 組件進(jìn)行模糊測試。然而,上述工具大多著眼于Intent 通信機(jī)制,而且目標(biāo)多為Android 平臺下的各種應(yīng)用程序。
因此,本文在研究Binder 通信機(jī)制的基礎(chǔ)上,通過對Android 系統(tǒng)服務(wù)進(jìn)行統(tǒng)計與分析,結(jié)合模糊測試技術(shù)對系統(tǒng)服務(wù)的安全性展開研究。
系統(tǒng)服務(wù)在整個Android 系統(tǒng)中占據(jù)著十分重要的地位,它們將Android 提供的各種功能如獲取地理位置、發(fā)送短信、檢查網(wǎng)絡(luò)連接等進(jìn)行封裝,并以應(yīng)用程序編程接口(Application Programming Interface,API)的形式為上層的應(yīng)用程序提供服務(wù)[11]。Android 系統(tǒng)服務(wù)主要分為三類:第一類是Java 系統(tǒng)服務(wù),由Java 語言編寫,通過AIDL 文件進(jìn)行封裝,運(yùn)行在System Server進(jìn)程中,這類服務(wù)在所有系統(tǒng)服務(wù)中占據(jù)了絕大部分。其次是本地守護(hù)進(jìn)程,在init.rc 文件中定義并在Android 系統(tǒng)初始化的過程中由init 進(jìn)程啟動,啟動后會常駐在系統(tǒng)中,這類服務(wù)的數(shù)量比較少,其中包括負(fù)責(zé)apk 軟件包的安裝與卸載的installd 守護(hù)進(jìn)程,負(fù)責(zé)多媒體處理的MediaServer 守護(hù)進(jìn)程,等等。最后是Native 系統(tǒng)服務(wù),由C 或C++語言編寫,運(yùn)行在本地守護(hù)進(jìn)程中,例如MediaServer 守護(hù)進(jìn)程中就包括AudioFlinger、AudioPolicyService、MediaPlayerService、CameraService 等Native 服務(wù),這類服務(wù)同樣也只占很小部分。本文主要對Java 系統(tǒng)服務(wù)的安全性進(jìn)行研究,Android 系統(tǒng)上一些常用的Java 系統(tǒng)服務(wù)如表1 所示。
表1 一些常用的系統(tǒng)服務(wù)
當(dāng)上層的應(yīng)用程序通過API 調(diào)用系統(tǒng)服務(wù)的時候,實(shí)際上是在通過Binder 通信的方式與系統(tǒng)服務(wù)進(jìn)行進(jìn)程間通信(Inter Process Communication,IPC)。系統(tǒng)服務(wù)等待著上層應(yīng)用程序發(fā)出請求,接收到請求后進(jìn)行響應(yīng)同時將結(jié)果返回給應(yīng)用程序。如果惡意的應(yīng)用程序向系統(tǒng)服務(wù)傳遞了包含畸形參數(shù)的外部輸入數(shù)據(jù),可能導(dǎo)致系統(tǒng)服務(wù)發(fā)生崩潰、設(shè)備重啟等拒絕服務(wù)的情況,甚至可能造成任意代碼執(zhí)行的嚴(yán)重后果。
為了保護(hù)應(yīng)用和系統(tǒng)免受惡意應(yīng)用的攻擊,Android 采用了基于用戶的Linux 保護(hù)機(jī)制,為每個Android 應(yīng)用設(shè)置一個內(nèi)核級應(yīng)用沙盒。默認(rèn)情況下,應(yīng)用不能彼此交互,而且對操作系統(tǒng)的訪問權(quán)限會受到限制。在應(yīng)用間需要交互的情況下,需要使用IPC 進(jìn)程間通信方式[12]。與Linux 中常用的Pipe(管道)、Signal(信號)、Message(消息隊列)、Shared Memory(共享內(nèi)存)、Semaphore(信號量)、Socket(套接字)等基于文件系統(tǒng)的IPC 方式不同,Android 系統(tǒng)選擇了采用C/S 架構(gòu)、基于權(quán)限機(jī)制的Binder 通信作為主要IPC 方式[13]。
Android 系統(tǒng)的Binder 通信模型由四大部分構(gòu)成,分 別 是Client、Server、Service Manager、Binder Driver。其中,Client、Server、Service Manager 運(yùn)行在用戶空間,Binder Driver 運(yùn)行在內(nèi)核空間。Binder Driver 提供了設(shè)備文件/dev/binder,用戶空間可通過open、ioctl 等方式與其進(jìn)行交互;Service Manager 的作用為對系統(tǒng)中的服務(wù)進(jìn)行管理,Server 通過addService()方法將自己注冊到Service Manager,Client 則通過getService()方法獲取Server 信息;Client 和Server 采用了典型的Proxy-Stub 設(shè)計模式,由AIDL 工具生成代理Proxy 和Stub 對象,兩端各自調(diào)用其中的transact()和onTransact()方法實(shí)現(xiàn)對待傳送的Parcel 數(shù)據(jù)的發(fā)送與接收,Client 和Server 之間的IPC 通信是通過底層的驅(qū)動程序來間接實(shí)現(xiàn)的。整個Binder 通信機(jī)制的系統(tǒng)架構(gòu)如圖1所示。
圖1 Binder通信架構(gòu)圖
AIDL(Android Interface Definition Language),是Android 系統(tǒng)使用的一種接口定義語言。與其他IDL語言類似,AIDL 主要用于定義Android 系統(tǒng)中Client和Server 端在進(jìn)行基于Binder 的IPC 進(jìn)程間通信時雙方都認(rèn)可的接口規(guī)范。在AIDL 機(jī)制中,Android 系統(tǒng)會提供一系列的工具將開發(fā)者定義的.aidl 文件編譯生成Client 端與Server 端的相關(guān)代碼。由于AIDL 對Binder 機(jī)制的封裝,使得開發(fā)者能夠更簡單方便地實(shí)現(xiàn)IPC 通信,而不必關(guān)心Binder 的具體細(xì)節(jié)。
圖2 展示了一個.aidl 文件示例。其中定義了get-Pid 和basicTypes 兩個接口方法,getPid 不帶任何參數(shù),basicTypes 則接收六個不同數(shù)據(jù)類型的參數(shù)。
圖2 IRemoteService.aidl文件示例
當(dāng)開發(fā)者在.aidl 文件中聲明完相關(guān)接口和方法的定義后,Android SDK 工具會自動生成與.aidl 文件同名的.java 接口文件,該文件的核心為其中的stub 內(nèi)部類,該類中包含了.aidl 文件中定義的方法聲明,并且為定義的每個方法分配了一個整型的唯一標(biāo)識code,以及供Client 端調(diào)用的代理類Proxy,和用于接收Binder 通信數(shù)據(jù)的onTransact()方法。
本文在Binder 通信機(jī)制的基礎(chǔ)上提出了一種針對Android 系統(tǒng)服務(wù)的漏洞挖掘框架。其基本思路是:首先對Android 系統(tǒng)服務(wù)展開統(tǒng)計和分析,獲取系統(tǒng)服務(wù)和接口函數(shù)的相關(guān)信息,為后續(xù)的模糊測試用例生成提供指導(dǎo)依據(jù)。然后根據(jù)一定的測試用例生成策略構(gòu)造請求數(shù)據(jù),通過Binder 驅(qū)動將請求數(shù)據(jù)發(fā)送給系統(tǒng)服務(wù)。最后通過Android 的logcat 日志系統(tǒng)對系統(tǒng)服務(wù)的運(yùn)行狀態(tài)進(jìn)行監(jiān)控,記錄進(jìn)程異常、崩潰、死亡等信息與相應(yīng)的請求數(shù)據(jù)。
在對系統(tǒng)服務(wù)進(jìn)行模糊測試之前,首先需要獲取系統(tǒng)服務(wù)以及每個服務(wù)內(nèi)定義的所有接口函數(shù)的相關(guān)信息,包括系統(tǒng)服務(wù)名、類名,接口函數(shù)的參數(shù)個數(shù)、參數(shù)類型,等等。通過分析這些信息有利于針對性地指導(dǎo)測試用例的生成,大大減少無用的測試用例,從而提高fuzzer 的效率。
(1)獲取服務(wù)名稱及句柄
本文采用Java 反射機(jī)制來獲取系統(tǒng)服務(wù)列表。在Binder 通信機(jī)制中,由Service Manager 負(fù)責(zé)對Android系統(tǒng)中所有的系統(tǒng)服務(wù)進(jìn)行管理。作為一個特殊的系統(tǒng)服務(wù),Service Manager 維持了一個服務(wù)列表,其中記錄了所有的系統(tǒng)服務(wù)名稱以及句柄。其他服務(wù)在被使用之前,需要通過add_service 方法向Service Manager進(jìn)行注冊,登記自己的服務(wù)名以及句柄。同樣的,客戶端在調(diào)用系統(tǒng)服務(wù)之前,也需要通過check_service 方法向Service Manager 查詢,通過目標(biāo)系統(tǒng)服務(wù)的名稱獲取到相關(guān)聯(lián)的句柄,并以該句柄作為目的地址發(fā)起通信請求。由于Service Manager 具有@hide 隱藏屬性,因此利用Java 的反射機(jī)制獲取android.os.ServiceManager 實(shí)例,獲取其中的listServices 方法,該方法將返回一個字符串列表,其中即包含需要的所有系統(tǒng)服務(wù)信息。
(2)獲取定義方法信息
系統(tǒng)服務(wù)信息獲取完畢后,可以類似地利用Java的反射機(jī)制嘗試獲取單個系統(tǒng)服務(wù)中定義的可供外界調(diào)用的所有方法信息。通過向Class.forName()方法傳入系統(tǒng)服務(wù)類名,可以獲取到該系統(tǒng)服務(wù)的實(shí)例對象,然后通過調(diào)用getDeclaredMethods()方法將返回一個Method 對象的數(shù)組,數(shù)組中存儲了該系統(tǒng)服務(wù)類中定義的所有方法對象,包括方法名以及對應(yīng)的參數(shù)信息。
此外,系統(tǒng)服務(wù)中定義的所有方法都將分配一個方法號,方法號從1 開始逐次遞增,單個服務(wù)中定義的N 個方法的方法號即為1 到N。此方法號即為通過transact()函數(shù)調(diào)用Binder 服務(wù)端時填充的第一個參數(shù)code。由AIDL 機(jī)制的特點(diǎn)可知,可以通過反射獲取系統(tǒng)服務(wù)類中的stub 子類對象,從中獲取到每個方法對應(yīng)的不同code 值。
獲取這些系統(tǒng)服務(wù)的相關(guān)信息主要有以下兩個作用:①確定模糊測試的測試目標(biāo);②在測試用例生成階段使用,根據(jù)方法參數(shù)信息指導(dǎo)測試用例數(shù)據(jù)的生成。
基于之前獲取的系統(tǒng)服務(wù)信息,針對Binder 通信中通常攜帶的各種數(shù)據(jù)類型,本文采用一定的生成策略對不同數(shù)據(jù)類型的數(shù)值進(jìn)行填充,如表2 所示。
表2 數(shù)據(jù)類型填充模板
除了這些常見的數(shù)據(jù)類型以外,有時還會出現(xiàn)某些特殊的數(shù)據(jù)類型導(dǎo)致無法直接構(gòu)造測試用例的情況,例如Bundle、Interface 作為方法調(diào)用的參數(shù)等,本文統(tǒng)一使用null 對該類型的數(shù)據(jù)進(jìn)行填充。
通過以上的測試用例生成策略,可以生成與系統(tǒng)服務(wù)的目標(biāo)測試方法相對應(yīng)的測試用例,以便通過目標(biāo)方法的初始參數(shù)檢查,提高模糊測試的效率。
為了能夠?qū)y試用例成功發(fā)送給系統(tǒng)服務(wù),本文實(shí)現(xiàn)了一個第三方應(yīng)用程序作為Binder 通信的客戶端??紤]到在Android 系統(tǒng)中對某些系統(tǒng)服務(wù)的調(diào)用需要一定的權(quán)限,因此在該應(yīng)用程序的AndroidManifest.xml 文件中預(yù)先請求了第三方應(yīng)用程序可以獲取的所有權(quán)限。該應(yīng)用程序通過使用Java 的反射技術(shù)來獲取系統(tǒng)服務(wù)的句柄,進(jìn)而調(diào)用相應(yīng)的系統(tǒng)服務(wù),因此具有良好的系統(tǒng)兼容性,可以在不同版本的Android 系統(tǒng)上使用。
應(yīng)用程序首先嘗試獲取所有可以獲取的系統(tǒng)權(quán)限,然后通過反射獲得目標(biāo)系統(tǒng)服務(wù)的句柄IBinder 對象,并且使用IBinder 對象調(diào)用transact()函數(shù),該函數(shù)最終將觸發(fā)系統(tǒng)服務(wù)端的onTransact()函數(shù),將測試用例原樣地傳送給系統(tǒng)服務(wù)的目標(biāo)方法。根據(jù)transact(int code,Parcel data,Parcel reply,int flags)的函數(shù)原型可知,需要對其中的各個參數(shù)進(jìn)行相應(yīng)的填充。參數(shù)code 表示目標(biāo)方法號,在系統(tǒng)服務(wù)信息收集階段已獲??;參數(shù)data 表示寫入了各種數(shù)據(jù)類型的Parcel 對象,等待發(fā)往Binder 通信的服務(wù)端,這里將依據(jù)待測試方法的參數(shù)類型寫入對應(yīng)的測試用例;參數(shù)reply 則為空的Parcel 對象,等待存儲系統(tǒng)服務(wù)的返回數(shù)據(jù);最后的參數(shù)flags 則表示Binder 通信的服務(wù)端在執(zhí)行完相應(yīng)操作后是否會返回數(shù)據(jù),這里采用默認(rèn)值0 進(jìn)行填充,即等待系統(tǒng)服務(wù)返回數(shù)據(jù)。填充完畢后即可通過transact()函數(shù)發(fā)起對系統(tǒng)服務(wù)的請求調(diào)用。
在測試用例發(fā)送給目標(biāo)系統(tǒng)服務(wù)之后,需要對系統(tǒng)服務(wù)的運(yùn)行狀態(tài)進(jìn)行監(jiān)控。本文借助adb 的Logcat工具實(shí)現(xiàn)在模糊測試期間的日志監(jiān)控。記錄的日志信息主要包括以下兩類:
(1)E/F 級別日志:該類別的日志表明系統(tǒng)服務(wù)產(chǎn)生了錯誤(error)或者嚴(yán)重錯誤(fatal),時常伴隨著系統(tǒng)服務(wù)進(jìn)程的崩潰;
(2)包含有“exception”、“crash”字符串的日志:“exception”表示系統(tǒng)服務(wù)拋出了捕獲或者未捕獲的異常,未捕獲的異常可能意味著更為嚴(yán)重的安全問題;“crash”則表示系統(tǒng)服務(wù)發(fā)生崩潰,有的crash 甚至?xí)?dǎo)致system_process 進(jìn)程崩潰,造成設(shè)備重啟的嚴(yán)重情況。
日志監(jiān)控部分的偽代碼如下:
輸入:測試用例testcases
輸出:系統(tǒng)服務(wù)產(chǎn)生崩潰時的日志以及相應(yīng)的輸入測試用例
Outputs out=executeCMD("adb logcat");
if("E"or"F"in out.logs.level)or("exception"or"crash"in out.logs.message)then
saveFile(out);
saveFile(testcases);
end if
通過對系統(tǒng)服務(wù)的異常運(yùn)行狀態(tài)進(jìn)行監(jiān)控,并記錄產(chǎn)生異常的系統(tǒng)服務(wù)與接口方法,以及造成異常的相應(yīng)測試用例,為后續(xù)定位漏洞以及對源代碼的安全審計提供了可能。
為了驗(yàn)證系統(tǒng)的有效性,本文分別在Android 7.0、Android 8.0、Android 9.0 三個不同AOSP 版本的系統(tǒng)虛擬機(jī)上進(jìn)行了實(shí)驗(yàn),發(fā)現(xiàn)了系統(tǒng)服務(wù)中的一些接口方法由于對接收的Binder 通信數(shù)據(jù)校驗(yàn)不嚴(yán)格,結(jié)果造成自身進(jìn)程甚至system_process 進(jìn)程的崩潰,導(dǎo)致系統(tǒng)拒絕服務(wù)(DoS)的后果。
系統(tǒng)的實(shí)驗(yàn)環(huán)境為安裝有Genymotion Android Emulator 軟件的64 位Windows 10 系統(tǒng)計算機(jī),Intel Xeon E3-1231 v3 CPU,內(nèi)存8GB,如表3 所示。
表3 實(shí)驗(yàn)環(huán)境
對Android 7.0、Android 8.0、Android 9.0 三個版本的系統(tǒng)進(jìn)行測試后發(fā)現(xiàn),Android 7.0 上擁有117 個系統(tǒng)服務(wù),總共包含2312 個接口方法,經(jīng)過測試后發(fā)現(xiàn)其中102 個接口方法會拋出異常;Android 8.0 上擁有126 個系統(tǒng)服務(wù),總共包含2688 個接口方法,經(jīng)過測試后發(fā)現(xiàn)其中181 個接口方法會拋出異常;Android 9.0上擁有140 個系統(tǒng)服務(wù),總共包含3106 個接口方法,經(jīng)過測試后發(fā)現(xiàn)其中166 個接口方法會拋出異常。測試結(jié)果如表4 所示。
表4 測試結(jié)果
在拋出異常之后,如果系統(tǒng)服務(wù)內(nèi)部存在相應(yīng)的異常處理機(jī)制,那么正常情況下無法造成嚴(yán)重的后果。如果系統(tǒng)服務(wù)只是對異常進(jìn)行簡單的捕獲,而沒有進(jìn)行相應(yīng)的處理,或者沒有捕獲到異常,則有可能導(dǎo)致系統(tǒng)服務(wù)進(jìn)程的崩潰。由于Android 系統(tǒng)中的所有系統(tǒng)服務(wù)均運(yùn)行在名為system_server 的系統(tǒng)進(jìn)程中,某些情況下系統(tǒng)服務(wù)的崩潰甚至?xí)?dǎo)致system_server進(jìn)程的死亡,進(jìn)而導(dǎo)致整個Android 系統(tǒng)的重啟。在測試流程中發(fā)現(xiàn)某些系統(tǒng)服務(wù)的崩潰可以造成整個設(shè)備重啟,如表5 所示。
表5 造成Android 系統(tǒng)重啟的服務(wù)與方法
由上述的實(shí)驗(yàn)結(jié)果可知,本文的設(shè)計方案可以很好地應(yīng)用于Android 系統(tǒng)服務(wù)的安全性研究中,挖掘其中可能存在的漏洞,從而提升Android 系統(tǒng)的安全性。
本文提出了一種針對Android 系統(tǒng)服務(wù)的漏洞挖掘技術(shù)方案。該方法通過獲取系統(tǒng)服務(wù)和接口方法的相關(guān)信息,基于此基礎(chǔ)上構(gòu)建覆蓋范圍廣泛的測試用例,并以Binder 通信的方式將測試用例發(fā)送給目標(biāo)服務(wù)進(jìn)行測試,最后的實(shí)驗(yàn)結(jié)果表明了技術(shù)方案的可行性和測試工具的可用性。
本文的研究工作尚存在一定的局限性,未來可通過結(jié)合符號執(zhí)行等方法對系統(tǒng)服務(wù)的程序執(zhí)行路徑展開分析,借此改進(jìn)測試用例的生成方案,以提高模糊測試效率。