hacktricks/mobile-pentesting/ios-pentesting
2024-02-10 13:03:23 +00:00
..
basic-ios-testing-operations.md Translated to Italian 2024-02-10 13:03:23 +00:00
burp-configuration-for-ios.md Translated to Italian 2024-02-10 13:03:23 +00:00
extracting-entitlements-from-compiled-application.md Translated to Italian 2024-02-10 13:03:23 +00:00
frida-configuration-in-ios.md Translated to Italian 2024-02-10 13:03:23 +00:00
ios-app-extensions.md Translated to Italian 2024-02-10 13:03:23 +00:00
ios-basics.md Translated to Italian 2024-02-10 13:03:23 +00:00
ios-custom-uri-handlers-deeplinks-custom-schemes.md Translated to Italian 2024-02-10 13:03:23 +00:00
ios-hooking-with-objection.md Translated to Italian 2024-02-10 13:03:23 +00:00
ios-protocol-handlers.md Translated to Italian 2024-02-10 13:03:23 +00:00
ios-serialisation-and-encoding.md Translated to Italian 2024-02-10 13:03:23 +00:00
ios-testing-environment.md Translated to Italian 2024-02-10 13:03:23 +00:00
ios-uiactivity-sharing.md Translated to Italian 2024-02-10 13:03:23 +00:00
ios-uipasteboard.md Translated to Italian 2024-02-10 13:03:23 +00:00
ios-universal-links.md Translated to Italian 2024-02-10 13:03:23 +00:00
ios-webviews.md Translated to Italian 2024-02-10 13:03:23 +00:00
README.md Translated to Italian 2024-02-10 13:03:23 +00:00

iOS Pentesting


Utilizza Trickest per creare e automatizzare facilmente flussi di lavoro supportati dagli strumenti della community più avanzati al mondo.
Ottieni l'accesso oggi stesso:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}

Impara l'hacking di AWS da zero a eroe con htARTE (HackTricks AWS Red Team Expert)!

Altri modi per supportare HackTricks:

Concetti di base di iOS

{% content-ref url="ios-basics.md" %} ios-basics.md {% endcontent-ref %}

Ambiente di test

In questa pagina puoi trovare informazioni sul simulatore iOS, sugli emulatori e sul jailbreaking:

{% content-ref url="ios-testing-environment.md" %} ios-testing-environment.md {% endcontent-ref %}

Analisi iniziale

Operazioni di base per il test di iOS

Durante il test saranno suggerite diverse operazioni (connettersi al dispositivo, leggere/scrivere/caricare/scaricare file, utilizzare alcuni strumenti...). Pertanto, se non sai come eseguire una di queste azioni, inizia a leggere la pagina:

{% content-ref url="basic-ios-testing-operations.md" %} basic-ios-testing-operations.md {% endcontent-ref %}

{% hint style="info" %} Per i passaggi successivi, l'app dovrebbe essere installata sul dispositivo e dovresti aver già ottenuto il file IPA dell'applicazione.
Leggi la pagina Operazioni di base per il test di iOS per imparare come fare questo. {% endhint %}

Analisi statica di base

Si consiglia di utilizzare lo strumento MobSF per eseguire un'analisi statica automatica del file IPA.

Identificazione delle protezioni presenti nel binario:

  • PIE (Position Independent Executable): Quando abilitato, l'applicazione si carica in un indirizzo di memoria casuale ogni volta che viene avviata, rendendo più difficile prevedere il suo indirizzo di memoria iniziale.
otool -hv <app-binary> | grep PIE   # Dovrebbe includere il flag PIE
  • Stack Canaries: Per convalidare l'integrità dello stack, viene inserito un valore "canary" nello stack prima di chiamare una funzione e viene convalidato nuovamente una volta che la funzione termina.
otool -I -v <app-binary> | grep stack_chk   # Dovrebbe includere i simboli: stack_chk_guard e stack_chk_fail
  • ARC (Automatic Reference Counting): Per prevenire errori comuni di corruzione della memoria
otool -I -v <app-binary> | grep objc_release   # Dovrebbe includere il simbolo _objc_release
  • Binary crittografato: Il binario dovrebbe essere crittografato
otool -arch all -Vl <app-binary> | grep -A5 LC_ENCRYPT   # Il cryptid dovrebbe essere 1

Identificazione di funzioni sensibili/insicure

  • Algoritmi di hashing deboli
# Sul dispositivo iOS
otool -Iv <app> | grep -w "_CC_MD5"
otool -Iv <app> | grep -w "_CC_SHA1"

# Su Linux
grep -iER "_CC_MD5"
grep -iER "_CC_SHA1"
  • Funzioni di generazione di numeri casuali non sicure
# Sul dispositivo iOS
otool -Iv <app> | grep -w "_random"
otool -Iv <app> | grep -w "_srand"
otool -Iv <app> | grep -w "_rand"

# Su Linux
grep -iER "_random"
grep -iER "_srand"
grep -iER "_rand"
  • Funzione 'Malloc' non sicura
# Sul dispositivo iOS
otool -Iv <app> | grep -w "_malloc"

# Su Linux
grep -iER "_malloc"
  • Funzioni non sicure e vulnerabili
# Sul dispositivo iOS
otool -Iv <app> | grep -w "_gets"
otool -Iv <app> | grep -w "_memcpy"
otool -Iv <app> | grep -w "_strncpy"
otool -Iv <app> | grep -w "_strlen"
otool -Iv <app> | grep -w "_vsnprintf"
otool -Iv <app> | grep -w "_sscanf"
otool -Iv <app> | grep -w "_strtok"
otool -Iv <app> | grep -w "_alloca"
otool -Iv <app> | grep -w "_sprintf"
otool -Iv <app> | grep -w "_printf"
otool -Iv <app> | grep -w "_vsprintf"

# Su Linux
grep -R "_gets"
grep -iER "_memcpy"
grep -iER "_strncpy"
grep -iER "_strlen"
grep -iER "_vsnprintf"
grep -iER "_sscanf"
grep -iER "_strtok"
grep -iER "_alloca"
grep -iER "_sprintf"
grep -iER "_printf"
grep -iER "_vsprintf"

Analisi dinamica di base

Consulta l'analisi dinamica che MobSF esegue. Dovrai navigare tra le diverse viste e interagire con esse, ma verranno agganciate diverse classi per fare altre cose e verrà preparato un rapporto una volta terminato.

Elenco delle app installate

Utilizza il comando frida-ps -Uai per determinare l'identificatore del pacchetto delle app installate:

$ frida-ps -Uai
PID  Name                 Identifier
----  -------------------  -----------------------------------------
6847  Calendar             com.apple.mobilecal
6815  Mail                 com.apple.mobilemail
-  App Store            com.apple.AppStore
-  Apple Store          com.apple.store.Jolly
-  Calculator           com.apple.calculator
-  Camera               com.apple.camera
-  iGoat-Swift          OWASP.iGoat-Swift

Enumerazione di base e Hooking

Impara come enumerare i componenti dell'applicazione e come hookare facilmente metodi e classi con Objection:

{% content-ref url="ios-hooking-with-objection.md" %} ios-hooking-with-objection.md {% endcontent-ref %}

Struttura IPA

