Android Fuzz 漏洞挖掘初探

1 簡介

最近因爲某些原因,主要看了幾乎能找到的安卓相關的fuzz腳本。當然時間原因具體實際測試的並不是特別多,下面就發現的一些問題,以及個人想法分享一下。

2 實際應用過程中的收穫

2.1 binder fuzz的基礎

  (1) binder 機制
  Android的Binder機制 

Binder其實也不是Android提出來的一套新的進程間通信機制,它是基於OpenBinder來實現的。Binder是一種進程間通信機制,它是一種類似於COM和CORBA分佈式組件架構,提供遠程過程調用(RPC)功能。
那麼何爲Binder?
直觀來說,Binder是Android中的一個類,它繼承了IBinder接口;
從IPC角度來說,Binder是Android中的一種跨進程通信方式,Binder還可以理解爲一種虛擬的物理設備,它的設備驅動是/dev/binder,該通信方式在Linux中沒有;
從Android Framework角度來說,Binder是ServiceManager連接各種Manager(ActivityManager、WindowManager等)和相應ManagerService的橋樑;
從Android應用層來說,Binder是客戶端和服務端進行通信的媒介,當你Bind Service的時候,服務端會返回一個包含了服務端業務調用的Binder對象,通過這個Binder對象,客戶端就可以獲取服務端提供的服務或者數據,這裏的服務包括普通服務和基於AIDL的服務。
在Android系統的Binder機制中,由系統組件組成,分別是Client、Server、Service Manager和Binder驅動程序,其中Client、Server和Service Manager運行在用戶空間,Binder驅動程序運行內核空間,如圖1所示。Binder就是一種把這四個組件粘合在一起的粘結劑,其中核心組件便是Binder驅動程序了,Service Manager提供了輔助管理的功能,Client和Server正是在Binder驅動和Service Manager提供的基礎設施上,進行Client-Server之間的通信。Service Manager和Binder驅動已經在Android平臺中實現好,開發者只要按照規範實現自己的Client和Server組件就可以了。

  圖1 Binder架構圖

(2) Aidl機制
AIDL (Android Interface Definition Language) 是一種IDL 語言,用於生成可以在Android設備上兩個進程之間進行進程間通信(interprocess communication, IPC)的代碼。如果在一個進程中(例如Activity)要調用另一個進程中(例如Service)對象的操作,就可以使用AIDL生成可序列化的參數。
AIDL IPC機制是面向接口的,像COM或CORBA一樣,但是更加輕量級。它是使用代理類在客戶端和服務端傳遞數據。只有你允許客戶端從不同的應用程序爲了進程間的通信而去訪問你的service,以及想在你的service處理多線程。如果不需要進行不同應用程序間的併發通信(IPC),或者你想進行IPC,但不需要處理多線程的。使用AIDL前,必須要理解如何綁定service。
AIDL IPC機制是面向接口的,像COM或Corba一樣,但是更加輕量級。它是使用代理類在客戶端和實現端傳遞數據。

2.2 binder 的接口

(1)系統保留測試接口
 Android給我們留下了“測試後門”。在shell中,通過service指令可以直接對系統服務進行測試,並支持對所有aidl文件中定義的方法的測試。
直接adb shell service list 列出系統服務名稱,如圖二所示:
圖2 ServiceName 列表

測試命令 :service call SERVICE CODE 就是對aidl文件中定義的方法的測試。其中,SERVICE就是對應的service名,code就是在aidl文件中定義的方法,其數值根據定義的方法遞增,從1開始。方法中的參數是直接給的null 值。測試腳本如下圖三:

圖3 測試腳本

