Android Service Security

wyzsk發表於2020-08-19
作者: 瘦蛟舞 · 2015/02/14 12:41

0x00 科普


一個Service是沒有介面且能長時間執行於後臺的應用元件.其它應用的元件可以啟動一個服務執行於後臺,即使使用者切換到另一個應用也會繼續執行.另外,一個元件可以繫結到一個service來進行互動,即使這個互動是程式間通訊也沒問題.例如,一個service可能處理網路事物,播放音樂,執行檔案I/O,或與一個內容提供者互動,所有這些都在後臺進行.

0x01 知識要點


生命週期

左圖是startService()建立service,右圖是bindService()建立service。 startService與bindService都可以啟動Service,那麼它們之間有什麼區別呢?它們兩者的區別就是使Service的週期改變。由startService啟動的Service必須要有stopService來結束Service,不呼叫stopService則會造成Activity結束了而Service還執行著。bindService啟動的Service可以由unbindService來結束,也可以在Activity結束之後(onDestroy)自動結束。

關鍵方法

  • onStartCommand() 系統在其它元件比如activity透過呼叫startService()請求service啟動時呼叫這個方法.一旦這個方法執行,service就啟動並且在後臺長期執行.如果你實現了它,你需要負責在service完成任務時停止它,透過呼叫stopSelf()或stopService().(如果你只想提供繫結,你不需實現此方法).

  • OnBind() 當元件呼叫bindService()想要繫結到service時(比如想要執行程式間通訊)系統呼叫此方法.在你的實現中,你必須提供一個返回一個IBinder來以使客戶端能夠使用它與service通訊,你必須總是實現這個方法,但是如果你不允許繫結,那麼你應返回null.

  • OnCreate() 系統在service第一次建立時執行此方法,來執行只執行一次的初始化工作(在呼叫它方法如onStartCommand()或onBind()之前).如果service已經執行,這個方法不會被呼叫.

  • OnDestroy() 系統在service不再被使用並要銷燬時呼叫此方法.你的service應在此方法中釋放資源,比如執行緒,已註冊的偵聽器,接收器等等.這是service收到的最後一個呼叫.

  • public abstract boolean bindService (Intent service, ServiceConnection conn, int flags)

    BindService中使用bindService()方法來繫結服務,呼叫者和繫結者綁在一起,呼叫者一旦(all)退出服務也就終止了.

  • startService()

    startService()方法會立即返回然後Android系統呼叫service的onStartCommand()方法.但是如果service尚沒有執行,系統會先呼叫onCreate(),然後呼叫onStartCommand().

  • protected abstract void onHandleIntent (Intent intent)

    呼叫工作執行緒處理請求

  • public boolean onUnbind (Intent intent)

    當所有client均從service釋出的介面斷開的時候被呼叫。預設實現不執行任何操作,並返回false。

extends

  1. Service

    這是所有service的基類.當你派生這個類時,在service中建立一個新的執行緒來做所有的工作是十分重要的.因為這個service會預設使用你的應用的主執行緒(UI執行緒),這將拉低你的應用中所有執行的activity的效能

  2. IntentService

    這是一個Service的子類,使用一個工作執行緒來處理所有的啟動請求,一次處理一個.這是你不需你的service同時處理多個請求時的最好選擇.你所有要做的就是實現onHandleIntent(),這個方法接收每次啟動請求發來的intent,於是你可以做後臺的工作.

表現形式

  1. Started

    一個service在某個應用元件(比如一個activity)呼叫startService()時就處於"started"狀態(注意,可能已經啟動了).一旦執行後,service可以在後臺無限期地執行,即使啟動它的元件銷燬了.通常地,一個startedservice執行一個單一的操作並且不會返回給呼叫者結果.例如,它可能透過網路下載或上傳一個檔案.當操作完成後,service自己就停止了

  2. Bound

    一個service在某個應用元件呼叫bindService()時就處於"bound"狀態.一個boundservice提供一個client-server介面以使元件可以與service互動,傳送請求,獲取結果,甚至透過程式間通訊進行交叉進行這些互動.一個boundservice僅在有其它應用的元件繫結它時執行.多個應用元件可以同時繫結到一個service,但是當所有的自由競爭元件不再繫結時,service就銷燬了.

Bound Service

