Applicazioni iOS su Mac ARM: Opportunità di pentesting

Post sul blog 20 luglio 2021 di Jim Aspers, Specialista in Sicurezza di Bureau Veritas Cybersecurity

Quando ispezionano le applicazioni iOS per le vulnerabilità di sicurezza, i penetration tester di solito si affidano a dispositivi jailbroken in arrivo. Per le applicazioni con rilevamento del jailbreak, questo requisito può portare a ritardi nell'esecuzione, in quanto aggirare il rilevamento del jailbreak può essere un compito complicato.


Sebbene esistano metodi che consentono di iniettare strumenti di assessment della sicurezza nell'applicazione target su un dispositivo non jailbroken (si veda ad esempio frida-agent), in genere questo richiede molto tempo e ha possibilità limitate. La disponibilità di una piattaforma ampia e comoda per eseguire i security testing, che non venga segnalata dalle applicazioni come jailbroken, sarebbe molto utile.

Adobe Stock 252554510 1

MacOS può svolgere il ruolo di tale piattaforma. Il sistema operativo contiene molte potenti funzioni native utili per il reverse engineering, come dtrace e i suoi derivati (ad esempio dtruss, opensnoop). Inoltre, il traffico Wi-Fi e Bluetooth può essere banalmente intercettato localmente sul sistema (ad esempio, utilizzando Wireshark o un proxy come Burp Suite), invece di dover impostare un setup man-in-the-middle esterno.

Poco dopo l'arrivo dei computer Mac con processore ARM, Apple ha annunciato la possibilità di eseguire applicazioni iOS sul sistema operativo macOS. Per esplorare le possibilità offerte da questa funzione per il pentesting, pur rispettando le restrizioni di Apple, abbiamo cercato un modo per eseguire applicazioni iOS arbitrarie su macchine macOS.

Sebbene l'installazione di applicazioni iOS sia possibile, Apple mantiene ancora un rigido controllo su ciò che può essere installato e ciò che non può essere installato, con l'obiettivo di fornire la stessa protezione/DRM contro la pirateria che viene offerta dalla piattaforma iOS. A tal fine, Apple incoraggia gli utenti a installare le applicazioni iOS attraverso l'App Store di macOS. Inoltre, quando si installa manualmente da un pacchetto .ipa, è possibile installare solo i bundle di installazione firmati. Dopo che la comunità ha scoperto la possibilità di 'sideloading' delle applicazioni acquistate utilizzando lo stesso ID Apple con cui è stata registrata la macchina macOS, Apple ha aggiunto un'altra restrizione che significa che solo le applicazioni approvate per funzionare su macOS saranno installabili.

Sebbene sia tutt'altro che 'pulito', speriamo che il metodo dimostrato possa essere utilizzato dai pentester di applicazioni a loro vantaggio.

Accelerated mobile pages amp improve seo

Decriptare l'applicazione di destinazione

I binari delle applicazioni iOS sono crittografati utilizzando il FairPlay DRM di Apple, rendendoli inutilizzabili per chiunque, tranne che per il titolare dell'ID Apple dell'acquirente dell'applicazione. Oltre ad essere un efficace meccanismo anti-pirateria, questa crittografia implica quanto segue:

  • L'applicazione non può essere trasferita su un dispositivo che non sia associato allo stesso ID Apple;
  • L'applicazione non può essere analizzata staticamente in un disassemblatore per il reverse engineering;
  • L'applicazione non può essere modificata sul disco per la creazione di patch.

Per questo motivo, i security testing e soprattutto il reverse engineering vengono generalmente eseguiti su un'applicazione iOS non criptata.

Il processo per ottenere una versione non criptata di tutti i file binari dell'applicazione, comprese le librerie e i framework, può essere effettuato in modo più comodo utilizzando frida-ios-dump (vedere AloneMonkey/frida-ios-dump). Questo strumento basato su Frida sfrutta il fatto che per eseguire un binario criptato, un dispositivo iOS deve decriptare il binario in memoria in un formato eseguibile. Lo strumento trova e scarica le immagini binarie decifrate dalla memoria di un dispositivo jailbroken subito dopo l'avvio dell'applicazione target e crea un archivio di installazione .ipa per l'app contenente binari non crittografati.