(2)java 反射調用接口
上述方式可以直接用python寫個腳本本地測試。第二種方法是編寫本地App,通過調用binder來對系統服務進行測試採用第二種,更加有利於學習Android系統服務及binder通信機制的相關知識。我也分別嘗試了兩種方式,比如在第一種腳本測試的過程更暴力一點,code參數直接盲測的,data數據直接給的null值。本地app的測試更溫和一點,code 直接可以反射出來,data 也重新按照格式構造了。
fuzz的切入點
爲了更好的挖掘漏洞,選擇fuzz接口需要滿足這幾個要求:
1)這個接口是開放的,是可以被低權限進程調用的
2)這個接口距離fuzz目標(系統服務)比較接近,中間路徑最好透傳,這樣比較容易分析異常
3)從簡原則
根據上面的分析,BpBinder中的transact函數就是一個很好的fuzz接口,但這個函數在底層無法直接調用。
底層transact方法介紹
在c層中,BBinder::transact中會調用onTransact,這個onTransact纔是真正處理業務的。需要注意的是,因爲我們的binder實體在本質上都是繼承於BBinder的,而且我們一般都會重載onTransact()函數,所以onTransact()實際上調用的是具體binder實體的onTransact()成員函數。也就是說,onTransact的具體實現一般在上層的binder實體,而不在BBinder。BBinder沒有實現一個默認的onTransact()成員函數,所以在遠程通信時,BBinder::transact()調用的onTransact()其實是Bnxxx或者BnInterface的某個子類的onTransact()成員函數,舉個例子,BnMediaRecorder中實現了一個onTransact函數,通過switch-case,根據不同code進行分發處理。
我們從BpBinder往上層找,很容易發現,Java層IBinder的transact函數最終調用到BpBinder,且參數是原封不動的“透傳”到底層,考慮到java層的可視化和擴展性,可以選擇IBinder的公有方法transact作爲fuzz接口。
transact的四個參數介紹。我們可以構造這四個參數進行測試。
code是int類型,指定了服務方法號
data是parcel類型,是發送的數據,滿足binder協議規則,下面會有詳述
reply也是parcel類型,是通信結束後返回的數據
flag是標記位,0爲普通RPC,需要等待,調用發起後處於阻塞狀態直到接收到返回,1爲one-way RPC,表示“不需要等待回覆的”事務,一般爲無返回值的單向調用。
根據上面分析情況,參考別人腳本寫了部分測試,如下圖4:

 圖4 app測試腳本

2.3 實際測試

在實際測試過程中,直接fuzz出來的有一個本地拒絕服務漏洞、以及UI服務的一些影響系統可用的bug。比如下面的漏洞,在華爲手機測試出來的,最新版本已經修復了adb 命令: service call package 100 即可觸發漏洞
Bug信息,如下圖5:
圖5 bug信息

漏洞位置如下圖6:
根據bug信息,找到pm包的代碼,可以定位到漏洞的真正原因,沒有對packageName校驗null值造成的本地拒絕服務。
com.android.server.pm.PackageManagerService.clearExternalStorageDataSync

圖6 漏洞位置

2.4 擴展總結

這算是第一次真正的自己嘗試去挖漏洞,收穫還是挺大的,從瞭解fuzz 基礎,到參考別人腳本去實現某些測試,這個過程也遇到了不小的難題。比如在嘗試進行文件fuzz的時候,對各種文件格式瞭解不夠詳細,在生成畸形文件測試的時候就無從下手。繼而,在安卓驅動fuzz部分也是進行了嘗試,自己去寫了一些腳本,寫的過程中發現在構造參數的過程構造不出合適數據,造成fuzz 腳本沒有真正發揮作用。這些問題,最終都要解決。
最後,最近一段時間會花大量時間在漏洞挖掘這塊,如果有感興趣的小夥伴也希望能一起多交流。

3 參考鏈接

文章:
https://blog.csdn.net/omnispace/article/details/54341584
https://blog.csdn.net/u010651541/article/details/54980839
https://www.jb51.net/hack/540592.html
腳本:
https://github.com/Venscor/AndroidSystemServiceFuuzzer
https://github.com/imcczy/SSFuzzing

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章