Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
OrganizerTransaction — PoC per CVE-2021-39749, che consente di avviare un'Activity arbitraria su Android 12L Beta | Kitploit
Strumenti/GitHubGitHub/michalbednarski/organizertransaction
Sicurezza AndroidAnalisi delle VulnerabilitàExploitPentesting di App MobiliSicurezza Mobile
GitHubmichalbednarski/organizertransaction

OrganizerTransaction

PoC per CVE-2021-39749, che consente di avviare un'Activity arbitraria su Android 12L Beta

Vedi Repository

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi
37114 anni faRevisionato da Kitploit

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):

  1. startActivityInTaskFragment non si affida più a Binder.getCallingUid()
  2. ResolverActivity ora ha relinquishTaskIdentity abilitato
  3. (Non necessario per avviare altre attività, ma consente di riposizionarle sullo schermo e renderle trasparenti e tap-jackable) SurfaceControl di TaskFragment non viene più fornito
  4. (Non mostrato nel codice qui, problema menzionato solo nel report originale) La decisione su quando inviare ActivityRecord#appToken a TaskFragmentOrganizer ora si basa su uid invece che su pid

Puoi 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 sistema

Il 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)

Come chiamare startActivityInTaskFragment

Come parte del report di analisi statica ho ottenuto la gerarchia di chiamate dall'implementazione di onTransact() (dove inizia la chiamata Binder) a startActivityInTaskFragment:

  1. onTransact nel codice generato da aidl di IWindowOrganizerController
  2. WindowOrganizerController#applyTransaction (senza argomento CallerInfo)
  3. WindowOrganizerController#applyTransaction (con argomento CallerInfo)
  4. WindowOrganizerController#applyHierarchyOp
  5. ActivityStartController#startActivityInTaskFragment

Ho 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"

Possiamo registrare tale TaskFragment tramite HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT, che chiama createTaskFragment()

(Nel codice del PoC queste transazioni vengono inviate in SecondActivity: HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT viene inviato da initOrganizerAndFragment() e HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT viene inviato da startActivityInOrganizer)

Quindi questo ci consente di chiamare startActivityInTaskFragment e gli Intent delle Activity avviate qui sono considerati provenienti dall'uid di sistema, ma si scopre che di per sé non ci permette di fare nulla: le activity avviate dal sistema non possono fare URI grants e se proviamo a lanciare un'attività di un'altra app saremo fermati dal controllo canEmbedActivity

Bypassare canEmbedActivity

Diamo un'altra occhiata a canEmbedActivity: l'embedding è consentito se taskFragment.getTask().effectiveUid è l'uid di sistema o corrisponde all'uid dell'app lanciata. Dovremo essere in un task il cui effectiveUid sia di sistema

Facciamo anche un passo indietro a createTaskFragment(): la creazione di TaskFragment era consentita solo se rootActivity.getUid() != ownerActivity.getUid(). Questo significa che la nostra activity dovrà essere in fondo alla back-stack del Task in cui si trova