La struttura di un file IPA è essenzialmente quella di un pacchetto compresso. Rinominando l'estensione in .zip, può essere decompresso per rivelarne il contenuto. All'interno di questa struttura, un Bundle rappresenta un'applicazione completamente confezionata pronta per l'installazione. All'interno troverai una directory chiamata <NOME>.app, che racchiude le risorse dell'applicazione.

  • Info.plist: Questo file contiene dettagli di configurazione specifici dell'applicazione.
  • _CodeSignature/: Questa directory include un file plist che contiene una firma, garantendo l'integrità di tutti i file nel bundle.
  • Assets.car: Un archivio compresso che memorizza file di risorse come icone.
  • Frameworks/: Questa cartella contiene le librerie native dell'applicazione, che possono essere file .dylib o .framework.
  • PlugIns/: Questo può includere estensioni dell'applicazione, noti come file .appex, anche se non sono sempre presenti. * Core Data: Viene utilizzato per salvare i dati permanenti dell'applicazione per l'uso offline, per memorizzare dati temporanei e per aggiungere la funzionalità di annullamento all'app su un singolo dispositivo. Per sincronizzare i dati su più dispositivi in un singolo account iCloud, Core Data replica automaticamente lo schema in un contenitore CloudKit.
  • PkgInfo: Il file PkgInfo è un modo alternativo per specificare i codici di tipo e creatore della tua applicazione o bundle.
  • en.lproj, fr.proj, Base.lproj: Sono i pacchetti di lingua che contengono risorse per quelle lingue specifiche e una risorsa predefinita nel caso in cui una lingua non sia supportata.
  • Sicurezza: La directory _CodeSignature/ svolge un ruolo critico nella sicurezza dell'app verificando l'integrità di tutti i file inclusi tramite firme digitali.
  • Gestione delle risorse: Il file Assets.car utilizza la compressione per gestire efficientemente le risorse grafiche, fondamentale per ottimizzare le prestazioni dell'applicazione e ridurne la dimensione complessiva.
  • Frameworks e PlugIns: Queste directory sottolineano la modularità delle applicazioni iOS, consentendo agli sviluppatori di includere librerie di codice riutilizzabili (Frameworks/) ed estendere la funzionalità dell'app (PlugIns/).
  • Localizzazione: La struttura supporta più lingue, facilitando la diffusione globale dell'applicazione includendo risorse per pacchetti di lingua specifici.

Info.plist

L'Info.plist serve come base per le applicazioni iOS, racchiudendo dati di configurazione chiave sotto forma di coppie chiave-valore. Questo file è un requisito non solo per le applicazioni, ma anche per le estensioni delle app e i framework inclusi. È strutturato in formato XML o binario e contiene informazioni critiche che vanno dai permessi dell'app alle configurazioni di sicurezza. Per una dettagliata esplorazione delle chiavi disponibili, si può fare riferimento alla Documentazione per sviluppatori Apple.

Per coloro che desiderano lavorare con questo file in un formato più accessibile, la conversione in XML può essere facilmente ottenuta tramite l'uso di plutil su macOS (disponibile nativamente nelle versioni 10.2 e successive) o plistutil su Linux. I comandi per la conversione sono i seguenti:

  • Per macOS:
$ plutil -convert xml1 Info.plist
  • Per Linux:
$ apt install libplist-utils
$ plistutil -i Info.plist -o Info_xml.plist

Tra le molteplici informazioni che il file Info.plist può rivelare, le voci degne di nota includono le stringhe di autorizzazione dell'app (UsageDescription), gli schemi URL personalizzati (CFBundleURLTypes) e le configurazioni per la sicurezza del trasporto dell'app (NSAppTransportSecurity). Queste voci, insieme ad altre come i tipi di documento personalizzati esportati/importati (UTExportedTypeDeclarations / UTImportedTypeDeclarations), possono essere facilmente individuate ispezionando il file o utilizzando un semplice comando grep:

$ grep -i <keyword> Info.plist

Percorsi dei dati

Nell'ambiente iOS, le directory sono designate specificamente per le applicazioni di sistema e le applicazioni installate dall'utente. Le applicazioni di sistema risiedono nella directory /Applications, mentre le app installate dall'utente sono collocate sotto /private/var/containers/. Queste applicazioni vengono assegnate un identificatore univoco noto come UUID a 128 bit, rendendo difficile individuare manualmente la cartella di un'app a causa della casualità dei nomi delle directory.

Per facilitare la scoperta della directory di installazione di un'app installata dall'utente, lo strumento objection fornisce un utile comando, env. Questo comando rivela informazioni dettagliate sulla directory dell'app in questione. Di seguito è riportato un esempio di come utilizzare questo comando:

OWASP.iGoat-Swift on (iPhone: 11.1.2) [usb] # env

Name               Path
-----------------  -------------------------------------------------------------------------------------------
BundlePath         /var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app
CachesDirectory    /var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/Library/Caches
DocumentDirectory  /var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/Documents
LibraryDirectory   /var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/Library

In alternativa, il nome dell'app può essere cercato all'interno di /private/var/containers utilizzando il comando find:

find /private/var/containers -name "Progname*"

I comandi come ps e lsof possono essere utilizzati anche per identificare il processo dell'applicazione e elencare i file aperti, fornendo informazioni sui percorsi delle directory attive dell'applicazione:

ps -ef | grep -i <app-name>
lsof -p <pid> | grep -i "/containers" | head -n 1

Directory del pacchetto:

  • AppName.app
  • Questo è il pacchetto dell'applicazione come visto in precedenza nell'IPA, contiene dati essenziali dell'applicazione, contenuti statici e il binario compilato dell'applicazione.
  • Questa directory è visibile agli utenti, ma gli utenti non possono scriverci.
  • Il contenuto di questa directory non viene eseguito il backup.
  • Il contenuto di questa cartella viene utilizzato per validare la firma del codice.

Directory dei dati:

  • Documents/
  • Contiene tutti i dati generati dall'utente. La creazione di questi dati viene avviata dall'utente finale dell'applicazione.
  • Visibile agli utenti e gli utenti possono scriverci.
  • Il contenuto di questa directory viene eseguito il backup.
  • L'applicazione può disabilitare i percorsi impostando NSURLIsExcludedFromBackupKey.
  • Library/
  • Contiene tutti i file che non sono specifici dell'utente, come cache, preferenze, cookie e file di configurazione delle proprietà (plist).
  • Le app iOS di solito utilizzano le sottodirectory Application Support e Caches, ma l'app può creare sottodirectory personalizzate.
  • Library/Caches/
  • Contiene file memorizzati in cache in modo semipersistente.
  • Invisibile agli utenti e gli utenti non possono scriverci.
  • Il contenuto di questa directory non viene eseguito il backup.
  • Il sistema operativo può eliminare automaticamente i file di questa directory quando l'app non è in esecuzione e lo spazio di archiviazione è scarso.
  • Library/Application Support/
  • Contiene file persistenti necessari per l'esecuzione dell'app.
  • Invisibile agli utenti e gli utenti non possono scriverci.
  • Il contenuto di questa directory viene eseguito il backup.
  • L'applicazione può disabilitare i percorsi impostando NSURLIsExcludedFromBackupKey.
  • Library/Preferences/
  • Utilizzato per memorizzare proprietà che possono persistere anche dopo il riavvio dell'applicazione.
  • Le informazioni vengono salvate, non criptate, all'interno della sandbox dell'applicazione in un file plist chiamato [BUNDLE_ID].plist.
  • Tutte le coppie chiave/valore memorizzate utilizzando NSUserDefaults possono essere trovate in questo file.
  • tmp/
  • Utilizzare questa directory per scrivere file temporanei che non devono persistere tra i lanci dell'app.
  • Contiene file memorizzati nella cache non persistenti.
  • Invisibile agli utenti.
  • Il contenuto di questa directory non viene eseguito il backup.
  • Il sistema operativo può eliminare automaticamente i file di questa directory quando l'app non è in esecuzione e lo spazio di archiviazione è scarso.

