
PoC per CVE-2021-39749, che consente di avviare un'Activity arbitraria su Android 12L Beta
Questo è un PoC per CVE-2021-39749, che consente di avviare attività di altre app su Android 12L Beta indipendentemente dalle loro impostazioni permission ed exported
In Android 12L l'accesso a TaskFragmentOrganizer (intenzionalmente) non richiede più il permesso MANAGE_ACTIVITY_TASKS
L'utilizzo dell'app qui fornita richiede la disabilitazione dei Hidden API Checks; puoi farlo tramite adb shell settings put global hidden_api_policy 1. Questi non costituiscono un confine di sicurezza e esistono bypass noti basati su app
Ecco i commit che correggono questo bug (e alcuni correlati menzionati nel report originale):
startActivityInTaskFragment non si affida più a Binder.getCallingUid()ResolverActivity ora ha relinquishTaskIdentity abilitatoSurfaceControl di TaskFragment non viene più fornitoActivityRecord#appToken a TaskFragmentOrganizer ora si basa su uid invece che su pidPuoi fare il checkout di android-12.1.0_r4, annullare i primi 3 commit (o i primi 2; l'applicazione sarà comunque in grado di spegnere il dispositivo (avviando ShutdownActivity), ma la casella "Zoom and set alpha" non funzionerà)
(Il primo commit di quella lista avrà conflitti di merge nei test se provi a annullarlo, ma puoi ignorarli)
Binder.getCallingUid() che restituisce sempre l'uid di sistemaIl metodo Binder.getCallingUid() restituisce l'uid del processo che ha inviato la transazione Binder attualmente in elaborazione. Tale uid è memorizzato in una variabile thread-local. Il codice che gestisce la transazione può chiamare Binder.clearCallingIdentity() per impostare quella variabile sull'uid del proprio processo, indicando ai metodi chiamati successivamente durante la gestione della transazione che i controlli dei permessi devono essere eseguiti contro se stesso (il codice che gestisce la transazione) e non contro il chiamante della transazione Binder
A volte ci sono chiamate a Binder.getCallingUid() che vengono sempre eseguite dopo Binder.clearCallingIdentity(), quindi restituiscono sempre l'uid del proprio processo. A volte ciò avviene intenzionalmente, ad esempio in ActivityTaskManagerService#startDreamActivity (anche se è un modo piuttosto contorto di fare Process.myUid() o Os.getuid())
Ho scritto per me uno strumento di analisi statica (basato su Soot) che segnala tali chiamate a Binder.getCallingUid() (e altri controlli dei permessi) che possono avvenire solo dopo Binder.clearCallingIdentity(). (Ho una logica personalizzata per gestire l'IR Jimple/Shimple IR fornito da Soot, anche se potrebbe esserci un modo migliore per farlo con Soot, ma è quello che ho ora)
In Android 12L Beta quello strumento ne ha trovato uno in ActivityStartController#startActivityInTaskFragment (Nota: il codice sorgente non era disponibile allora poiché le versioni Beta non sono open source, ma Shimple è generalmente leggibile, quindi ho usato Soot anche come decompilatore Java)
startActivityInTaskFragmentCome parte del report di analisi statica ho ottenuto la gerarchia di chiamate dall'implementazione di onTransact() (dove inizia la chiamata Binder) a startActivityInTaskFragment:
onTransact nel codice generato da aidl di IWindowOrganizerControllerWindowOrganizerController#applyTransaction (senza argomento CallerInfo)WindowOrganizerController#applyTransaction (con argomento CallerInfo)WindowOrganizerController#applyHierarchyOpActivityStartController#startActivityInTaskFragmentHo scoperto che le chiamate Binder a applyTransaction sono presenti nella classe TaskFragmentOrganizer e ho deciso di usarla come wrapper più comodo piuttosto che fare tutte le chiamate Binder direttamente (nessuna delle due è API pubblica, quindi ho comunque dovuto usare la riflessione)
Prima di tutto, il metodo "2." chiama enforceTaskPermission, che su Android 12.0 controllava il permesso MANAGE_ACTIVITY_TASKS solo-signature che non potevamo ottenere; tuttavia su Android 12L le regole sono state allentate così che certe transazioni possono essere fatte senza permessi. Si è scoperto che nessuna delle operazioni necessarie per eseguire startActivityInTaskFragment richiedeva un permesso (se la transazione aveva un TaskFragmentOrganizer associato)
Quindi vogliamo eseguire HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT. Per farlo dobbiamo avere il nostro TaskFragment registrato in mLaunchTaskFragments, altrimenti verrà segnalata l'eccezione "Not allowed to operate with invalid fragment token"