Adobe Stock 219049287

A scopo dimostrativo, l'applicazione 'Intelligent Hub' sviluppata da VMware è stata scaricata dall'App Store iOS su un dispositivo jailbroken. Questa applicazione non è disponibile per l'installazione attraverso l'App Store di macOS e contiene molte librerie e framework. Come tale, è un bersaglio perfetto per il nostro esperimento. Per il resto di questo articolo, questa applicazione sarà utilizzata come soggetto che vorremmo eseguire su un sistema macOS e sarà indicata come 'applicazione target'.

Per eseguire il dump di un archivio .ipa per l'applicazione di destinazione contenente i binari decriptati, il comando seguente viene eseguito mentre il dispositivo iOS jailbroken è collegato tramite USB:

I OS apps pic 18

Ora, se tentiamo di installare l'archivio risultante direttamente tramite iOS Application Installer.app di macOS (che si trova in /System/Library/CoreServices/Applications/), ci imbattiamo in un errore:

I OS apps pic 1

Guardando i registri in Console.app, vediamo che la firma dell'archivio non viene accettata

I OS apps pic 2

Si tratta di un comportamento atteso, in quanto l'IPA non è stato dimesso per contenere i binari ora decriptati. Potremmo dimettere l'IPA, ma questo processo può diventare macchinoso piuttosto rapidamente, soprattutto quando sono inclusi più framework o quando l'applicazione di destinazione richiede abilitazioni esotiche. A questo scopo si possono utilizzare strumenti come AltSign, ma poiché vorremmo essere in grado di installare bundle di applicazioni arbitrarie (modificate) in qualsiasi momento per i security testing, cerchiamo un metodo per aggirare la convalida della firma sull'applicazione installata.

Imparare con l'esempio

Ispezionando l'output in Console.app durante l'installazione di applicazioni iOS ufficialmente contrassegnate come compatibili con macOS dall'App Store, scopriamo che il processo di installazione non si limita a collocare i file del bundle di installazione . Come esempio per studiare il processo di installazione, abbiamo utilizzato l'applicazione 'Aangifte 2020' sviluppata da de Belastingdienst. Questa applicazione era disponibile come app per iOS, sia attraverso gli App Store di iOS che di macOS. In questo articolo, ci riferiremo a questa applicazione come 'applicazione donatore'.

La prima osservazione è che viene creata una speciale struttura di cartelle 'wrapper' in /Applicazioni:

I OS apps pic 3

La cartella maa.iOS.app è stata trovata contenere una tipica struttura di cartelle del bundle dell'applicazione iOS.

Ulteriori osservazioni mostrano che il programma di installazione non si limita a creare questo wrapper per l'applicazione iOS vera e propria. Osservando i registri di sistema e l'attività dei file, numerosi componenti del sistema operativo sono coinvolti in questo processo apparentemente complesso, che coinvolge i record accoppiati ai dettagli del bundle in un database di sistema.

Invece di effettuare un ulteriore reverse engineering del processo di installazione, viene esplorata la possibilità di utilizzare il wrapper dell'applicazione valida per ospitare la nostra applicazione target.

Giocare con il parassita

Tornando all'archivio dell'applicazione decriptato per l'applicazione VMware Intelligent Hub, il contenuto dell'archivio può essere estratto banalmente:

I OS apps pic 4

Possiamo sovrascrivere il contenuto del bundle dell'applicazione donatrice con il contenuto estratto del bundle dell'applicazione di destinazione:

I OS apps pic 5