Diamo un'occhiata più da vicino alla directory del pacchetto dell'app iGoat-Swift (.app) all'interno della directory del pacchetto (/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app):

OWASP.iGoat-Swift on (iPhone: 11.1.2) [usb] # ls
NSFileType      Perms  NSFileProtection    ...  Name
------------  -------  ------------------  ...  --------------------------------------
Regular           420  None                ...  rutger.html
Regular           420  None                ...  mansi.html
Regular           420  None                ...  splash.html
Regular           420  None                ...  about.html

Regular           420  None                ...  LICENSE.txt
Regular           420  None                ...  Sentinel.txt
Regular           420  None                ...  README.txt

Reverse Engineering Binario

All'interno della cartella <nome-applicazione>.app troverai un file binario chiamato <nome-applicazione>. Questo è il file che verrà eseguito. Puoi effettuare una semplice ispezione del binario con lo strumento otool:

otool -Vh DVIA-v2 #Check some compilation attributes
magic  cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
MH_MAGIC_64    ARM64        ALL  0x00     EXECUTE    65       7112   NOUNDEFS DYLDLINK TWOLEVEL WEAK_DEFINES BINDS_TO_WEAK PIE

otool -L DVIA-v2 #Get third party libraries
DVIA-v2:
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 400.9.1)
/usr/lib/libsqlite3.dylib (compatibility version 9.0.0, current version 274.6.0)
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.11)
@rpath/Bolts.framework/Bolts (compatibility version 1.0.0, current version 1.0.0)
[...]

Verifica se l'applicazione è criptata

Verifica se c'è qualche output per:

otool -l <app-binary> | grep -A 4 LC_ENCRYPTION_INFO

Disassemblaggio del binario

Disassembla la sezione di testo:

otool -tV DVIA-v2
DVIA-v2:
(__TEXT,__text) section
+[DDLog initialize]:
0000000100004ab8    sub    sp, sp, #0x60
0000000100004abc    stp    x29, x30, [sp, #0x50]   ; Latency: 6
0000000100004ac0    add    x29, sp, #0x50
0000000100004ac4    sub    x8, x29, #0x10
0000000100004ac8    mov    x9, #0x0
0000000100004acc    adrp    x10, 1098 ; 0x10044e000
0000000100004ad0    add    x10, x10, #0x268

Per stampare il segmento Objective-C dell'applicazione di esempio, è possibile utilizzare:

otool -oV DVIA-v2
DVIA-v2:
Contents of (__DATA,__objc_classlist) section
00000001003dd5b8 0x1004423d0 _OBJC_CLASS_$_DDLog
isa        0x1004423a8 _OBJC_METACLASS_$_DDLog
superclass 0x0 _OBJC_CLASS_$_NSObject
cache      0x0 __objc_empty_cache
vtable     0x0
data       0x1003de748
flags          0x80
instanceStart  8

Per ottenere un codice Objective-C più compatto, puoi utilizzare class-dump:

class-dump some-app
//
//     Generated by class-dump 3.5 (64 bit).
//
//     class-dump is Copyright (C) 1997-1998, 2000-2001, 2004-2013 by Steve Nygard.
//

#pragma mark Named Structures

struct CGPoint {
double _field1;
double _field2;
};

struct CGRect {
struct CGPoint _field1;
struct CGSize _field2;
};

struct CGSize {
double _field1;
double _field2;
};

Tuttavia, le migliori opzioni per disassemblare il binario sono: Hopper e IDA.


Utilizza Trickest per creare facilmente e automatizzare flussi di lavoro supportati dagli strumenti della comunità più avanzati al mondo.
Ottieni l'accesso oggi stesso:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}

Archiviazione dei dati

Per conoscere come iOS archivia i dati nel dispositivo, leggi questa pagina:

{% content-ref url="ios-basics.md" %} ios-basics.md {% endcontent-ref %}

{% hint style="warning" %} I seguenti luoghi per archiviare le informazioni dovrebbero essere controllati subito dopo l'installazione dell'applicazione, dopo aver verificato tutte le funzionalità dell'applicazione e anche dopo aver effettuato il logout da un utente e aver effettuato il login con un utente diverso.
L'obiettivo è trovare informazioni sensibili non protette dell'applicazione (password, token), dell'utente corrente e degli utenti precedentemente registrati. {% endhint %}

Plist

I file plist sono file XML strutturati che contengono coppie chiave-valore. È un modo per archiviare dati persistenti, quindi a volte è possibile trovare informazioni sensibili in questi file. Si consiglia di controllare questi file dopo l'installazione dell'app e dopo averla utilizzata intensivamente per vedere se vengono scritte nuove informazioni.

Il modo più comune per persistere i dati nei file plist è tramite l'utilizzo di NSUserDefaults. Questo file plist viene salvato all'interno della sandbox dell'app in Library/Preferences/<appBundleID>.plist

La classe NSUserDefaults fornisce un'interfaccia programmabile per interagire con il sistema predefinito. Il sistema predefinito consente a un'applicazione di personalizzare il suo comportamento in base alle preferenze dell'utente. I dati salvati da NSUserDefaults possono essere visualizzati nel bundle dell'applicazione. Questa classe archivia dati in un file plist, ma è destinata ad essere utilizzata con piccole quantità di dati.

Questi dati non possono essere più accessibili direttamente tramite un computer fidato, ma possono essere accessibili eseguendo un backup.

Puoi dumpare le informazioni salvate utilizzando NSUserDefaults utilizzando il comando ios nsuserdefaults get di objection.

Per trovare tutti i plist utilizzati dall'applicazione, puoi accedere a /private/var/mobile/Containers/Data/Application/{APPID} e eseguire:

find ./ -name "*.plist"

Per convertire file dal formato XML o binario (bplist) in formato XML, sono disponibili vari metodi a seconda del sistema operativo:

Per gli utenti macOS: Utilizzare il comando plutil. È uno strumento integrato in macOS (10.2+), progettato appositamente per questo scopo:

$ plutil -convert xml1 Info.plist

Per gli utenti Linux: Prima di tutto, installa libplist-utils, quindi utilizza plistutil per convertire il tuo file:

$ apt install libplist-utils
$ plistutil -i Info.plist -o Info_xml.plist

All'interno di una sessione di Objection: Per analizzare le applicazioni mobili, un comando specifico ti consente di convertire direttamente i file plist:

ios plist cat /private/var/mobile/Containers/Data/Application/<Application-UUID>/Library/Preferences/com.some.package.app.plist

Core Data

Core Data è un framework per gestire il livello di modello degli oggetti nella tua applicazione. Core Data può utilizzare SQLite come archivio persistente, ma il framework stesso non è un database.
CoreData non crittografa i suoi dati di default. Tuttavia, è possibile aggiungere un ulteriore livello di crittografia a CoreData. Consulta il Repo di GitHub per ulteriori dettagli.

Puoi trovare le informazioni di SQLite Core Data di un'applicazione nel percorso /private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support

Se riesci ad aprire il file SQLite e accedere a informazioni sensibili, hai trovato una configurazione errata.

{% code title="Codice da iGoat" %}

-(void)storeDetails {
AppDelegate * appDelegate = (AppDelegate *)(UIApplication.sharedApplication.delegate);

NSManagedObjectContext *context =[appDelegate managedObjectContext];

User *user = [self fetchUser];
if (user) {
return;
}
user = [NSEntityDescription insertNewObjectForEntityForName:@"User"
inManagedObjectContext:context];
user.email = CoreDataEmail;
user.password = CoreDataPassword;
NSError *error;
if (![context save:&error]) {
NSLog(@"Error in saving data: %@", [error localizedDescription]);

}else{
NSLog(@"data stored in core data");
}
}

{% endcode %}

YapDatabase

YapDatabase è un archivio chiave/valore costruito sopra SQLite.
Poiché i database Yap sono database sqlite, è possibile trovarli utilizzando il comando proposto nella sezione precedente.

Altri database SQLite

È comune che le applicazioni creino il proprio database sqlite. Potrebbero memorizzare dati sensibili al loro interno e lasciarli non criptati. Pertanto, è sempre interessante controllare ogni database all'interno della directory delle applicazioni. Quindi vai alla directory dell'applicazione dove vengono salvati i dati (/private/var/mobile/Containers/Data/Application/{APPID})

find ./ -name "*.sqlite" -or -name "*.db"

Database in tempo reale di Firebase

I developer possono archiviare e sincronizzare dati all'interno di un database cloud NoSQL tramite il database in tempo reale di Firebase. I dati, archiviati in formato JSON, vengono sincronizzati in tempo reale su tutti i client connessi.

Puoi trovare come verificare la configurazione errata dei database di Firebase qui:

{% content-ref url="../../network-services-pentesting/pentesting-web/buckets/firebase-database.md" %} firebase-database.md {% endcontent-ref %}

Database di Realm

Realm Objective-C e Realm Swift offrono un'alternativa potente per l'archiviazione dei dati, non fornita da Apple. Di default, i dati vengono archiviati in forma non crittografata, ma è possibile abilitare la crittografia tramite una specifica configurazione.

I database si trovano in: /private/var/mobile/Containers/Data/Application/{APPID}. Per esplorare questi file, è possibile utilizzare comandi come:

iPhone:/private/var/mobile/Containers/Data/Application/A079DF84-726C-4AEA-A194-805B97B3684A/Documents root# ls
default.realm  default.realm.lock  default.realm.management/  default.realm.note|

$ find ./ -name "*.realm*"

Per visualizzare questi file di database, si consiglia l'utilizzo dello strumento Realm Studio.

Per implementare la crittografia all'interno di un database Realm, è possibile utilizzare il seguente frammento di codice:

// Open the encrypted Realm file where getKey() is a method to obtain a key from the Keychain or a server
let config = Realm.Configuration(encryptionKey: getKey())
do {
let realm = try Realm(configuration: config)
// Use the Realm as normal
} catch let error as NSError {
// If the encryption key is wrong, `error` will say that it's an invalid database
fatalError("Error opening realm: \(error)")
}

Database di Couchbase Lite

Couchbase Lite è descritto come un motore di database leggero e integrato che segue l'approccio orientato ai documenti (NoSQL). Progettato per essere nativo di iOS e macOS, offre la capacità di sincronizzare i dati in modo trasparente.

Per identificare potenziali database di Couchbase su un dispositivo, è necessario ispezionare la seguente directory:

ls /private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support/

Cookies

iOS memorizza i cookie delle app nella cartella Library/Cookies/cookies.binarycookies all'interno di ogni cartella dell'app. Tuttavia, gli sviluppatori a volte decidono di salvarli nel keychain poiché il suddetto file dei cookie può essere accessibile nei backup.

Per ispezionare il file dei cookie puoi utilizzare questo script python o utilizzare il comando ios cookies get di objection.
Puoi anche utilizzare objection per convertire questi file in formato JSON e ispezionare i dati.

...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # ios cookies get --json
[
{
"domain": "highaltitudehacks.com",
"expiresDate": "2051-09-15 07:46:43 +0000",
"isHTTPOnly": "false",
"isSecure": "false",
"name": "username",
"path": "/",
"value": "admin123",
"version": "0"
}
]

Cache

Per impostazione predefinita, NSURLSession memorizza i dati, come le richieste e le risposte HTTP, nel database Cache.db. Questo database può contenere dati sensibili, se sono stati memorizzati token, nomi utente o altre informazioni sensibili. Per trovare le informazioni memorizzate nella cache, aprire la directory dei dati dell'app (/var/mobile/Containers/Data/Application/<UUID>) e andare a /Library/Caches/<Bundle Identifier>. La cache di WebKit viene anche memorizzata nel file Cache.db. Objection può aprire e interagire con il database con il comando sqlite connect Cache.db, poiché si tratta di un normale database SQLite.

È consigliabile disabilitare la memorizzazione nella cache di questi dati, poiché potrebbero contenere informazioni sensibili nella richiesta o nella risposta. Di seguito sono elencati diversi modi per ottenere questo:

  1. Si consiglia di rimuovere le risposte memorizzate nella cache dopo il logout. Ciò può essere fatto utilizzando il metodo fornito da Apple chiamato removeAllCachedResponses. È possibile chiamare questo metodo nel seguente modo:

URLCache.shared.removeAllCachedResponses()

Questo metodo rimuoverà tutte le richieste e le risposte memorizzate nella cache dal file Cache.db. 2. Se non è necessario utilizzare i vantaggi dei cookie, sarebbe consigliabile utilizzare la proprietà di configurazione .ephemeral di URLSession, che disabiliterà il salvataggio dei cookie e della cache.

Documentazione Apple:

Un oggetto di configurazione di sessione effimera è simile a un oggetto di configurazione di sessione predefinito (vedi default), ad eccezione del fatto che l'oggetto di sessione corrispondente non memorizza cache, archivi di credenziali o dati correlati alla sessione su disco. Invece, i dati correlati alla sessione vengono memorizzati nella RAM. L'unico momento in cui una sessione effimera scrive dati su disco è quando si indica di scrivere il contenuto di un URL su un file. 3. La cache può essere disabilitata anche impostando la Cache Policy su .notAllowed. Ciò disabiliterà la memorizzazione della cache in qualsiasi modo, sia in memoria che su disco.

Snapshots

Ogni volta che si preme il pulsante home, iOS fa uno snapshot dello schermo corrente per poter effettuare la transizione all'applicazione in modo più fluido. Tuttavia, se sono presenti dati sensibili nello schermo corrente, verranno salvati nell'immagine (che persiste anche dopo il riavvio). Questi sono gli snapshot a cui è possibile accedere anche facendo doppio tap sulla schermata home per passare tra le app.

A meno che l'iPhone non sia jailbroken, l'attaccante deve avere accesso al dispositivo sbloccato per vedere queste schermate. Per impostazione predefinita, l'ultimo snapshot viene memorizzato nella sandbox dell'app nella cartella Library/Caches/Snapshots/ o Library/SplashBoard/Snapshots (i computer fidati non possono accedere al filesystem da iOS 7.0).

Un modo per prevenire questo comportamento indesiderato è quello di mettere uno schermo vuoto o rimuovere i dati sensibili prima di fare lo snapshot utilizzando la funzione ApplicationDidEnterBackground().

Di seguito è riportato un esempio di metodo di correzione che imposterà uno screenshot predefinito.

Swift:

private var backgroundImage: UIImageView?

func applicationDidEnterBackground(_ application: UIApplication) {
let myBanner = UIImageView(image: #imageLiteral(resourceName: "overlayImage"))
myBanner.frame = UIScreen.main.bounds
backgroundImage = myBanner
window?.addSubview(myBanner)
}

func applicationWillEnterForeground(_ application: UIApplication) {
backgroundImage?.removeFromSuperview()
}

Objective-C:

Objective-C è un linguaggio di programmazione utilizzato per lo sviluppo di applicazioni iOS. È un'estensione del linguaggio C e fornisce funzionalità aggiuntive per la programmazione orientata agli oggetti. Objective-C è ampiamente utilizzato nello sviluppo di applicazioni iOS e macOS.

Per la pentest di applicazioni iOS, è importante comprendere i concetti di base di Objective-C. Questo linguaggio viene utilizzato per scrivere il codice dell'applicazione e comprendere come funziona può aiutare a identificare potenziali vulnerabilità.

Alcuni concetti chiave di Objective-C includono:

  • Classi e oggetti: Objective-C è un linguaggio orientato agli oggetti, quindi è importante comprendere come definire classi e creare oggetti.
  • Proprietà e metodi: le proprietà definiscono le caratteristiche degli oggetti, mentre i metodi definiscono il comportamento degli oggetti.
  • Messaggi: in Objective-C, gli oggetti comunicano tra loro inviando messaggi. È importante comprendere come funzionano i messaggi e come possono essere utilizzati per interagire con gli oggetti.
  • Delegati: i delegati sono un concetto chiave in Objective-C e vengono utilizzati per consentire a un oggetto di comunicare con un altro oggetto. È importante comprendere come funzionano i delegati e come possono essere utilizzati per gestire eventi e dati.

Comprendere Objective-C può essere utile durante la pentest di applicazioni iOS, in quanto consente di analizzare il codice sorgente dell'applicazione e identificare potenziali vulnerabilità o problemi di sicurezza.

@property (UIImageView *)backgroundImage;

- (void)applicationDidEnterBackground:(UIApplication *)application {
UIImageView *myBanner = [[UIImageView alloc] initWithImage:@"overlayImage.png"];
self.backgroundImage = myBanner;
self.backgroundImage.bounds = UIScreen.mainScreen.bounds;
[self.window addSubview:myBanner];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
[self.backgroundImage removeFromSuperview];
}

Questo imposta l'immagine di sfondo su overlayImage.png ogni volta che l'applicazione viene messa in background. Ciò impedisce la divulgazione di dati sensibili perché overlayImage.png sovrascriverà sempre la vista corrente.

Keychain

Per accedere e gestire il keychain di iOS, sono disponibili strumenti come Keychain-Dumper, adatti per dispositivi jailbroken. Inoltre, Objection fornisce il comando ios keychain dump per scopi simili.

Memorizzazione delle credenziali

La classe NSURLCredential è ideale per salvare informazioni sensibili direttamente nel keychain, bypassando la necessità di NSUserDefaults o altri wrapper. Per memorizzare le credenziali dopo il login, viene utilizzato il seguente codice Swift:

NSURLCredential *credential;
credential = [NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistencePermanent];
[[NSURLCredentialStorage sharedCredentialStorage] setCredential:credential forProtectionSpace:self.loginProtectionSpace];

Per estrarre queste credenziali memorizzate, viene utilizzato il comando ios nsurlcredentialstorage dump di Objection.

Tastiere personalizzate e cache della tastiera

Con iOS 8.0 in poi, gli utenti possono installare estensioni di tastiera personalizzate, che sono gestibili in Impostazioni > Generale > Tastiera > Tastiere. Sebbene queste tastiere offrano funzionalità estese, rappresentano un rischio di registrazione dei tasti premuti e di trasmissione dei dati a server esterni, anche se agli utenti viene notificato quando una tastiera richiede l'accesso alla rete. Le app possono e dovrebbero limitare l'uso delle tastiere personalizzate per l'inserimento di informazioni sensibili.

Raccomandazioni di sicurezza:

  • Si consiglia di disabilitare le tastiere di terze parti per una maggiore sicurezza.
  • Prestare attenzione alle funzioni di autocorrezione e suggerimenti automatici della tastiera predefinita di iOS, che potrebbero memorizzare informazioni sensibili nei file di cache situati in Library/Keyboard/{locale}-dynamic-text.dat o /private/var/mobile/Library/Keyboard/dynamic-text.dat. Questi file di cache dovrebbero essere controllati regolarmente per verificare la presenza di dati sensibili. Si consiglia di ripristinare il dizionario della tastiera tramite Impostazioni > Generale > Ripristina > Ripristina dizionario tastiera per cancellare i dati memorizzati nella cache.
  • L'intercettazione del traffico di rete può rivelare se una tastiera personalizzata sta trasmettendo i tasti premuti in remoto.

Prevenzione della memorizzazione nella cache dei campi di testo

Il protocollo UITextInputTraits offre proprietà per gestire l'autocorrezione e l'inserimento di testo sicuro, essenziali per prevenire la memorizzazione nella cache di informazioni sensibili. Ad esempio, è possibile disabilitare l'autocorrezione e abilitare l'inserimento di testo sicuro con:

textObject.autocorrectionType = UITextAutocorrectionTypeNo;
textObject.secureTextEntry = YES;

Inoltre, gli sviluppatori dovrebbero assicurarsi che i campi di testo, specialmente quelli per l'inserimento di informazioni sensibili come password e PIN, disabilitino la memorizzazione nella cache impostando autocorrectionType su UITextAutocorrectionTypeNo e secureTextEntry su YES.

UITextField *textField = [[UITextField alloc] initWithFrame:frame];
textField.autocorrectionType = UITextAutocorrectionTypeNo;

Log

Il debug del codice spesso comporta l'uso del logging. C'è un rischio in quanto i log possono contenere informazioni sensibili. In precedenza, in iOS 6 e nelle versioni precedenti, i log erano accessibili a tutte le app, creando un rischio di divulgazione di dati sensibili. Ora, le applicazioni sono limitate ad accedere solo ai propri log.

Nonostante queste restrizioni, un attaccante con accesso fisico a un dispositivo sbloccato può ancora sfruttarlo collegando il dispositivo a un computer e leggendo i log. È importante notare che i log rimangono sul disco anche dopo la disinstallazione dell'app.

Per mitigare i rischi, si consiglia di interagire approfonditamente con l'app, esplorando tutte le sue funzionalità e input per assicurarsi che non vengano registrate informazioni sensibili per errore.

Nel momento in cui si esamina il codice sorgente dell'app per possibili falle, cercare sia dichiarazioni di logging predefinite che personalizzate utilizzando parole chiave come NSLog, NSAssert, NSCAssert, fprintf per le funzioni integrate e qualsiasi menzione di Logging o Logfile per implementazioni personalizzate.

Monitoraggio dei log di sistema

Le app registrano varie informazioni che possono essere sensibili. Per monitorare questi log, sono disponibili strumenti e comandi come:

idevice_id --list   # To find the device ID
idevicesyslog -u <id> (| grep <app>)   # To capture the device logs

sono utili. Inoltre, Xcode fornisce un modo per raccogliere i log della console:

  1. Apri Xcode.
  2. Collega il dispositivo iOS.
  3. Vai su Finestra -> Dispositivi e simulatori.
  4. Seleziona il tuo dispositivo.
  5. Provoca il problema che stai investigando.
  6. Utilizza il pulsante Apri Console per visualizzare i log in una nuova finestra.

Per una registrazione più avanzata, la connessione alla shell del dispositivo e l'utilizzo di socat possono fornire un monitoraggio dei log in tempo reale:

iPhone:~ root# socat - UNIX-CONNECT:/var/run/lockdown/syslog.sock

Seguito dai comandi per osservare le attività di log, che possono essere preziosi per diagnosticare problemi o identificare potenziali perdite di dati nei log.



Utilizza Trickest per creare e automatizzare facilmente flussi di lavoro con gli strumenti della community più avanzati al mondo.
Ottieni l'accesso oggi stesso:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}

Backup

Le funzionalità di backup automatico sono integrate in iOS, facilitando la creazione di copie dei dati del dispositivo tramite iTunes (fino a macOS Catalina), Finder (da macOS Catalina in poi) o iCloud. Questi backup includono quasi tutti i dati del dispositivo, escludendo elementi altamente sensibili come i dettagli di Apple Pay e le configurazioni di Touch ID.

Rischi per la sicurezza

L'inclusione delle app installate e dei loro dati nei backup solleva il problema di potenziali perdite di dati e del rischio che le modifiche al backup possano alterare la funzionalità dell'app. Si consiglia di non memorizzare informazioni sensibili in chiaro all'interno della directory di un'app o delle sue sottodirectory per mitigare questi rischi.

Escludere file dai backup

I file in Documents/ e Library/Application Support/ vengono di default inclusi nei backup. Gli sviluppatori possono escludere file o directory specifiche dai backup utilizzando NSURL setResourceValue:forKey:error: con NSURLIsExcludedFromBackupKey. Questa pratica è fondamentale per proteggere i dati sensibili dall'inclusione nei backup.

Testare le vulnerabilità

Per valutare la sicurezza del backup di un'app, inizia creando un backup utilizzando Finder, quindi individualo seguendo le indicazioni della documentazione ufficiale di Apple. Analizza il backup per individuare dati sensibili o configurazioni che potrebbero essere modificate per influenzare il comportamento dell'app.

Le informazioni sensibili possono essere cercate utilizzando strumenti da linea di comando o applicazioni come iMazing. Per i backup criptati, la presenza di crittografia può essere confermata verificando la chiave "IsEncrypted" nel file "Manifest.plist" nella radice del backup.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
...
<key>Date</key>
<date>2021-03-12T17:43:33Z</date>
<key>IsEncrypted</key>
<true/>
...
</plist>

Per gestire i backup crittografati, gli script Python disponibili nel repository GitHub di DinoSec, come backup_tool.py e backup_passwd.py, possono essere utili, anche se potrebbero richiedere modifiche per essere compatibili con le ultime versioni di iTunes/Finder. Un'altra opzione per accedere ai file all'interno dei backup protetti da password è lo strumento iOSbackup.

Modificare il comportamento dell'app

Un esempio di modifica del comportamento dell'app attraverso modifiche al backup è dimostrato nell'app del portafoglio bitcoin Bither, dove il PIN di blocco dell'interfaccia utente è memorizzato in net.bither.plist sotto la chiave pin_code. Rimuovendo questa chiave dal plist e ripristinando il backup, viene eliminata l'esigenza del PIN, fornendo accesso illimitato.

Riassunto sul testing della memoria per dati sensibili

Quando si tratta di informazioni sensibili memorizzate nella memoria di un'applicazione, è fondamentale limitare il tempo di esposizione di questi dati. Ci sono due approcci principali per investigare il contenuto della memoria: creare un dump della memoria e analizzare la memoria in tempo reale. Entrambi i metodi presentano delle sfide, tra cui la possibilità di perdere dati critici durante il processo di dump o di analisi.

Recupero e analisi di un dump della memoria

Sia per dispositivi jailbroken che non jailbroken, strumenti come objection e Fridump consentono di effettuare il dump della memoria di un'applicazione. Una volta effettuato il dump, l'analisi di questi dati richiede vari strumenti, a seconda della natura delle informazioni che si sta cercando.

Per estrarre stringhe da un dump della memoria, possono essere utilizzati comandi come strings o rabin2 -zz:

# Extracting strings using strings command
$ strings memory > strings.txt

# Extracting strings using rabin2
$ rabin2 -ZZ memory > strings.txt

Per un'analisi più dettagliata, inclusa la ricerca di tipi di dati o pattern specifici, radare2 offre ampie capacità di ricerca:

$ r2 <name_of_your_dump_file>
[0x00000000]> /?
...

Analisi della memoria in tempo di esecuzione

r2frida fornisce un'alternativa potente per ispezionare la memoria di un'app in tempo reale, senza la necessità di un dump di memoria. Questo strumento consente l'esecuzione di comandi di ricerca direttamente sulla memoria dell'applicazione in esecuzione:

$ r2 frida://usb//<name_of_your_app>
[0x00000000]> /\ <search_command>

Crittografia difettosa

Processi di gestione delle chiavi scadenti

Alcuni sviluppatori salvano dati sensibili nella memoria locale e li crittografano con una chiave codificata/predicibile nel codice. Questo non dovrebbe essere fatto poiché un'operazione di reversing potrebbe consentire agli attaccanti di estrarre le informazioni confidenziali.

Utilizzo di algoritmi insicuri e/o deprecati

Gli sviluppatori non dovrebbero utilizzare algoritmi deprecati per eseguire controlli di autorizzazione, memorizzare o inviare dati. Alcuni di questi algoritmi sono: RC4, MD4, MD5, SHA1... Se ad esempio vengono utilizzati hash per memorizzare le password, dovrebbero essere utilizzati hash resistenti all'attacco di forza bruta con salt.

Controllo

I principali controlli da effettuare consistono nel verificare se è possibile trovare password/segreti codificati nel codice, o se questi sono prevedibili, e se il codice utilizza qualche tipo di algoritmo di crittografia debole.

È interessante sapere che è possibile monitorare automaticamente alcune librerie crittografiche utilizzando objection con:

ios monitor crypt

Per ulteriori informazioni sulle API e le librerie crittografiche di iOS, accedere a https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06e-testing-cryptography

Autenticazione locale

L'autenticazione locale svolge un ruolo cruciale, specialmente quando si tratta di proteggere l'accesso a un endpoint remoto attraverso metodi crittografici. L'essenza qui è che senza una corretta implementazione, i meccanismi di autenticazione locale possono essere elusi.

Il framework Local Authentication di Apple e il keychain forniscono API robuste per gli sviluppatori al fine di facilitare i dialoghi di autenticazione dell'utente e gestire in modo sicuro i dati segreti, rispettivamente. Il Secure Enclave protegge l'ID dell'impronta digitale per il Touch ID, mentre il Face ID si basa sul riconoscimento facciale senza compromettere i dati biometrici.

Per integrare il Touch ID/Face ID, gli sviluppatori hanno due scelte di API:

  • LocalAuthentication.framework per l'autenticazione dell'utente a livello elevato senza accesso ai dati biometrici.
  • Security.framework per l'accesso ai servizi del keychain a livello inferiore, proteggendo i dati segreti con l'autenticazione biometrica. Diversi wrapper open-source semplificano l'accesso al keychain.

{% hint style="danger" %} Tuttavia, sia LocalAuthentication.framework che Security.framework presentano vulnerabilità, poiché restituiscono principalmente valori booleani senza trasmettere dati per i processi di autenticazione, rendendoli suscettibili all'elusione (fare riferimento a Don't touch me that way, di David Lindner et al). {% endhint %}

Implementazione dell'autenticazione locale

Per richiedere l'autenticazione agli utenti, gli sviluppatori dovrebbero utilizzare il metodo evaluatePolicy all'interno della classe LAContext, scegliendo tra:

  • deviceOwnerAuthentication: Richiede il Touch ID o il codice di accesso del dispositivo, fallendo se nessuno dei due è abilitato.
  • deviceOwnerAuthenticationWithBiometrics: Richiede esclusivamente il Touch ID.

Un'autenticazione riuscita è indicata da un valore booleano restituito da evaluatePolicy, evidenziando una potenziale falla di sicurezza.

Autenticazione locale utilizzando il keychain

L'implementazione dell'autenticazione locale nelle app iOS coinvolge l'uso delle API del keychain per memorizzare in modo sicuro dati segreti come i token di autenticazione. Questo processo garantisce che i dati possano essere accessibili solo dall'utente, utilizzando il codice di accesso del dispositivo o l'autenticazione biometrica come il Touch ID.

Il keychain offre la possibilità di impostare elementi con l'attributo SecAccessControl, che limita l'accesso all'elemento fino a quando l'utente non si autentica con successo tramite il Touch ID o il codice di accesso del dispositivo. Questa funzionalità è cruciale per migliorare la sicurezza.

Di seguito sono riportati esempi di codice in Swift e Objective-C che mostrano come salvare e recuperare una stringa dal keychain, sfruttando queste funzionalità di sicurezza. Gli esempi mostrano specificamente come configurare il controllo di accesso per richiedere l'autenticazione del Touch ID e garantire che i dati siano accessibili solo sul dispositivo su cui sono stati impostati, a condizione che sia configurato un codice di accesso del dispositivo.

{% tabs %} {% tab title="Swift" %}

// From https://github.com/mufambisi/owasp-mstg/blob/master/Document/0x06f-Testing-Local-Authentication.md

// 1. create AccessControl object that will represent authentication settings

var error: Unmanaged<CFError>?

guard let accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
SecAccessControlCreateFlags.biometryCurrentSet,
&error) else {
// failed to create AccessControl object

return
}