Dovremo lanciare un nuovo Task (tramite Intent.FLAG_ACTIVITY_NEW_TASK) che avrà un'Activity appartenente all'uid di sistema (così Task#effectiveUid sarà impostato su AID_SYSTEM) e poi quell'Activity avvierà la nostra Activity (nello stesso Task) e chiamerà finish() su se stessa (così la nostra Activity diventerà la root di quel task permettendoci di usare createTaskFragment())

Una di queste Activity è ChooserActivity. Il Chooser è solitamente usato per scegliere a quale app l'utente vuole destinare l'azione dopo aver selezionato l'opzione "condividi". ChooserActivity però ha android:relinquishTaskIdentity="true" impostato in AndroidManifest.xml, il che significa che quando lancia un'altra Activity sovrascriverà Task#effectiveUid con l'uid dell'app appena lanciata

(relinquishTaskIdentity funziona solo quando usato dalla prima app nel Task e solo per app di sistema, quindi non possiamo usare relinquishTaskIdentity noi stessi e lanciare un'app di sistema per sovrascrivere Task#effectiveUid del nostro Task)

Un'altra Activity di questo tipo (che può avviare la nostra Activity e chiamare finish() su se stessa) è ResolverActivity. Viene usata quando si avvia un Intent implicito che risolve in più Activity. Il Resolver (a differenza del Chooser) offre l'opzione di ricordare la scelta, che è il modo in cui tu (come utente del telefono) puoi distinguere i due. ResolverActivity non aveva relinquishTaskIdentity impostato, tuttavia il Resolver usa il proprio Intent per trovare quali opzioni sono disponibili (mentre il Chooser prende l'Intent fornito negli Extras). Questo si rivela un problema per lo sfruttamento perché i flag dell'Intent usati dal Resolver quando lancia l'Activity selezionata saranno gli stessi usati per lanciare il Resolver e:

  • Se non impostiamo Intent.FLAG_ACTIVITY_NEW_TASK, il Resolver verrà lanciato nel nostro Task che ha già effectiveUid impostato permanentemente
  • Se impostiamo Intent.FLAG_ACTIVITY_NEW_TASK, il Resolver lancerà la selezione in un altro Task, che poi avrà effectiveUid impostato su quello dell'app lanciata

La soluzione a questi problemi è usarli entrambi:

  1. Prima lanciamo ChooserActivity: Forniamo al suo Intent:
    • Intent.FLAG_ACTIVITY_NEW_TASK, così il Chooser viene lanciato in un nuovo Task (che avrà effectiveUid di sistema ma solo fino al prossimo lancio di Activity)
    • Intent.EXTRA_INTENT impostato su un Intent che non corrisponde a nessuna Activity e le uniche opzioni rimaste nel Chooser proverranno da Intent.EXTRA_INITIAL_INTENTS
    • Intent.EXTRA_INITIAL_INTENTS contenente un array con un solo elemento: l'Intent che vogliamo che il Chooser lanci (quando c'è una sola opzione sia il Chooser che il Resolver saltano il prompt e lanciano immediatamente l'unica opzione e chiamano finish() su se stessi)
  2. Poi ResolverActivity viene lanciata da ChooserActivity:
    • Il Resolver non aveva impostato, quindi ora è impostato su sistema e rimarrà tale indipendentemente dalle prossime Activity lanciate in questo Task

(Nell'app del PoC la preparazione di questi passaggi viene eseguita in FirstActivity)

Altri trucchi con TaskFragmentOrganizer

TaskFragmentOrganizer riceve un SurfaceControl tramite il callback onTaskFragmentAppeared e usando quel SurfaceControl si può scalare l'Activity lanciata e renderla trasparente, mentre continuerà a ricevere eventi touch e non sarà considerata oscurata (quindi gli elementi protetti da tap-jacking possono ancora essere toccati)

Puoi vederlo selezionando la casella "Zoom and set alpha" nell'app del PoC

Questo è corretto dal commit "3." della lista di fix in alto


Un'altra cosa è che gli ActivityRecord#appToken-s delle Activity in esecuzione dentro TaskFragment vengono passati ai callback di TaskFragmentOrganizer. Questa lista era filtrata per includere solo i token delle Activity nello stesso processo, tuttavia il controllo veniva fatto confrontando il pid di TaskFragmentOrganizer con il pid dell'Activity di cui potevamo ottenere appToken. Non ho effettivamente verificato, ma penso che un'applicazione potesse creare TaskFragmentOrganizer, uscire dal processo usato per crearlo inizialmente e far riusare il suo pid come pid di un'Activity di un'altra app per ottenere il suo appToken. Ecco il commit ("4." nella lista di fix sopra) che cambia la verifica da basata su pid a basata su uid (sembra che questo commit sia stato fatto indipendentemente dal mio report però (anche se dopo))

Una volta che l'attaccante ottiene appToken di un'Activity può iniettare chiamate onActivityResult() (anche se l'app target non ha chiamato startActivityForResult() essa stessa) e possibilmente manomettere savedInstanceState (chiamando activityStopped(), supponendo che l'attaccante possa vincere la corsa con l'applicazione target che chiama quel metodo e che la chiamata aggiuntiva non causi la perdita dello stato a causa di un crash)

Non ho verificato se questo possa essere fatto in questo caso, tuttavia in precedenza, con CVE-2020-0001 (Sì, ho ottenuto un numero elegante), sono stato in grado di usare la manomissione di savedInstanceState e l'iniezione di onActivityResult() per ingannare l'app delle impostazioni di sistema e abilitare il mio AccessibilityService senza interazione dell'utente, ma questa è una storia per un'altra volta

Scarica lo strumento
relinquishTaskIdentity
Task#effectiveUid
  • L'Intent non ha Intent.FLAG_ACTIVITY_NEW_TASK, quindi la prossima Activity viene lanciata nello stesso Task
  • L'azione dell'Intent è impostata su una non standard, che corrisponde solo all'<intent-filter> che abbiamo dichiarato noi stessi nella nostra app, quindi il Resolver procede immediatamente a lanciare la nostra Activity
  • ResolverActivity lancia la nostra Activity
    • Ora siamo in un Task il cui effectiveUid è AID_SYSTEM, quindi canEmbedActivity() consente qualsiasi cosa
    • Sia il Chooser che il Resolver hanno chiamato finish() su se stessi, quindi siamo l'Activity root nel Task e ci è consentito usare createTaskFragment()