Ora, questo non funzionerà in modo immediato. Tutti i binari di macOS e iOS (comprese le librerie e i framework collegati dinamicamente) devono essere firmati digitalmente. Per creare una firma valida, si possono utilizzare solo i certificati emessi da Apple. La modifica di un binario comporta quindi una nuova firma del codice modificato. Queste firme sono incorporate nel binario stesso. Per le librerie, i framework e altre risorse importanti all'interno di un bundle applicativo (ad esempio Info.plist), le firme sono memorizzate in un file dedicato (_CodeSignature/CodeResources) in aggiunta. In questo modo, il sistema operativo può garantire l'integrità del codice eseguito. Per maggiori dettagli, consulti la documentazione per sviluppatori di Apple al riguardo.

Adobe Stock 225084966

Per questo motivo, la semplice sovrascrittura dei contenuti del bundle applicativo del nostro wrapper valido con quelli di Hub.app non funzionerà: le firme del codice per i binari all'interno del bundle estratto non sono valide . Poiché abbiamo copiato i contenuti del bundle applicativo modificato nel wrapper dell'applicazione donatrice, dovremo aggiungere una firma di codice ai file pertinenti. Tuttavia, non vogliamo generare manualmente il profilo di provisioning necessario, che include tutti i diritti richiesti per ogni applicazione in fase di test; ciò comporterebbe un notevole lavoro manuale nel portale per sviluppatori di Apple. Inoltre, ciò richiederebbe la modifica dei diritti dei binari per farli corrispondere alla nostra identità di codesign. In effetti, se adottassimo questo approccio, potremmo anche dimettere l'archivio del programma di installazione decrittografato nella sua interezza. Per ovviare a tutto questo, qui utilizziamo la cosiddetta 'firma ad hoc'. Da man codesign(1):

I OS apps pic 6

Quando si utilizza la firma ad hoc invece della firma regolare con un'identità di firma del codice appropriata, le firme del codice dei binari contengono solo un hash del rispettivo binario firmato. Questo hash sarà verificato dal kernel prima dell'esecuzione rispetto alla cache statica di fiducia del sistema operativo. La cache di fiducia contiene gli hash dei binari di sistema Apple conosciuti e non può essere modificata in fase di esecuzione senza sfruttare una grave vulnerabilità di sicurezza nella configurazione predefinita di macOS.

Tenendo presente questo, iniziamo firmando ad hoc il nostro bundle modificato:

I OS apps pic 7

Come previsto dalle nostre conoscenze sulla firma del codice, se applichiamo la firma del codice ad hoc e proviamo a eseguire l'applicazione, il caricatore si blocca al momento del caricamento. Poco prima del crash, osserviamo la seguente voce di registro proveniente dal kernel:

I OS apps pic 8

Vediamo che il componente coinvolto è AppleMobileFileIntegrity, comunemente noto come AMFI. AMFI viene eseguito come parte del kernel (KEXT) e gestisce il controllo dell'integrità dei binari. Il messaggio riscontrato mostra il codice di ritorno 0xe00002f0.

Cercando il sottocodice di ritorno IOreturn osservato nell'origine del kernel XNU, si può spiegare l'origine di questo errore:

I OS apps pic 9

Il kernel ha restituito un kIOReturnNotFound come risultato quando gli è stato chiesto di cercare l'hash del nostro binario nell'archivio di fiducia. Questo ha senso, poiché sappiamo che la cache di fiducia è una struttura di dati precompilata e codificata che contiene solo gli hash dei binari di cui Apple si fida. L'aggiunta dei nostri hash nell'archivio di fiducia va oltre lo scopo di questo articolo e utilizzeremo invece un banale bypass.

A scopo di test, a differenza di iOS, macOS consente all'utente di disabilitare (parzialmente) AMFI. Se disabilitiamo AMFI, l'assenza dell'hash del nostro binario firmato ad hoc nella cache di fiducia non sarà più un problema bloccante. La disabilitazione di AMFI può essere effettuata passando un argomento di avvio particolarmente interessante al kernel di macOS. L'argomento può essere aggiunto da un sistema live come segue, per essere efficace dopo il riavvio:

I OS apps pic 10

Si noti che per poter modificare gli argomenti di avvio, la System Integrity Protection (SIP) deve essere disattivata nelle versioni recenti di macOS.

Dopo aver aggiunto gli argomenti di avvio e riavviato il computer, il bundle di applicazioni firmate ad hoc non è più bloccato e può essere lanciato come un'applicazione normale attraverso Finder.app.

NOTA: la disabilitazione di AMFI, e soprattutto di SIP, disabilita il nucleo del modello di sicurezza del sistema operativo di macOS. Il SIP non dovrebbe MAI essere disabilitato su un sistema di produzione senza un'attenta considerazione dei rischi di sicurezza che comporta!

È importante notare che, affinché questo metodo funzioni, l'applicazione donatore che utilizziamo come wrapper valido per la nostra applicazione di destinazione non deve essere lanciata prima che il suo contenuto venga sovrascritto. Questo è legato al fatto che al primo avvio, macOS sembra memorizzare un riferimento all'identificatore del bundle dell'applicazione iOS in relazione al bundle del wrapper stesso. Ciò significa che se vogliamo spostare un'altra applicazione di destinazione all'interno del wrapper, dobbiamo mantenere lo stesso identificatore di bundle, oppure semplicemente disinstallare e reinstallare l'applicazione donatrice dall'App Store. La modifica del contenuto del bundle dell'applicazione iOS è possibile senza restrizioni, purché l'identificatore del bundle sia lasciato invariato e l'intero bundle sia (ad-hoc) ri-firmato dopo la modifica.

Mettiamoci al lavoro!

Come risultato del nostro piccolo hack, ora possiamo eseguire con successo la nostra applicazione di destinazione, VMware Intelligent Hub, sul nostro sistema macOS:

I OS apps pic 11

Particolarmente interessante per un pentester, ispezionare i data store dell'applicazione diventa comodo:

I OS apps pic 15

Possiamo modificare l'applicazione stessa con restrizioni minime (tenendo presente la ri-firma richiesta). Questo permette di applicare le patch in poco tempo. Un esempio di modifica del nome visualizzato dell'applicazione:

I OS apps pic 13

Di conseguenza, il nome di visualizzazione dell'applicazione (e quindi il titolo della finestra) è cambiato dopo il riavvio dell'applicazione:

I OS apps pic 14

Poiché l'applicazione iOS viene eseguita nell'ambiente nativo macOS, viene trattata in modo quasi identico alle normali applicazioni macOS. Ciò significa che il traffico di rete può essere monitorato e intercettato utilizzando strumenti comuni come Wireshark, Burp Suite o Charles. Inoltre, è possibile utilizzare gli strumenti di tracciamento e debug nativi di macOS, come lldb e gli strumenti simili a dtrace:

I OS apps pic 16

Anche allegare un ambiente di debug Xcode completo diventa banale, offrendo un'esperienza notevolmente migliorata rispetto all'utilizzo di semplici strumenti di jailbreak:

I OS apps pic 17
Mobile 06

E ora?

Abbiamo avuto successo? Beh, in parte. Ora possiamo eseguire applicazioni iOS arbitrarie sui nostri sistemi macOS. Tuttavia, tornando alla nostra dichiarazione del problema posta nell'introduzione, diverse applicazioni che utilizzano il rilevamento del jailbreak segnalano ancora il nostro sistema come jailbroken. Sarebbero necessarie ulteriori ricerche per sapere se questo approccio è adatto a risolvere questo problema.

Inoltre, non siamo riusciti a installare alcuna applicazione iOS arbitraria. Abbiamo semplicemente 'parassitato' un'applicazione donatrice. Il reverse engineering del modo in cui macOS gestisce internamente lo spawning di applicazioni iOS e l'applicazione di questo metodo per raggiungere il nostro obiettivo saranno trattati in un post successivo (vedere https://github.com/srepsa/launchr per un'anteprima). Rimanga sintonizzato!