// 2. define keychain services query. Pay attention that kSecAttrAccessControl is mutually exclusive with kSecAttrAccessible attribute

var query: [String: Any] = [:]

query[kSecClass as String] = kSecClassGenericPassword
query[kSecAttrLabel as String] = "com.me.myapp.password" as CFString
query[kSecAttrAccount as String] = "OWASP Account" as CFString
query[kSecValueData as String] = "test_strong_password".data(using: .utf8)! as CFData
query[kSecAttrAccessControl as String] = accessControl

// 3. save item

let status = SecItemAdd(query as CFDictionary, nil)

if status == noErr {
// successfully saved
} else {
// error while saving
}

{% endtab %}

{% tab title="Objective-C" %}

// 1. create AccessControl object that will represent authentication settings
CFErrorRef *err = nil;

SecAccessControlRef sacRef = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
kSecAccessControlUserPresence,
err);

// 2. define keychain services query. Pay attention that kSecAttrAccessControl is mutually exclusive with kSecAttrAccessible attribute
NSDictionary* query = @{
(_ _bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecAttrLabel: @"com.me.myapp.password",
(__bridge id)kSecAttrAccount: @"OWASP Account",
(__bridge id)kSecValueData: [@"test_strong_password" dataUsingEncoding:NSUTF8StringEncoding],
(__bridge id)kSecAttrAccessControl: (__bridge_transfer id)sacRef
};

// 3. save item
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, nil);

