Android Applications Basics
Last updated
Last updated
Impara e pratica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Impara e pratica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Ci sono due livelli:
Il OS, che mantiene le applicazioni installate isolate l'una dall'altra.
L'applicazione stessa, che consente agli sviluppatori di esporre determinate funzionalità e configura le capacità dell'applicazione.
A ciascuna applicazione viene assegnato un ID Utente specifico. Questo avviene durante l'installazione dell'app in modo che l'app possa interagire solo con i file di proprietà del suo ID Utente o con file condivisi. Pertanto, solo l'app stessa, alcuni componenti del sistema operativo e l'utente root possono accedere ai dati delle app.
Due applicazioni possono essere configurate per utilizzare lo stesso UID. Questo può essere utile per condividere informazioni, ma se una di esse viene compromessa, i dati di entrambe le applicazioni saranno compromessi. Questo è il motivo per cui questo comportamento è sconsigliato.
Per condividere lo stesso UID, le applicazioni devono definire lo stesso valore android:sharedUserId
nei loro manifest.
Il Sandbox delle Applicazioni Android consente di eseguire ogni applicazione come un processo separato sotto un ID Utente separato. Ogni processo ha la propria macchina virtuale, quindi il codice di un'app viene eseguito in isolamento rispetto ad altre app. A partire da Android 5.0(L) SELinux è applicato. Fondamentalmente, SELinux nega tutte le interazioni tra processi e poi crea politiche per consentire solo le interazioni previste tra di essi.
Quando installi un'app e chiede permessi, l'app sta chiedendo i permessi configurati negli elementi uses-permission
nel file AndroidManifest.xml. L'elemento uses-permission indica il nome del permesso richiesto all'interno dell'attributo name. Ha anche l'attributo maxSdkVersion che smette di chiedere permessi su versioni superiori a quella specificata.
Nota che le applicazioni android non devono chiedere tutti i permessi all'inizio, possono anche chiedere permessi dinamicamente ma tutti i permessi devono essere dichiarati nel manifest.
Quando un'app espone funzionalità, può limitare l'accesso solo alle app che hanno un permesso specificato. Un elemento di permesso ha tre attributi:
Il nome del permesso
L'attributo permission-group, che consente di raggruppare permessi correlati.
Il protection-level che indica come vengono concessi i permessi. Ci sono quattro tipi:
Normale: Usato quando non ci sono minacce note all'app. L'utente non è tenuto ad approvarlo.
Pericoloso: Indica che il permesso concede all'applicazione richiedente un accesso elevato. Gli utenti sono invitati ad approvarli.
Firma: Solo le app firmate dallo stesso certificato di quello che esporta il componente possono ottenere il permesso. Questo è il tipo di protezione più forte.
FirmaOSystem: Solo le app firmate dallo stesso certificato di quello che esporta il componente o app che girano con accesso a livello di sistema possono ottenere permessi.
Queste app si trovano generalmente nelle directory /system/app
o /system/priv-app
e alcune di esse sono ottimizzate (potresti non trovare nemmeno il file classes.dex
). Queste applicazioni valgono la pena di essere controllate perché a volte girano con troppi permessi (come root).
Quelle fornite con il AOSP (Android OpenSource Project) ROM
Aggiunte dal produttore del dispositivo
Aggiunte dal fornitore di telefonia mobile (se acquistate da loro)
Per ottenere accesso root su un dispositivo android fisico, generalmente è necessario sfruttare 1 o 2 vulnerabilità che tendono a essere specifiche per il dispositivo e la versione.
Una volta che lo sfruttamento ha funzionato, di solito il binario Linux su
viene copiato in una posizione specificata nella variabile PATH dell'utente come /system/xbin
.
Una volta configurato il binario su, un'altra app Android viene utilizzata per interfacciarsi con il binario su
e elaborare richieste di accesso root come Superuser e SuperSU (disponibile nel Google Play store).
Nota che il processo di rooting è molto pericoloso e può danneggiare gravemente il dispositivo.
È possibile sostituire il sistema operativo installando un firmware personalizzato. Facendo ciò, è possibile estendere l'utilità di un vecchio dispositivo, bypassare restrizioni software o accedere all'ultima versione del codice Android. OmniROM e LineageOS sono due dei firmware più popolari da utilizzare.
Nota che non è sempre necessario rootare il dispositivo per installare un firmware personalizzato. Alcuni produttori consentono lo sblocco dei loro bootloader in modo ben documentato e sicuro.
Una volta che un dispositivo è rootato, qualsiasi app potrebbe richiedere accesso come root. Se un'applicazione malevola ottiene questo accesso, avrà accesso a quasi tutto e sarà in grado di danneggiare il telefono.
Il formato delle applicazioni Android è noto come formato file APK. È essenzialmente un file ZIP (rinominando l'estensione del file in .zip, i contenuti possono essere estratti e visualizzati).
Contenuti APK (non esaustivo)
AndroidManifest.xml
resources.arsc/strings.xml
resources.arsc: contiene risorse precompilate, come XML binario.
res/xml/files_paths.xml
META-INF/
Qui si trova il Certificato!
classes.dex
Contiene bytecode Dalvik, che rappresenta il codice Java (o Kotlin) compilato che l'applicazione esegue per impostazione predefinita.
lib/
Contiene librerie native, segregate per architettura CPU in sottodirectory.
armeabi
: codice per processori basati su ARM
armeabi-v7a
: codice per processori ARMv7 e superiori
x86
: codice per processori X86
mips
: codice solo per processori MIPS
assets/
Memorizza file vari necessari all'app, potenzialmente inclusi librerie native aggiuntive o file DEX, a volte utilizzati dagli autori di malware per nascondere codice aggiuntivo.
res/
Contiene risorse che non sono compilate in resources.arsc
Nello sviluppo Android, Java o Kotlin viene utilizzato per creare app. Invece di utilizzare la JVM come nelle app desktop, Android compila questo codice in bytecode Dalvik Executable (DEX). In passato, la macchina virtuale Dalvik gestiva questo bytecode, ma ora, l'Android Runtime (ART) prende il sopravvento nelle versioni più recenti di Android.
Per il reverse engineering, Smali diventa cruciale. È la versione leggibile dall'uomo del bytecode DEX, che agisce come un linguaggio assembly traducendo il codice sorgente in istruzioni bytecode. Smali e baksmali si riferiscono agli strumenti di assemblaggio e disassemblaggio in questo contesto.
Gli Intents sono il principale mezzo attraverso il quale le app Android comunicano tra i loro componenti o con altre app. Questi oggetti messaggio possono anche trasportare dati tra app o componenti, simile a come vengono utilizzate le richieste GET/POST nelle comunicazioni HTTP.
Quindi un Intent è fondamentalmente un messaggio che viene passato tra i componenti. Gli Intents possono essere diretti a componenti o app specifiche, o possono essere inviati senza un destinatario specifico. Per essere semplici, l'Intent può essere utilizzato:
Per avviare un'Activity, tipicamente aprendo un'interfaccia utente per un'app
Come trasmissioni per informare il sistema e le app di cambiamenti
Per avviare, fermare e comunicare con un servizio in background
Per accedere ai dati tramite ContentProviders
Come callback per gestire eventi
Se vulnerabili, gli Intents possono essere utilizzati per eseguire una varietà di attacchi.
I Filtri di Intent definiscono come un'attività, un servizio o un Broadcast Receiver possono interagire con diversi tipi di Intents. Fondamentalmente, descrivono le capacità di questi componenti, come quali azioni possono eseguire o i tipi di trasmissioni che possono elaborare. Il luogo principale per dichiarare questi filtri è all'interno del file AndroidManifest.xml, anche se per i Broadcast Receivers, codificarli è anche un'opzione.
I Filtri di Intent sono composti da categorie, azioni e filtri di dati, con la possibilità di includere metadati aggiuntivi. Questa configurazione consente ai componenti di gestire specifici Intents che corrispondono ai criteri dichiarati.
Un aspetto critico dei componenti Android (attività/servizi/provider di contenuti/receiver di trasmissione) è la loro visibilità o stato pubblico. Un componente è considerato pubblico e può interagire con altre app se è exported
con un valore di true
o se un Filtro di Intent è dichiarato per esso nel manifest. Tuttavia, c'è un modo per gli sviluppatori di mantenere esplicitamente privati questi componenti, assicurandosi che non interagiscano con altre app inavvertitamente. Questo viene realizzato impostando l'attributo exported
su false
nelle loro definizioni di manifest.
Inoltre, gli sviluppatori hanno la possibilità di garantire ulteriormente l'accesso a questi componenti richiedendo permessi specifici. L'attributo permission
può essere impostato per imporre che solo le app con il permesso designato possano accedere al componente, aggiungendo un ulteriore livello di sicurezza e controllo su chi può interagire con esso.
Gli intent vengono creati programmaticamente utilizzando un costruttore di Intent:
L'Azione dell'intento precedentemente dichiarato è ACTION_SEND e l'Extra è un mailto Uri (l'Extra è le informazioni aggiuntive che l'intento si aspetta).
Questo intento dovrebbe essere dichiarato all'interno del manifest come nel seguente esempio:
Un intent-filter deve corrispondere all'azione, ai dati e alla categoria per ricevere un messaggio.
Il processo di "risoluzione dell'Intent" determina quale app dovrebbe ricevere ciascun messaggio. Questo processo considera l'attributo di priorità, che può essere impostato nella dichiarazione dell'intent-filter, e quella con la priorità più alta sarà selezionata. Questa priorità può essere impostata tra -1000 e 1000 e le applicazioni possono utilizzare il valore SYSTEM_HIGH_PRIORITY
. Se si verifica un conflitto, appare una finestra "choser" in modo che l'utente possa decidere.
Un intent esplicito specifica il nome della classe che sta mirando:
In altre applicazioni, per accedere all'intento precedentemente dichiarato, puoi usare:
Questi consentono ad altre applicazioni di eseguire azioni per conto della tua applicazione, utilizzando l'identità e i permessi della tua app. Costruendo un Pending Intent, dovrebbe essere specificato un intent e l'azione da eseguire. Se l'intent dichiarato non è Esplicito (non dichiara quale intent può chiamarlo), un'applicazione malevola potrebbe eseguire l'azione dichiarata per conto dell'app vittima. Inoltre, se un'azione non è specificata, l'app malevola sarà in grado di fare qualsiasi azione per conto della vittima.
A differenza degli intent precedenti, che sono ricevuti solo da un'app, gli intent broadcast possono essere ricevuti da più app. Tuttavia, dalla versione API 14, è possibile specificare l'app che dovrebbe ricevere il messaggio utilizzando Intent.setPackage.
In alternativa, è anche possibile specificare un permesso quando si invia il broadcast. L'app ricevente avrà bisogno di avere quel permesso.
Ci sono due tipi di Broadcast: Normale (asincrono) e Ordinato (sincrono). L'ordine si basa sulla priorità configurata all'interno dell'elemento ricevente. Ogni app può elaborare, inoltrare o scartare il Broadcast.
È possibile inviare un broadcast utilizzando la funzione sendBroadcast(intent, receiverPermission)
dalla classe Context
.
Puoi anche utilizzare la funzione sendBroadcast
dal LocalBroadCastManager
che garantisce che il messaggio non esca mai dall'app. Utilizzando questo non avrai nemmeno bisogno di esportare un componente ricevente.
Questo tipo di Broadcasts può essere accessibile molto tempo dopo che sono stati inviati. Questi sono stati deprecati a livello API 21 ed è consigliato non usarli. Consentono a qualsiasi applicazione di sniffare i dati, ma anche di modificarli.
Se trovi funzioni contenenti la parola "sticky" come sendStickyBroadcast
o sendStickyBroadcastAsUser
, controlla l'impatto e cerca di rimuoverle.
Nelle applicazioni Android, deep links vengono utilizzati per avviare un'azione (Intent) direttamente tramite un URL. Questo viene fatto dichiarando un URL scheme specifico all'interno di un'attività. Quando un dispositivo Android cerca di accedere a un URL con questo schema, l'attività specificata all'interno dell'applicazione viene avviata.
Lo schema deve essere dichiarato nel file AndroidManifest.xml
:
Lo schema dell'esempio precedente è examplescheme://
(nota anche il category BROWSABLE
)
Quindi, nel campo dati, puoi specificare l'host e il path:
Per accedervi da un web è possibile impostare un link come:
Per trovare il codice che verrà eseguito nell'App, vai all'attività chiamata dal deeplink e cerca la funzione onNewIntent
.
Scopri come chiamare deep link senza utilizzare pagine HTML.
Il Linguaggio di Definizione dell'Interfaccia Android (AIDL) è progettato per facilitare la comunicazione tra client e servizio nelle applicazioni Android attraverso la comunicazione interprocesso (IPC). Poiché l'accesso diretto alla memoria di un altro processo non è consentito su Android, AIDL semplifica il processo marshalling degli oggetti in un formato comprensibile dal sistema operativo, facilitando così la comunicazione tra diversi processi.
Servizi Legati: Questi servizi utilizzano AIDL per IPC, consentendo ad attività o componenti di collegarsi a un servizio, fare richieste e ricevere risposte. Il metodo onBind
nella classe del servizio è fondamentale per avviare l'interazione, segnalandolo come un'area vitale per la revisione della sicurezza alla ricerca di vulnerabilità.
Messenger: Operando come un servizio legato, Messenger facilita l'IPC con un focus sul trattamento dei dati attraverso il metodo onBind
. È essenziale ispezionare questo metodo attentamente per eventuali gestioni di dati non sicure o esecuzione di funzioni sensibili.
Binder: Sebbene l'uso diretto della classe Binder sia meno comune a causa dell'astrazione di AIDL, è utile comprendere che Binder agisce come un driver a livello di kernel facilitando il trasferimento di dati tra gli spazi di memoria di diversi processi. Per ulteriori informazioni, è disponibile una risorsa su https://www.youtube.com/watch?v=O-UHvFjxwZ8.
Questi includono: Attività, Servizi, Ricevitori di Broadcast e Provider.
Nelle app Android, le attività sono come schermi, mostrando diverse parti dell'interfaccia utente dell'app. Un'app può avere molte attività, ognuna delle quali presenta uno schermo unico all'utente.
L'attività di lancio è il principale gateway per un'app, avviata quando tocchi l'icona dell'app. È definita nel file manifest dell'app con intent specifici MAIN e LAUNCHER:
Non tutte le app necessitano di un'attività di avvio, specialmente quelle senza un'interfaccia utente, come i servizi in background.
Le attività possono essere rese disponibili ad altre app o processi contrassegnandole come "exported" nel manifest. Questa impostazione consente ad altre app di avviare questa attività:
Tuttavia, accedere a un'attività da un'altra app non è sempre un rischio per la sicurezza. La preoccupazione sorge se i dati sensibili vengono condivisi in modo improprio, il che potrebbe portare a leak di informazioni.
Il ciclo di vita di un'attività inizia con il metodo onCreate, impostando l'interfaccia utente e preparando l'attività per l'interazione con l'utente.
Nello sviluppo Android, un'app ha la possibilità di creare una sottoclasse della classe Application, anche se non è obbligatorio. Quando tale sottoclasse è definita, diventa la prima classe a essere istanziata all'interno dell'app. Il metodo attachBaseContext
, se implementato in questa sottoclasse, viene eseguito prima del metodo onCreate
. Questa configurazione consente un'inizializzazione anticipata prima che il resto dell'applicazione inizi.
I servizi sono operativi in background capaci di eseguire compiti senza un'interfaccia utente. Questi compiti possono continuare a funzionare anche quando gli utenti passano ad altre applicazioni, rendendo i servizi cruciali per operazioni a lungo termine.
I servizi sono versatili; possono essere avviati in vari modi, con Intents che rappresentano il metodo principale per lanciarli come punto di ingresso di un'applicazione. Una volta che un servizio è avviato utilizzando il metodo startService
, il suo metodo onStart
entra in azione e continua a funzionare fino a quando il metodo stopService
non viene chiamato esplicitamente. In alternativa, se il ruolo di un servizio dipende da una connessione client attiva, il metodo bindService
viene utilizzato per legare il client al servizio, attivando il metodo onBind
per il passaggio dei dati.
Un'applicazione interessante dei servizi include la riproduzione di musica in background o il recupero di dati di rete senza ostacolare l'interazione dell'utente con un'app. Inoltre, i servizi possono essere resi accessibili ad altri processi sullo stesso dispositivo attraverso l'esportazione. Questo non è il comportamento predefinito e richiede una configurazione esplicita nel file Android Manifest:
I Broadcast receivers fungono da ascoltatori in un sistema di messaggistica, consentendo a più applicazioni di rispondere agli stessi messaggi dal sistema. Un'app può registrare un ricevitore in due modi principali: attraverso il Manifest dell'app o dinamicamente all'interno del codice dell'app tramite l'API registerReceiver
. Nel Manifest, le trasmissioni sono filtrate con permessi, mentre i ricevitori registrati dinamicamente possono anche specificare permessi al momento della registrazione.
I filtri di Intent sono cruciali in entrambi i metodi di registrazione, determinando quali trasmissioni attivano il ricevitore. Una volta inviata una trasmissione corrispondente, viene invocato il metodo onReceive
del ricevitore, consentendo all'app di reagire di conseguenza, come modificare il comportamento in risposta a un avviso di batteria scarica.
Le trasmissioni possono essere asincrone, raggiungendo tutti i ricevitori senza ordine, o sincrone, dove i ricevitori ricevono la trasmissione in base a priorità impostate. Tuttavia, è importante notare il potenziale rischio per la sicurezza, poiché qualsiasi app può dare priorità a se stessa per intercettare una trasmissione.
Per comprendere la funzionalità di un ricevitore, cerca il metodo onReceive
all'interno della sua classe. Il codice di questo metodo può manipolare l'Intent ricevuto, evidenziando la necessità di convalida dei dati da parte dei ricevitori, specialmente nelle Ordered Broadcasts, che possono modificare o eliminare l'Intent.
I Content Providers sono essenziali per condividere dati strutturati tra app, sottolineando l'importanza di implementare permessi per garantire la sicurezza dei dati. Consentono alle app di accedere ai dati provenienti da varie fonti, inclusi database, filesystem o il web. Permessi specifici, come readPermission
e writePermission
, sono cruciali per controllare l'accesso. Inoltre, l'accesso temporaneo può essere concesso tramite le impostazioni grantUriPermission
nel manifest dell'app, sfruttando attributi come path
, pathPrefix
e pathPattern
per un controllo dettagliato dell'accesso.
La convalida dell'input è fondamentale per prevenire vulnerabilità, come l'iniezione SQL. I Content Providers supportano operazioni di base: insert()
, update()
, delete()
e query()
, facilitando la manipolazione e la condivisione dei dati tra le applicazioni.
FileProvider, un Content Provider specializzato, si concentra sulla condivisione sicura di file. È definito nel manifest dell'app con attributi specifici per controllare l'accesso alle cartelle, denotato da android:exported
e android:resource
che puntano alle configurazioni delle cartelle. Si consiglia cautela quando si condividono directory per evitare di esporre involontariamente dati sensibili.
Esempio di dichiarazione del manifest per FileProvider:
E un esempio di specificazione delle cartelle condivise in filepaths.xml
:
Per ulteriori informazioni controlla:
WebViews sono come mini browser web all'interno delle app Android, che estraggono contenuti dal web o da file locali. Affrontano rischi simili a quelli dei browser normali, ma ci sono modi per ridurre questi rischi attraverso impostazioni specifiche.
Android offre due principali tipi di WebView:
WebViewClient è ottimo per HTML di base ma non supporta la funzione di avviso JavaScript, influenzando il modo in cui gli attacchi XSS possono essere testati.
WebChromeClient si comporta più come l'esperienza completa del browser Chrome.
Un punto chiave è che i browser WebView non condividono i cookie con il browser principale del dispositivo.
Per caricare contenuti, sono disponibili metodi come loadUrl
, loadData
, e loadDataWithBaseURL
. È cruciale assicurarsi che questi URL o file siano sicuri da usare. Le impostazioni di sicurezza possono essere gestite tramite la classe WebSettings
. Ad esempio, disabilitare JavaScript con setJavaScriptEnabled(false)
può prevenire attacchi XSS.
Il "Bridge" JavaScript consente agli oggetti Java di interagire con JavaScript, richiedendo che i metodi siano contrassegnati con @JavascriptInterface
per la sicurezza a partire da Android 4.2.
Consentire l'accesso ai contenuti (setAllowContentAccess(true)
) consente ai WebView di accedere ai Content Providers, il che potrebbe essere un rischio a meno che gli URL dei contenuti non siano verificati come sicuri.
Per controllare l'accesso ai file:
Disabilitare l'accesso ai file (setAllowFileAccess(false)
) limita l'accesso al filesystem, con eccezioni per alcuni asset, assicurando che vengano utilizzati solo per contenuti non sensibili.
La firma digitale è un must per le app Android, assicurando che siano autenticamente create prima dell'installazione. Questo processo utilizza un certificato per l'identificazione dell'app e deve essere verificato dal gestore pacchetti del dispositivo al momento dell'installazione. Le app possono essere autofirmate o certificate da un CA esterno, proteggendo contro accessi non autorizzati e garantendo che l'app rimanga intatta durante la sua consegna al dispositivo.
A partire da Android 4.2, una funzione chiamata Verifica App consente agli utenti di far controllare le app per la sicurezza prima dell'installazione. Questo processo di verifica può avvisare gli utenti contro app potenzialmente dannose, o addirittura prevenire l'installazione di quelle particolarmente dannose, migliorando la sicurezza dell'utente.
Le soluzioni MDM forniscono supervisione e sicurezza per i dispositivi mobili attraverso l'API di Amministrazione Dispositivi. Richiedono l'installazione di un'app Android per gestire e proteggere efficacemente i dispositivi mobili. Le funzioni chiave includono imposizione di politiche di password, obbligo di crittografia dello storage, e permettere la cancellazione remota dei dati, garantendo un controllo e una sicurezza completi sui dispositivi mobili.
Impara e pratica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Impara e pratica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)