當建立一個提供繫結的service時,你必須提供一個客戶端用來與service互動的IBinder.有三種方式你可以定義這個介面:

  1. 從類Binder派生

    如果你的service是你自己應用的私有物,並且與客戶端執行於同一個程式中(一般都這樣),你應該透過從類Binder派生來建立你的介面並且從onBind()返回一它的例項.客戶端接收這個Binder然後使用它來直接操作所實現的Binder甚至Service的公共介面.

    當你的service僅僅是一個後臺工作並且僅服務於自己的應用時,這是最好的選擇.唯一使你不能以這種方式建立你的介面的理由就是你的service被其它應用使使用或者是跨程式的.

  2. 使用一個Messenger

    如果你需要你的介面跨程式工作,你可以為service建立一個帶有Messager的介面.在此方式下,service定義一個Handler來負責不同型別的Message物件.這個Handler是Messenger可以與客戶端共享一個IBinder的基礎,它允許客戶端使用Message物件傳送命令給servic.客戶端可以定義一個自己的Messenger以使service可以回發訊息.

    這是執行IPC的最簡單的方法,因為Messenger把所有的請求都放在佇列中依次送入一個執行緒中,所以你不必把你的service設計為執行緒安全的

  3. 使用AIDL

    AIDL(Android介面定義語言)執行把物件分解為作業系統能夠理解並能跨程式封送的基本體以執行IPC的所有的工作.上面所講的使用一個Messenger,實際上就是基於AIDL的.就像上面提到的,Messenger在一個執行緒中建立一個容納所有客戶端請求的佇列,使用service一個時刻只接收一個請求.然而,如果你想要你的service同時處理多個請求,那麼你可以直接使用AIDL.在此情況下,你的service必須是多執行緒安全的.

    要直接使用AIDL,你必須建立一個.aidl檔案,它定義了程式的介面.AndroidSDK工具使用這個檔案來生成一個實現介面和處理IPC的抽象類,之後你在你的service內派生它.

    注:大多數應用不應使用AIDL來處理一個繫結的service,因為它可能要求有多執行緒能力並且導致實現變得更加複雜.同樣的,AIDL也不適合於大多數應用並且本文件不會討論如何在你的service中使用它.如果你確定你需要直接使用AIDL,請看AIDL的文件.

注意

如果你打算只在本應用內使用自己的service,那麼你不需指定任何intent過濾器.不使用intent過濾器,你必須使用一個明確指定service的類名的intent來啟動你的service.

另外,你也可以透過包含android:exported屬性,並指定其值為“false”來保證你的service是私有的.即使你的service使用了intent過濾器,也會起作用.

當一個service被啟動後,它的生命期就不再依賴於啟動它的元件並且可以獨立執行於後臺,即使啟動它的元件死翹翹了.所以,service應該工作完成後呼叫stopSelf()自己停止掉,或者其它元件也可以呼叫stopService()停止service. 如果service沒有提供繫結功能,傳給startService()的intent是應用元件與service之間唯一的通訊方式.然而,如果你希望service回發一個結果,那麼啟動這個service的客戶端可以建立一個用於廣播(使用getBroadcast())的PendingIntent然後放在intent中傳給service,service然後就可以使用廣播來回送結果.

0x02 安全建議


service分類

私有service:不能被其他應用呼叫,相對安全
公開service:可以被任意應用呼叫
合作service:只能被信任合作公司的應用呼叫
內部service:只能被內部應用呼叫

intent-filter與exported組合建議

總結:

exported屬性明確定義
私有service不定義intent-filter並且設定exported為false
公開的service設定exported為true,intent-filter可以定義或者不定義
內部/合作service設定exported為true,intent-filter不定義

rule book

  1. 只被應用本身使用的service應設定為私有

  2. service接收到的資料需需謹慎處理

  3. 內部service需使用簽名級別的protectionLevel來判斷是否未內部應用呼叫

  4. 不應在service建立(onCreate方法被呼叫)的時候決定是否提供服務,應在onStartCommand/onBind/onHandleIntent等方法被呼叫的時候做判斷.

  5. 當service又返回資料的時候,因判斷資料接收app是否又資訊洩露的風險

  6. 有明確的服務需呼叫時使用顯示意圖

  7. 儘量不傳送敏感資訊

  8. 合作service需對合作公司的app簽名做效驗

0x03 測試方法


  1. service不像broadcast receicer只能靜態註冊,透過反編譯檢視配置檔案Androidmanifest.xml即可確定service,若有匯出的service則進行下一步

  2. 方法檢視service類,重點關注onCreate/onStarCommand/onHandleIntent方法

  3. 檢索所有類中startService/bindService方法及其傳遞的資料

  4. 根據業務情況編寫測試poc或者直接使用adb命令測試

0x04 案例


案例1:許可權提升

案例2:services劫持

攻擊原理:隱式啟動services,當存在同名services,先安裝應用的services優先順序高

攻擊模型

案例3:拒絕服務

現在除了空指標異常crash外還多出了一類crash:intent傳入物件的時候,轉化出現異常.

Serializable:

Intent i = getIntent();                             if(i.getAction().equals("serializable_action"))
    {  
        i.getSerializableExtra("serializable_key");//未做異常判斷
    }

Parcelable:

this.b =(RouterConfig)  this.getIntent().getParcelableExtra("filed_router_config");//引發轉型異常崩潰

POC內傳入畸形資料即可引發crash,修復很簡單捕獲異常即可.

案例4:訊息偽造

0x05 參考


http://blog.csdn.net/niu_gao/article/details/7307462

http://developer.android.com/reference/android/app/Service.html

http://developer.android.com/guide/components/services.html

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章