if (status == noErr) {
// successfully saved
} else {
// error while saving
}

{% endtab %} {% endtabs %}

Ora possiamo richiedere l'elemento salvato dalla keychain. I servizi della keychain presenteranno una finestra di autenticazione all'utente e restituiranno i dati o nil a seconda che sia stata fornita o meno un'impronta digitale valida.

{% tabs %} {% tab title="Swift" %}

// 1. define query
var query = [String: Any]()
query[kSecClass as String] = kSecClassGenericPassword
query[kSecReturnData as String] = kCFBooleanTrue
query[kSecAttrAccount as String] = "My Name" as CFString
query[kSecAttrLabel as String] = "com.me.myapp.password" as CFString
query[kSecUseOperationPrompt as String] = "Please, pass authorisation to enter this area" as CFString

// 2. get item
var queryResult: AnyObject?
let status = withUnsafeMutablePointer(to: &queryResult) {
SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
}

if status == noErr {
let password = String(data: queryResult as! Data, encoding: .utf8)!
// successfully received password
} else {
// authorization not passed
}

{% endtab %}

{% tab title="Objective-C" %}

// 1. define query
NSDictionary *query = @{(__bridge id)kSecClass: (__bridge id)kSecClassGenericPassword,
(__bridge id)kSecReturnData: @YES,
(__bridge id)kSecAttrAccount: @"My Name1",
(__bridge id)kSecAttrLabel: @"com.me.myapp.password",
(__bridge id)kSecUseOperationPrompt: @"Please, pass authorisation to enter this area" };

// 2. get item
CFTypeRef queryResult = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &queryResult);

if (status == noErr){
NSData* resultData = ( __bridge_transfer NSData* )queryResult;
NSString* password = [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
NSLog(@"%@", password);
} else {
NSLog(@"Something went wrong");
}

{% endtab %} {% endtabs %}

Rilevamento

L'utilizzo di framework in un'app può essere rilevato anche analizzando l'elenco delle librerie dinamiche condivise del file binario dell'app. Ciò può essere fatto utilizzando otool:

$ otool -L <AppName>.app/<AppName>

Se LocalAuthentication.framework viene utilizzato in un'app, l'output conterrà entrambe le seguenti righe (ricorda che LocalAuthentication.framework utilizza Security.framework internamente):

/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication
/System/Library/Frameworks/Security.framework/Security

Se viene utilizzato Security.framework, verrà mostrato solo il secondo.

Bypass del framework di autenticazione locale

Objection

Attraverso il Bypass biometrico di Objection, disponibile in questa pagina di GitHub, è possibile utilizzare una tecnica per superare il meccanismo di LocalAuthentication. Il cuore di questo approccio consiste nell'utilizzare Frida per manipolare la funzione evaluatePolicy, garantendo che restituisca sempre un risultato True, indipendentemente dal successo effettivo dell'autenticazione. Questo è particolarmente utile per aggirare processi di autenticazione biometrica difettosi.

Per attivare questo bypass, viene utilizzato il seguente comando:

...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # ios ui biometrics_bypass
(agent) Registering job 3mhtws9x47q. Type: ios-biometrics-disable
...itudehacks.DVIAswiftv2.develop on (iPhone: 13.2.3) [usb] # (agent) [3mhtws9x47q] Localized Reason for auth requirement: Please authenticate yourself
(agent) [3mhtws9x47q] OS authentication response: false
(agent) [3mhtws9x47q] Marking OS response as True instead
(agent) [3mhtws9x47q] Biometrics bypass hook complete

Questo comando avvia una sequenza in cui Objection registra un'attività che modifica efficacemente l'esito del controllo evaluatePolicy in True.

Frida

Un esempio di utilizzo di evaluatePolicy dall'applicazione DVIA-v2:

+(void)authenticateWithTouchID {
LAContext *myContext = [[LAContext alloc] init];
NSError *authError = nil;
NSString *myLocalizedReasonString = @"Please authenticate yourself";

if ([myContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError]) {
[myContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:myLocalizedReasonString
reply:^(BOOL success, NSError *error) {
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
[TouchIDAuthentication showAlert:@"Authentication Successful" withTitle:@"Success"];
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[TouchIDAuthentication showAlert:@"Authentication Failed !" withTitle:@"Error"];
});
}
}];
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[TouchIDAuthentication showAlert:@"Your device doesn't support Touch ID or you haven't configured Touch ID authentication on your device" withTitle:@"Error"];
});
}
}

Per ottenere il bypass dell'Autenticazione Locale, viene scritto uno script Frida. Questo script mira al controllo evaluatePolicy, intercettando il suo callback per assicurarsi che restituisca success=1. Modificando il comportamento del callback, il controllo di autenticazione viene bypassato in modo efficace.

Lo script di seguito viene iniettato per modificare il risultato del metodo evaluatePolicy. Cambia il risultato del callback in modo che indichi sempre il successo.

// from https://securitycafe.ro/2022/09/05/mobile-pentesting-101-bypassing-biometric-authentication/
if(ObjC.available) {
console.log("Injecting...");
var hook = ObjC.classes.LAContext["- evaluatePolicy:localizedReason:reply:"];
Interceptor.attach(hook.implementation, {
onEnter: function(args) {
var block = new ObjC.Block(args[4]);
const callback = block.implementation;
block.implementation = function (error, value)  {

console.log("Changing the result value to true")
const result = callback(1, null);
return result;
};
},
});
} else {
console.log("Objective-C Runtime is not available!");
}

Per iniettare lo script di Frida e bypassare l'autenticazione biometrica, viene utilizzato il seguente comando:

frida -U -f com.highaltitudehacks.DVIAswiftv2 --no-pause -l fingerprint-bypass-ios.js

Esposizione di funzionalità sensibili tramite IPC

{% content-ref url="ios-custom-uri-handlers-deeplinks-custom-schemes.md" %} ios-custom-uri-handlers-deeplinks-custom-schemes.md {% endcontent-ref %}

Collegamenti universali

{% content-ref url="ios-universal-links.md" %} ios-universal-links.md {% endcontent-ref %}

Condivisione di UIActivity

{% content-ref url="ios-uiactivity-sharing.md" %} ios-uiactivity-sharing.md {% endcontent-ref %}

UIPasteboard

{% content-ref url="ios-uipasteboard.md" %} ios-uipasteboard.md {% endcontent-ref %}

Estensioni dell'app

{% content-ref url="ios-app-extensions.md" %} ios-app-extensions.md {% endcontent-ref %}

WebViews

{% content-ref url="ios-webviews.md" %} ios-webviews.md {% endcontent-ref %}

Serializzazione e codifica

{% content-ref url="ios-serialisation-and-encoding.md" %} ios-serialisation-and-encoding.md {% endcontent-ref %}

Comunicazione di rete

È importante verificare che non avvenga alcuna comunicazione senza crittografia e che l'applicazione stia correttamente validando il certificato TLS del server.
Per verificare questi tipi di problemi, è possibile utilizzare un proxy come Burp:

{% content-ref url="burp-configuration-for-ios.md" %} burp-configuration-for-ios.md {% endcontent-ref %}

Controllo del nome host

Un problema comune nella convalida del certificato TLS è controllare se il certificato è stato firmato da una CA attendibile, ma non controllare se il nome host del certificato corrisponde al nome host a cui si accede.
Per verificare questo problema utilizzando Burp, dopo aver fidato della CA di Burp nell'iPhone, è possibile creare un nuovo certificato con Burp per un nome host diverso e utilizzarlo. Se l'applicazione funziona ancora, allora c'è una vulnerabilità.

Certificate Pinning

Se un'applicazione utilizza correttamente il pinning SSL, allora l'applicazione funzionerà solo se il certificato è quello previsto. Durante il test di un'applicazione, questo potrebbe essere un problema poiché Burp servirà il proprio certificato.
Per aggirare questa protezione all'interno di un dispositivo jailbroken, è possibile installare l'applicazione SSL Kill Switch o installare Burp Mobile Assistant

È anche possibile utilizzare il comando ios sslpinning disable di objection

Varie

  • In /System/Library è possibile trovare i framework installati nel telefono utilizzati dalle applicazioni di sistema
  • Le applicazioni installate dall'utente dall'App Store si trovano all'interno di /User/Applications
  • E /User/Library contiene i dati salvati dalle applicazioni a livello utente
  • È possibile accedere a /User/Library/Notes/notes.sqlite per leggere le note salvate nell'applicazione.
  • All'interno della cartella di un'applicazione installata (/User/Applications/<APP ID>/) è possibile trovare alcuni file interessanti:
  • iTunesArtwork: L'icona utilizzata dall'app
  • iTunesMetadata.plist: Informazioni dell'app utilizzate nell'App Store
  • /Library/*: Contiene le preferenze e la cache. In /Library/Cache/Snapshots/* è possibile trovare lo snapshot eseguito dall'applicazione prima di inviarla in background.

Hot Patching/Aggiornamenti forzati

Gli sviluppatori possono aggiornare istantaneamente tutte le installazioni della loro app senza doverla inviare nuovamente all'App Store e attendere l'approvazione.
A questo scopo viene solitamente utilizzato JSPatch. Ma ci sono anche altre opzioni come Siren e react-native-appstore-version-checker.
Si tratta di un meccanismo pericoloso che potrebbe essere abusato da SDK di terze parti maligni, pertanto è consigliabile verificare quale metodo viene utilizzato per l'aggiornamento automatico (se presente) e testarlo. È possibile provare a scaricare una versione precedente dell'app a questo scopo.

Terze parti

Una sfida significativa con gli SDK di terze parti è la mancanza di controllo granulare sulle loro funzionalità. Gli sviluppatori si trovano di fronte a una scelta: integrare lo SDK e accettare tutte le sue funzionalità, compresi potenziali problemi di sicurezza e preoccupazioni sulla privacy, oppure rinunciare completamente ai suoi vantaggi. Spesso, gli sviluppatori non sono in grado di correggere le vulnerabilità all'interno di questi SDK. Inoltre, man mano che gli SDK guadagnano fiducia nella comunità, alcuni potrebbero iniziare a contenere malware.

I servizi forniti dagli SDK di terze parti possono includere il tracciamento del comportamento degli utenti, la visualizzazione di annunci o il miglioramento dell'esperienza utente. Tuttavia, ciò comporta un rischio poiché gli sviluppatori potrebbero non essere pienamente consapevoli del codice eseguito da queste librerie, con conseguenti rischi per la privacy e la sicurezza. È fondamentale limitare le informazioni condivise con i servizi di terze parti a ciò che è necessario e assicurarsi che nessun dato sensibile venga esposto.

L'implementazione dei servizi di terze parti di solito avviene in due forme: una libreria autonoma o uno SDK completo. Per proteggere la privacy degli utenti, tutti i dati condivisi con questi servizi dovrebbero essere anonimizzati per evitare la divulgazione di informazioni personali identificabili (PII).

Per identificare le librerie utilizzate da un'applicazione, è possibile utilizzare il comando otool. Questo strumento deve essere eseguito sull'applicazione e su ogni libreria condivisa utilizzata per scoprire librerie aggiuntive.

otool -L <application_path>

Riferimenti e Risorse Aggiuntive


Utilizza Trickest per creare e automatizzare facilmente flussi di lavoro con gli strumenti della comunità più avanzati al mondo.
Ottieni l'accesso oggi stesso:

{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}

Impara l'hacking di AWS da zero a esperto con htARTE (HackTricks AWS Red Team Expert)!

Altri modi per supportare HackTricks: