# iOS Pentesting {{#include ../../banners/hacktricks-training.md}} ## iOS Basics {{#ref}} ios-basics.md {{#endref}} ## Testing Environment Dans cette page, vous pouvez trouver des informations sur le **simulateur iOS**, les **émulateurs** et le **jailbreaking** : {{#ref}} ios-testing-environment.md {{#endref}} ## Initial Analysis ### Basic iOS Testing Operations Lors des tests, **plusieurs opérations vont être suggérées** (se connecter à l'appareil, lire/écrire/télécharger/téléverser des fichiers, utiliser certains outils...). Par conséquent, si vous ne savez pas comment effectuer l'une de ces actions, veuillez **commencer à lire la page** : {{#ref}} basic-ios-testing-operations.md {{#endref}} > [!NOTE] > Pour les étapes suivantes, **l'application doit être installée** sur l'appareil et doit déjà avoir obtenu le **fichier IPA** de l'application.\ > Lisez la page [Basic iOS Testing Operations](basic-ios-testing-operations.md) pour apprendre comment faire cela. ### Basic Static Analysis Quelques décompilateurs intéressants pour les fichiers iOS - IPA : - https://github.com/LaurieWired/Malimite - https://ghidra-sre.org/ Il est recommandé d'utiliser l'outil [**MobSF**](https://github.com/MobSF/Mobile-Security-Framework-MobSF) pour effectuer une analyse statique automatique du fichier IPA. Identification des **protections présentes dans le binaire** : - **PIE (Position Independent Executable)** : Lorsqu'il est activé, l'application se charge à une adresse mémoire aléatoire à chaque lancement, rendant plus difficile la prédiction de son adresse mémoire initiale. ```bash otool -hv | grep PIE # Il devrait inclure le drapeau PIE ``` - **Stack Canaries** : Pour valider l'intégrité de la pile, une valeur de ‘canari’ est placée sur la pile avant d'appeler une fonction et est validée à nouveau une fois la fonction terminée. ```bash otool -I -v | grep stack_chk # Il devrait inclure les symboles : stack_chk_guard et stack_chk_fail ``` - **ARC (Automatic Reference Counting)** : Pour prévenir les défauts courants de corruption de mémoire ```bash otool -I -v | grep objc_release # Il devrait inclure le symbole _objc_release ``` - **Encrypted Binary** : Le binaire doit être chiffré ```bash otool -arch all -Vl | grep -A5 LC_ENCRYPT # Le cryptid devrait être 1 ``` **Identification des Fonctions Sensibles/Insecure** - **Algorithmes de Hachage Faibles** ```bash # Sur l'appareil iOS otool -Iv | grep -w "_CC_MD5" otool -Iv | grep -w "_CC_SHA1" # Sur linux grep -iER "_CC_MD5" grep -iER "_CC_SHA1" ``` - **Fonctions Aléatoires Insecure** ```bash # Sur l'appareil iOS otool -Iv | grep -w "_random" otool -Iv | grep -w "_srand" otool -Iv | grep -w "_rand" # Sur linux grep -iER "_random" grep -iER "_srand" grep -iER "_rand" ``` - **Fonction ‘Malloc’ Insecure** ```bash # Sur l'appareil iOS otool -Iv | grep -w "_malloc" # Sur linux grep -iER "_malloc" ``` - **Fonctions Insecure et Vulnérables** ```bash # Sur l'appareil iOS otool -Iv | grep -w "_gets" otool -Iv | grep -w "_memcpy" otool -Iv | grep -w "_strncpy" otool -Iv | grep -w "_strlen" otool -Iv | grep -w "_vsnprintf" otool -Iv | grep -w "_sscanf" otool -Iv | grep -w "_strtok" otool -Iv | grep -w "_alloca" otool -Iv | grep -w "_sprintf" otool -Iv | grep -w "_printf" otool -Iv | grep -w "_vsprintf" # Sur 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" ``` ### Basic Dynamic Analysis Consultez l'analyse dynamique que [**MobSF**](https://github.com/MobSF/Mobile-Security-Framework-MobSF) effectue. Vous devrez naviguer à travers les différentes vues et interagir avec elles, mais cela va accrocher plusieurs classes en faisant d'autres choses et préparera un rapport une fois que vous aurez terminé. ### Listing Installed Apps Utilisez la commande `frida-ps -Uai` pour déterminer le **bundle identifier** des applications installées : ```bash $ 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 ``` ### Énumération de base et Hooking Apprenez à **énumérer les composants de l'application** et comment **hooker facilement des méthodes et des classes** avec objection : {{#ref}} ios-hooking-with-objection.md {{#endref}} ### Structure IPA La structure d'un **fichier IPA** est essentiellement celle d'un **package compressé**. En renommant son extension en `.zip`, il peut être **décompressé** pour révéler son contenu. Dans cette structure, un **Bundle** représente une application entièrement empaquetée prête à être installée. À l'intérieur, vous trouverez un répertoire nommé `.app`, qui encapsule les ressources de l'application. - **`Info.plist`** : Ce fichier contient des détails de configuration spécifiques de l'application. - **`_CodeSignature/`** : Ce répertoire inclut un fichier plist qui contient une signature, garantissant l'intégrité de tous les fichiers dans le bundle. - **`Assets.car`** : Une archive compressée qui stocke des fichiers d'actifs comme des icônes. - **`Frameworks/`** : Ce dossier abrite les bibliothèques natives de l'application, qui peuvent être sous forme de fichiers `.dylib` ou `.framework`. - **`PlugIns/`** : Cela peut inclure des extensions à l'application, connues sous le nom de fichiers `.appex`, bien qu'elles ne soient pas toujours présentes. \* [**`Core Data`**](https://developer.apple.com/documentation/coredata) : Il est utilisé pour sauvegarder les données permanentes de votre application pour une utilisation hors ligne, pour mettre en cache des données temporaires et pour ajouter une fonctionnalité d'annulation à votre application sur un seul appareil. Pour synchroniser des données sur plusieurs appareils dans un seul compte iCloud, Core Data reflète automatiquement votre schéma dans un conteneur CloudKit. - [**`PkgInfo`**](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPRuntimeConfig/Articles/ConfigApplications.html) : Le fichier `PkgInfo` est un moyen alternatif de spécifier les codes de type et de créateur de votre application ou bundle. - **en.lproj, fr.proj, Base.lproj** : Sont les packs de langue qui contiennent des ressources pour ces langues spécifiques, et une ressource par défaut au cas où une langue ne serait pas supportée. - **Sécurité** : Le répertoire `_CodeSignature/` joue un rôle critique dans la sécurité de l'application en vérifiant l'intégrité de tous les fichiers empaquetés grâce à des signatures numériques. - **Gestion des actifs** : Le fichier `Assets.car` utilise la compression pour gérer efficacement les actifs graphiques, crucial pour optimiser les performances de l'application et réduire sa taille globale. - **Frameworks et PlugIns** : Ces répertoires soulignent la modularité des applications iOS, permettant aux développeurs d'inclure des bibliothèques de code réutilisables (`Frameworks/`) et d'étendre la fonctionnalité de l'application (`PlugIns/`). - **Localisation** : La structure prend en charge plusieurs langues, facilitant la portée mondiale de l'application en incluant des ressources pour des packs de langue spécifiques. **Info.plist** Le **Info.plist** sert de pierre angulaire pour les applications iOS, encapsulant des données de configuration clés sous forme de **paires clé-valeur**. Ce fichier est requis non seulement pour les applications mais aussi pour les extensions d'application et les frameworks empaquetés. Il est structuré en format XML ou binaire et contient des informations critiques allant des autorisations d'application aux configurations de sécurité. Pour une exploration détaillée des clés disponibles, on peut se référer à la [**Documentation des développeurs Apple**](https://developer.apple.com/documentation/bundleresources/information_property_list?language=objc). Pour ceux qui souhaitent travailler avec ce fichier dans un format plus accessible, la conversion XML peut être réalisée facilement grâce à l'utilisation de `plutil` sur macOS (disponible nativement sur les versions 10.2 et ultérieures) ou `plistutil` sur Linux. Les commandes pour la conversion sont les suivantes : - **Pour macOS** : ```bash $ plutil -convert xml1 Info.plist ``` - **Pour Linux**: ```bash $ apt install libplist-utils $ plistutil -i Info.plist -o Info_xml.plist ``` Parmi la myriade d'informations que le fichier **Info.plist** peut divulguer, les entrées notables incluent les chaînes de permission d'application (`UsageDescription`), les schémas d'URL personnalisés (`CFBundleURLTypes`), et les configurations pour la sécurité du transport d'application (`NSAppTransportSecurity`). Ces entrées, ainsi que d'autres comme les types de documents personnalisés exportés/importés (`UTExportedTypeDeclarations` / `UTImportedTypeDeclarations`), peuvent être facilement localisées en inspectant le fichier ou en utilisant une simple commande `grep` : ```bash $ grep -i Info.plist ``` **Chemins de données** Dans l'environnement iOS, les répertoires sont désignés spécifiquement pour les **applications système** et les **applications installées par l'utilisateur**. Les applications système résident dans le répertoire `/Applications`, tandis que les applications installées par l'utilisateur sont placées sous `/var/mobile/containers/Data/Application/`. Ces applications se voient attribuer un identifiant unique connu sous le nom de **UUID 128 bits**, rendant la tâche de localiser manuellement le dossier d'une application difficile en raison de l'aléatoire des noms de répertoires. > [!WARNING] > Comme les applications iOS doivent être isolées, chaque application aura également un dossier à l'intérieur de **`$HOME/Library/Containers`** avec le **`CFBundleIdentifier`** de l'application comme nom de dossier. > > Cependant, les deux dossiers (dossiers de données et de conteneurs) contiennent le fichier **`.com.apple.mobile_container_manager.metadata.plist`** qui relie les deux fichiers dans la clé `MCMetadataIdentifier`). Pour faciliter la découverte du répertoire d'installation d'une application installée par l'utilisateur, l'**outil objection** fournit une commande utile, `env`. Cette commande révèle des informations détaillées sur le répertoire de l'application en question. Voici un exemple de la façon d'utiliser cette commande : ```bash 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 ``` Alternativement, le nom de l'application peut être recherché dans le `/private/var/containers` en utilisant la commande `find` : ```bash find /private/var/containers -name "Progname*" ``` Des commandes telles que `ps` et `lsof` peuvent également être utilisées pour identifier le processus de l'application et lister les fichiers ouverts, respectivement, fournissant des informations sur les chemins de répertoire actifs de l'application : ```bash ps -ef | grep -i lsof -p | grep -i "/containers" | head -n 1 ``` **Répertoire du bundle :** - **AppName.app** - C'est le bundle de l'application comme vu précédemment dans l'IPA, il contient des données essentielles de l'application, du contenu statique ainsi que le binaire compilé de l'application. - Ce répertoire est visible par les utilisateurs, mais **les utilisateurs ne peuvent pas y écrire**. - Le contenu de ce répertoire **n'est pas sauvegardé**. - Les contenus de ce dossier sont utilisés pour **valider la signature du code**. **Répertoire des données :** - **Documents/** - Contient toutes les données générées par l'utilisateur. L'utilisateur final de l'application initie la création de ces données. - Visible par les utilisateurs et **les utilisateurs peuvent y écrire**. - Le contenu de ce répertoire est **sauvegardé**. - L'application peut désactiver des chemins en définissant `NSURLIsExcludedFromBackupKey`. - **Library/** - Contient tous les **fichiers qui ne sont pas spécifiques à l'utilisateur**, tels que **caches**, **préférences**, **cookies**, et fichiers de configuration de liste de propriétés (plist). - Les applications iOS utilisent généralement les sous-répertoires `Application Support` et `Caches`, mais l'application peut créer des sous-répertoires personnalisés. - **Library/Caches/** - Contient des **fichiers mis en cache semi-persistants.** - Invisible pour les utilisateurs et **les utilisateurs ne peuvent pas y écrire**. - Le contenu de ce répertoire **n'est pas sauvegardé**. - Le système d'exploitation peut supprimer automatiquement les fichiers de ce répertoire lorsque l'application n'est pas en cours d'exécution et que l'espace de stockage est faible. - **Library/Application Support/** - Contient des **fichiers persistants** nécessaires au fonctionnement de l'application. - **Invisible** **pour** **les utilisateurs** et les utilisateurs ne peuvent pas y écrire. - Le contenu de ce répertoire est **sauvegardé**. - L'application peut désactiver des chemins en définissant `NSURLIsExcludedFromBackupKey`. - **Library/Preferences/** - Utilisé pour stocker des propriétés qui peuvent **persister même après le redémarrage d'une application**. - Les informations sont sauvegardées, non chiffrées, à l'intérieur du sandbox de l'application dans un fichier plist appelé \[BUNDLE_ID].plist. - Tous les paires clé/valeur stockées en utilisant `NSUserDefaults` peuvent être trouvées dans ce fichier. - **tmp/** - Utilisez ce répertoire pour écrire des **fichiers temporaires** qui n'ont pas besoin de persister entre les lancements de l'application. - Contient des fichiers mis en cache non persistants. - **Invisible** pour les utilisateurs. - Le contenu de ce répertoire n'est pas sauvegardé. - Le système d'exploitation peut supprimer automatiquement les fichiers de ce répertoire lorsque l'application n'est pas en cours d'exécution et que l'espace de stockage est faible. Examinons de plus près le répertoire du bundle de l'application iGoat-Swift (.app) à l'intérieur du répertoire du bundle (`/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/iGoat-Swift.app`) : ```bash 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 ``` ### Reversing Binaire À l'intérieur du dossier `.app`, vous trouverez un fichier binaire appelé ``. C'est le fichier qui sera **exécuté**. Vous pouvez effectuer une inspection de base du binaire avec l'outil **`otool`** : ```bash 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) [...] ``` **Vérifiez si l'application est chiffrée** Vérifiez s'il y a une sortie pour : ```bash otool -l | grep -A 4 LC_ENCRYPTION_INFO ``` **Désassembler le binaire** Désassemblez la section texte : ```bash 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 ``` Pour imprimer le **segment Objective-C** de l'application d'exemple, on peut utiliser : ```bash 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 ``` Pour obtenir un code Objective-C plus compact, vous pouvez utiliser [**class-dump**](http://stevenygard.com/projects/class-dump/): ```bash 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; }; ``` Cependant, les meilleures options pour désassembler le binaire sont : [**Hopper**](https://www.hopperapp.com/download.html?) et [**IDA**](https://www.hex-rays.com/products/ida/support/download_freeware/). ## Stockage des données Pour en savoir plus sur la façon dont iOS stocke les données sur l'appareil, lisez cette page : {{#ref}} ios-basics.md {{#endref}} > [!WARNING] > Les endroits suivants pour stocker des informations doivent être vérifiés **juste après l'installation de l'application**, **après avoir vérifié toutes les fonctionnalités** de l'application et même après **s'être déconnecté d'un utilisateur et s'être connecté à un autre**.\ > L'objectif est de trouver **des informations sensibles non protégées** de l'application (mots de passe, jetons), de l'utilisateur actuel et des utilisateurs précédemment connectés. ### Plist Les fichiers **plist** sont des fichiers XML structurés qui **contiennent des paires clé-valeur**. C'est un moyen de stocker des données persistantes, donc parfois vous pouvez trouver **des informations sensibles dans ces fichiers**. Il est recommandé de vérifier ces fichiers après l'installation de l'application et après les avoir utilisés intensivement pour voir si de nouvelles données sont écrites. La façon la plus courante de persister des données dans des fichiers plist est par l'utilisation de **NSUserDefaults**. Ce fichier plist est enregistré à l'intérieur du bac à sable de l'application dans **`Library/Preferences/.plist`** La classe [`NSUserDefaults`](https://developer.apple.com/documentation/foundation/nsuserdefaults) fournit une interface programmatique pour interagir avec le système par défaut. Le système par défaut permet à une application de personnaliser son comportement en fonction des **préférences de l'utilisateur**. Les données enregistrées par `NSUserDefaults` peuvent être consultées dans le bundle de l'application. Cette classe stocke **des données** dans un **fichier plist**, mais elle est destinée à être utilisée avec de petites quantités de données. Ces données ne peuvent plus être accessibles directement via un ordinateur de confiance, mais peuvent être accessibles en effectuant une **sauvegarde**. Vous pouvez **dumper** les informations enregistrées en utilisant **`NSUserDefaults`** avec `objection's ios nsuserdefaults get` Pour trouver tous les plist utilisés par l'application, vous pouvez accéder à `/private/var/mobile/Containers/Data/Application/{APPID}` et exécuter : ```bash find ./ -name "*.plist" ``` Pour convertir des fichiers au format **XML ou binaire (bplist)** en XML, plusieurs méthodes selon votre système d'exploitation sont disponibles : **Pour les utilisateurs de macOS :** Utilisez la commande `plutil`. C'est un outil intégré dans macOS (10.2+), conçu à cet effet : ```bash $ plutil -convert xml1 Info.plist ``` **Pour les utilisateurs de Linux :** Installez d'abord `libplist-utils`, puis utilisez `plistutil` pour convertir votre fichier : ```bash $ apt install libplist-utils $ plistutil -i Info.plist -o Info_xml.plist ``` **Dans une session Objection :** Pour analyser des applications mobiles, une commande spécifique vous permet de convertir des fichiers plist directement : ```bash ios plist cat /private/var/mobile/Containers/Data/Application//Library/Preferences/com.some.package.app.plist ``` ### Core Data [`Core Data`](https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/nsfetchedresultscontroller.html#//apple_ref/doc/uid/TP40001075-CH8-SW1) est un framework pour gérer la couche modèle des objets dans votre application. [Core Data peut utiliser SQLite comme son magasin persistant](https://cocoacasts.com/what-is-the-difference-between-core-data-and-sqlite/), mais le framework lui-même n'est pas une base de données.\ CoreData ne chiffre pas ses données par défaut. Cependant, une couche de chiffrement supplémentaire peut être ajoutée à CoreData. Voir le [GitHub Repo](https://github.com/project-imas/encrypted-core-data) pour plus de détails. Vous pouvez trouver les informations SQLite Core Data d'une application dans le chemin `/private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support` **Si vous pouvez ouvrir le SQLite et accéder à des informations sensibles, alors vous avez trouvé une mauvaise configuration.** ```objectivec:Code from 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"); } } ``` ### YapDatabase [YapDatabase](https://github.com/yapstudios/YapDatabase) est un magasin clé/valeur construit sur SQLite.\ Comme les bases de données Yap sont des bases de données sqlite, vous pouvez les trouver en utilisant la commande proposée dans la section précédente. ### Autres bases de données SQLite Il est courant que les applications créent leur propre base de données sqlite. Elles peuvent **stocker** des **données** **sensibles** et les laisser non chiffrées. Par conséquent, il est toujours intéressant de vérifier chaque base de données dans le répertoire des applications. Allez donc dans le répertoire de l'application où les données sont enregistrées (`/private/var/mobile/Containers/Data/Application/{APPID}`) ```bash find ./ -name "*.sqlite" -or -name "*.db" ``` ### Firebase Real-Time Databases Les développeurs peuvent **stocker et synchroniser des données** dans une **base de données NoSQL hébergée dans le cloud** grâce à Firebase Real-Time Databases. Stockées au format JSON, les données sont synchronisées avec tous les clients connectés en temps réel. Vous pouvez trouver comment vérifier les bases de données Firebase mal configurées ici : {{#ref}} ../../network-services-pentesting/pentesting-web/buckets/firebase-database.md {{#endref}} ### Bases de données Realm [Realm Objective-C](https://realm.io/docs/objc/latest/) et [Realm Swift](https://realm.io/docs/swift/latest/) offrent une alternative puissante pour le stockage de données, non fournie par Apple. Par défaut, elles **stockent les données sans chiffrement**, avec un chiffrement disponible via une configuration spécifique. Les bases de données se trouvent à : `/private/var/mobile/Containers/Data/Application/{APPID}`. Pour explorer ces fichiers, on peut utiliser des commandes comme : ```bash 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*" ``` Pour visualiser ces fichiers de base de données, l'outil [**Realm Studio**](https://github.com/realm/realm-studio) est recommandé. Pour implémenter le chiffrement dans une base de données Realm, le code suivant peut être utilisé : ```swift // 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)") } ``` ### Bases de données Couchbase Lite [Couchbase Lite](https://github.com/couchbase/couchbase-lite-ios) est décrit comme un moteur de base de données **léger** et **intégré** qui suit l'approche **orientée document** (NoSQL). Conçu pour être natif à **iOS** et **macOS**, il offre la capacité de synchroniser les données de manière transparente. Pour identifier les bases de données Couchbase potentielles sur un appareil, le répertoire suivant doit être inspecté : ```bash ls /private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support/ ``` ### Cookies iOS stocke les cookies des applications dans le **`Library/Cookies/cookies.binarycookies`** à l'intérieur de chaque dossier d'application. Cependant, les développeurs décident parfois de les enregistrer dans le **keychain** car le **fichier de cookie mentionné peut être accessible dans les sauvegardes**. Pour inspecter le fichier de cookies, vous pouvez utiliser [**ce script python**](https://github.com/mdegrazia/Safari-Binary-Cookie-Parser) ou utiliser **`ios cookies get`** d'objection.\ **Vous pouvez également utiliser objection pour** convertir ces fichiers en format JSON et inspecter les données. ```bash ...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 Par défaut, NSURLSession stocke des données, telles que **les requêtes et réponses HTTP dans la base de données Cache.db**. Cette base de données peut contenir **des données sensibles**, si des tokens, des noms d'utilisateur ou toute autre information sensible ont été mises en cache. Pour trouver les informations mises en cache, ouvrez le répertoire de données de l'application (`/var/mobile/Containers/Data/Application/`) et allez à `/Library/Caches/`. Le **cache WebKit est également stocké dans le fichier Cache.db**. **Objection** peut ouvrir et interagir avec la base de données avec la commande `sqlite connect Cache.db`, car c'est une **base de données SQLite normale**. Il est **recommandé de désactiver la mise en cache de ces données**, car elles peuvent contenir des informations sensibles dans la requête ou la réponse. La liste suivante montre différentes façons d'y parvenir : 1. Il est recommandé de supprimer les réponses mises en cache après la déconnexion. Cela peut être fait avec la méthode fournie par Apple appelée [`removeAllCachedResponses`](https://developer.apple.com/documentation/foundation/urlcache/1417802-removeallcachedresponses). Vous pouvez appeler cette méthode comme suit : `URLCache.shared.removeAllCachedResponses()` Cette méthode supprimera toutes les requêtes et réponses mises en cache du fichier Cache.db. 2. Si vous n'avez pas besoin de profiter des cookies, il serait recommandé d'utiliser simplement la propriété de configuration [.ephemeral](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1410529-ephemeral) de URLSession, qui désactivera la sauvegarde des cookies et des caches. [Documentation Apple](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1410529-ephemeral) : `Un objet de configuration de session éphémère est similaire à une configuration de session par défaut (voir défaut), sauf que l'objet de session correspondant ne stocke pas de caches, de magasins d'identifiants ou de données liées à la session sur le disque. Au lieu de cela, les données liées à la session sont stockées dans la RAM. La seule fois qu'une session éphémère écrit des données sur le disque, c'est lorsque vous lui dites d'écrire le contenu d'une URL dans un fichier.` 3. Le cache peut également être désactivé en définissant la politique de cache sur [.notAllowed](https://developer.apple.com/documentation/foundation/urlcache/storagepolicy/notallowed). Cela désactivera le stockage du cache de toute manière, que ce soit en mémoire ou sur disque. ### Snapshots Chaque fois que vous appuyez sur le bouton d'accueil, iOS **prend un instantané de l'écran actuel** pour pouvoir effectuer la transition vers l'application de manière beaucoup plus fluide. Cependant, si des **données sensibles** sont présentes à l'écran actuel, elles seront **sauvegardées** dans l'**image** (qui **persiste** **à travers** **les redémarrages**). Ce sont les instantanés auxquels vous pouvez également accéder en double-tapant sur l'écran d'accueil pour passer d'une application à l'autre. À moins que l'iPhone ne soit jailbreaké, l'**attaquant** doit avoir **accès** à l'**appareil** **débloqué** pour voir ces captures d'écran. Par défaut, le dernier instantané est stocké dans le bac à sable de l'application dans le dossier `Library/Caches/Snapshots/` ou `Library/SplashBoard/Snapshots` (les ordinateurs de confiance ne peuvent pas accéder au système de fichiers depuis iOS 7.0). Une façon de prévenir ce mauvais comportement est de mettre un écran vide ou de supprimer les données sensibles avant de prendre l'instantané en utilisant la fonction `ApplicationDidEnterBackground()`. La suite est un exemple de méthode de remédiation qui définira une capture d'écran par défaut. Swift: ```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 : ``` @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]; } ``` Cela définit l'image de fond sur `overlayImage.png` chaque fois que l'application est mise en arrière-plan. Cela empêche les fuites de données sensibles car `overlayImage.png` remplacera toujours la vue actuelle. ### Keychain Pour accéder et gérer le trousseau iOS, des outils comme [**Keychain-Dumper**](https://github.com/ptoomey3/Keychain-Dumper) sont disponibles, adaptés aux appareils jailbreakés. De plus, [**Objection**](https://github.com/sensepost/objection) fournit la commande `ios keychain dump` à des fins similaires. #### **Stockage des Identifiants** La classe **NSURLCredential** est idéale pour enregistrer des informations sensibles directement dans le trousseau, contournant ainsi le besoin de NSUserDefaults ou d'autres wrappers. Pour stocker des identifiants après la connexion, le code Swift suivant est utilisé : ```swift NSURLCredential *credential; credential = [NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistencePermanent]; [[NSURLCredentialStorage sharedCredentialStorage] setCredential:credential forProtectionSpace:self.loginProtectionSpace]; ``` Pour extraire ces identifiants stockés, la commande `ios nsurlcredentialstorage dump` d'Objection est utilisée. ## **Claviers personnalisés et cache de clavier** Avec iOS 8.0 et versions ultérieures, les utilisateurs peuvent installer des extensions de clavier personnalisées, qui sont gérables sous **Réglages > Général > Clavier > Claviers**. Bien que ces claviers offrent des fonctionnalités étendues, ils présentent un risque d'enregistrement des frappes et de transmission de données vers des serveurs externes, bien que les utilisateurs soient informés des claviers nécessitant un accès réseau. Les applications peuvent, et doivent, restreindre l'utilisation de claviers personnalisés pour la saisie d'informations sensibles. **Recommandations de sécurité :** - Il est conseillé de désactiver les claviers tiers pour une sécurité accrue. - Soyez conscient des fonctionnalités de correction automatique et de suggestions automatiques du clavier iOS par défaut, qui pourraient stocker des informations sensibles dans des fichiers cache situés dans `Library/Keyboard/{locale}-dynamic-text.dat` ou `/private/var/mobile/Library/Keyboard/dynamic-text.dat`. Ces fichiers cache doivent être régulièrement vérifiés pour des données sensibles. Il est recommandé de réinitialiser le dictionnaire de clavier via **Réglages > Général > Réinitialiser > Réinitialiser le dictionnaire de clavier** pour effacer les données mises en cache. - L'interception du trafic réseau peut révéler si un clavier personnalisé transmet des frappes à distance. ### **Prévention du cache des champs de texte** Le [protocole UITextInputTraits](https://developer.apple.com/reference/uikit/uitextinputtraits) offre des propriétés pour gérer la correction automatique et la saisie de texte sécurisée, essentielles pour prévenir le cache d'informations sensibles. Par exemple, désactiver la correction automatique et activer la saisie de texte sécurisée peut être réalisé avec : ```objectivec textObject.autocorrectionType = UITextAutocorrectionTypeNo; textObject.secureTextEntry = YES; ``` De plus, les développeurs doivent s'assurer que les champs de texte, en particulier ceux pour entrer des informations sensibles comme des mots de passe et des codes PIN, désactivent la mise en cache en définissant `autocorrectionType` sur `UITextAutocorrectionTypeNo` et `secureTextEntry` sur `YES`. ```objectivec UITextField *textField = [[UITextField alloc] initWithFrame:frame]; textField.autocorrectionType = UITextAutocorrectionTypeNo; ``` ## **Logs** Le débogage du code implique souvent l'utilisation de **logging**. Il y a un risque car **les logs peuvent contenir des informations sensibles**. Auparavant, dans iOS 6 et les versions antérieures, les logs étaient accessibles à toutes les applications, posant un risque de fuite de données sensibles. **Maintenant, les applications sont limitées à l'accès uniquement à leurs logs**. Malgré ces restrictions, un **attaquant ayant un accès physique** à un appareil déverrouillé peut toujours en tirer parti en connectant l'appareil à un ordinateur et en **lisant les logs**. Il est important de noter que les logs restent sur le disque même après la désinstallation de l'application. Pour atténuer les risques, il est conseillé de **interagir en profondeur avec l'application**, en explorant toutes ses fonctionnalités et entrées pour s'assurer qu'aucune information sensible n'est enregistrée par inadvertance. Lors de l'examen du code source de l'application à la recherche de fuites potentielles, recherchez à la fois des **déclarations de logging** **prédéfinies** et **personnalisées** en utilisant des mots-clés tels que `NSLog`, `NSAssert`, `NSCAssert`, `fprintf` pour les fonctions intégrées, et toute mention de `Logging` ou `Logfile` pour les implémentations personnalisées. ### **Monitoring System Logs** Les applications enregistrent diverses informations qui peuvent être sensibles. Pour surveiller ces logs, des outils et des commandes comme : ```bash idevice_id --list # To find the device ID idevicesyslog -u (| grep ) # To capture the device logs ``` sont utiles. De plus, **Xcode** offre un moyen de collecter des journaux de console : 1. Ouvrez Xcode. 2. Connectez l'appareil iOS. 3. Accédez à **Fenêtre** -> **Appareils et simulateurs**. 4. Sélectionnez votre appareil. 5. Déclenchez le problème que vous enquêtez. 6. Utilisez le bouton **Ouvrir la console** pour voir les journaux dans une nouvelle fenêtre. Pour un journalisation plus avancée, se connecter au shell de l'appareil et utiliser **socat** peut fournir une surveillance des journaux en temps réel : ```bash iPhone:~ root# socat - UNIX-CONNECT:/var/run/lockdown/syslog.sock ``` Suivi des commandes pour observer les activités de journal, ce qui peut être inestimable pour diagnostiquer des problèmes ou identifier des fuites potentielles de données dans les journaux. ## Sauvegardes Les **fonctionnalités de sauvegarde automatique** sont intégrées dans iOS, facilitant la création de copies de données de l'appareil via iTunes (jusqu'à macOS Catalina), Finder (à partir de macOS Catalina) ou iCloud. Ces sauvegardes englobent presque toutes les données de l'appareil, à l'exception des éléments hautement sensibles comme les détails d'Apple Pay et les configurations de Touch ID. ### Risques de sécurité L'inclusion des **applications installées et de leurs données** dans les sauvegardes soulève la question de la **fuite de données** potentielle et du risque que **les modifications de sauvegarde puissent altérer la fonctionnalité de l'application**. Il est conseillé de **ne pas stocker d'informations sensibles en texte clair** dans le répertoire d'une application ou ses sous-répertoires pour atténuer ces risques. ### Exclusion de fichiers des sauvegardes Les fichiers dans `Documents/` et `Library/Application Support/` sont sauvegardés par défaut. Les développeurs peuvent exclure des fichiers ou des répertoires spécifiques des sauvegardes en utilisant `NSURL setResourceValue:forKey:error:` avec le `NSURLIsExcludedFromBackupKey`. Cette pratique est cruciale pour protéger les données sensibles d'être incluses dans les sauvegardes. ### Test des vulnérabilités Pour évaluer la sécurité de la sauvegarde d'une application, commencez par **créer une sauvegarde** en utilisant Finder, puis localisez-la en suivant les conseils de [la documentation officielle d'Apple](https://support.apple.com/en-us/HT204215). Analysez la sauvegarde à la recherche de données sensibles ou de configurations qui pourraient être modifiées pour affecter le comportement de l'application. Des informations sensibles peuvent être recherchées à l'aide d'outils en ligne de commande ou d'applications comme [iMazing](https://imazing.com). Pour les sauvegardes chiffrées, la présence de chiffrement peut être confirmée en vérifiant la clé "IsEncrypted" dans le fichier "Manifest.plist" à la racine de la sauvegarde. ```xml ... Date 2021-03-12T17:43:33Z IsEncrypted ... ``` Pour traiter les sauvegardes chiffrées, des scripts Python disponibles dans le [répertoire GitHub de DinoSec](https://github.com/dinosec/iphone-dataprotection/tree/master/python_scripts), comme **backup_tool.py** et **backup_passwd.py**, peuvent être utiles, bien qu'ils nécessitent potentiellement des ajustements pour être compatibles avec les dernières versions d'iTunes/Finder. L'outil [**iOSbackup**](https://pypi.org/project/iOSbackup/) est une autre option pour accéder aux fichiers dans des sauvegardes protégées par mot de passe. ### Modification du Comportement de l'Application Un exemple de modification du comportement d'une application par le biais de modifications de sauvegarde est démontré dans l'[application de portefeuille bitcoin Bither](https://github.com/bither/bither-ios), où le code PIN de verrouillage de l'interface utilisateur est stocké dans `net.bither.plist` sous la clé **pin_code**. La suppression de cette clé du plist et la restauration de la sauvegarde supprime l'exigence du code PIN, offrant un accès illimité. ## Résumé sur les Tests de Mémoire pour les Données Sensibles Lorsqu'il s'agit d'informations sensibles stockées dans la mémoire d'une application, il est crucial de limiter le temps d'exposition de ces données. Il existe deux approches principales pour enquêter sur le contenu de la mémoire : **créer un dump de mémoire** et **analyser la mémoire en temps réel**. Les deux méthodes présentent des défis, y compris le risque de manquer des données critiques lors du processus de dump ou d'analyse. ## **Récupération et Analyse d'un Dump de Mémoire** Pour les appareils jailbreakés et non jailbreakés, des outils comme [objection](https://github.com/sensepost/objection) et [Fridump](https://github.com/Nightbringer21/fridump) permettent de dumper la mémoire du processus d'une application. Une fois le dump effectué, l'analyse de ces données nécessite divers outils, en fonction de la nature des informations que vous recherchez. Pour extraire des chaînes d'un dump de mémoire, des commandes telles que `strings` ou `rabin2 -zz` peuvent être utilisées : ```bash # Extracting strings using strings command $ strings memory > strings.txt # Extracting strings using rabin2 $ rabin2 -ZZ memory > strings.txt ``` Pour une analyse plus détaillée, y compris la recherche de types de données ou de motifs spécifiques, **radare2** offre des capacités de recherche étendues : ```bash $ r2 [0x00000000]> /? ... ``` ## **Analyse de la mémoire à l'exécution** **r2frida** offre une alternative puissante pour inspecter la mémoire d'une application en temps réel, sans avoir besoin d'un dump mémoire. Cet outil permet l'exécution de commandes de recherche directement sur la mémoire de l'application en cours d'exécution : ```bash $ r2 frida://usb// [0x00000000]> /\ ``` ## Cryptographie Brisée ### Mauvaises Pratiques de Gestion des Clés Certains développeurs enregistrent des données sensibles dans le stockage local et les cryptent avec une clé codée en dur/prévisible dans le code. Cela ne devrait pas être fait car un certain reverse engineering pourrait permettre aux attaquants d'extraire les informations confidentielles. ### Utilisation d'Algorithmes Insecure et/ou Obsolètes Les développeurs ne devraient pas utiliser des **algorithmes obsolètes** pour effectuer des **vérifications** d'autorisation, **stocker** ou **envoyer** des données. Certains de ces algorithmes sont : RC4, MD4, MD5, SHA1... Si des **hashes** sont utilisés pour stocker des mots de passe par exemple, des **hashes** résistants à la force brute devraient être utilisés avec du sel. ### Vérification Les principales vérifications à effectuer consistent à trouver si vous pouvez trouver des mots de passe/secrets **codés en dur** dans le code, ou si ceux-ci sont **prévisibles**, et si le code utilise des algorithmes de **cryptographie** **faibles**. Il est intéressant de savoir que vous pouvez **surveiller** certaines **bibliothèques** **crypto** automatiquement en utilisant **objection** avec : ```swift ios monitor crypt ``` Pour **plus d'informations** sur les API et bibliothèques cryptographiques iOS, accédez à [https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06e-testing-cryptography](https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06e-testing-cryptography) ## Authentification Locale **L'authentification locale** joue un rôle crucial, surtout lorsqu'il s'agit de protéger l'accès à un point de terminaison distant par des méthodes cryptographiques. L'essence ici est que sans une mise en œuvre appropriée, les mécanismes d'authentification locale peuvent être contournés. Le [**framework d'authentification locale d'Apple**](https://developer.apple.com/documentation/localauthentication) et le [**keychain**](https://developer.apple.com/library/content/documentation/Security/Conceptual/keychainServConcepts/01introduction/introduction.html) fournissent des API robustes pour permettre aux développeurs de faciliter les dialogues d'authentification des utilisateurs et de gérer en toute sécurité les données secrètes, respectivement. Le Secure Enclave sécurise l'ID d'empreinte digitale pour Touch ID, tandis que Face ID repose sur la reconnaissance faciale sans compromettre les données biométriques. Pour intégrer Touch ID/Face ID, les développeurs ont deux choix d'API : - **`LocalAuthentication.framework`** pour une authentification utilisateur de haut niveau sans accès aux données biométriques. - **`Security.framework`** pour un accès aux services de keychain de bas niveau, sécurisant les données secrètes avec une authentification biométrique. Divers [wrappers open-source](https://www.raywenderlich.com/147308/secure-ios-user-data-keychain-touch-id) simplifient l'accès au keychain. > [!CAUTION] > Cependant, à la fois `LocalAuthentication.framework` et `Security.framework` présentent des vulnérabilités, car ils retournent principalement des valeurs booléennes sans transmettre de données pour les processus d'authentification, les rendant susceptibles d'être contournés (voir [Don't touch me that way, par David Lindner et al](https://www.youtube.com/watch?v=XhXIHVGCFFM)). ### Mise en œuvre de l'authentification locale Pour demander aux utilisateurs une authentification, les développeurs doivent utiliser la méthode **`evaluatePolicy`** dans la classe **`LAContext`**, en choisissant entre : - **`deviceOwnerAuthentication`** : Demande Touch ID ou code d'accès de l'appareil, échouant si aucun des deux n'est activé. - **`deviceOwnerAuthenticationWithBiometrics`** : Demande exclusivement Touch ID. Une authentification réussie est indiquée par une valeur de retour booléenne de **`evaluatePolicy`**, soulignant une potentielle faille de sécurité. ### Authentification locale utilisant le Keychain La mise en œuvre de **l'authentification locale** dans les applications iOS implique l'utilisation des **API de keychain** pour stocker en toute sécurité des données secrètes telles que des jetons d'authentification. Ce processus garantit que les données ne peuvent être accessibles que par l'utilisateur, en utilisant son code d'accès de l'appareil ou une authentification biométrique comme Touch ID. Le keychain offre la capacité de définir des éléments avec l'attribut `SecAccessControl`, qui restreint l'accès à l'élément jusqu'à ce que l'utilisateur s'authentifie avec succès via Touch ID ou code d'accès de l'appareil. Cette fonctionnalité est cruciale pour améliorer la sécurité. Voici des exemples de code en Swift et Objective-C démontrant comment enregistrer et récupérer une chaîne dans/le keychain, en tirant parti de ces fonctionnalités de sécurité. Les exemples montrent spécifiquement comment configurer le contrôle d'accès pour exiger une authentification Touch ID et garantir que les données ne sont accessibles que sur l'appareil sur lequel elles ont été configurées, sous la condition qu'un code d'accès de l'appareil soit configuré. {{#tabs}} {{#tab name="Swift"}} ```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? 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 name="Objectif-C"}} ```objectivec // 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}} Maintenant, nous pouvons demander l'élément enregistré dans le trousseau. Les services de trousseau présenteront la boîte de dialogue d'authentification à l'utilisateur et renverront des données ou nil en fonction de la fourniture ou non d'une empreinte digitale appropriée. {{#tabs}} {{#tab name="Swift"}} ```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 name="Objective-C"}} ```objectivec // 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}} ### Détection L'utilisation de frameworks dans une application peut également être détectée en analysant la liste des bibliothèques dynamiques partagées du binaire de l'application. Cela peut être fait en utilisant `otool`: ```bash $ otool -L .app/ ``` Si `LocalAuthentication.framework` est utilisé dans une application, la sortie contiendra les deux lignes suivantes (rappelez-vous que `LocalAuthentication.framework` utilise `Security.framework` en arrière-plan) : ```bash /System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication /System/Library/Frameworks/Security.framework/Security ``` Si `Security.framework` est utilisé, seul le second sera affiché. ### Contournement du Cadre d'Authentification Locale #### **Objection** Grâce au **Objection Biometrics Bypass**, situé sur [cette page GitHub](https://github.com/sensepost/objection/wiki/Understanding-the-iOS-Biometrics-Bypass), une technique est disponible pour surmonter le mécanisme **LocalAuthentication**. Le cœur de cette approche consiste à exploiter **Frida** pour manipuler la fonction `evaluatePolicy`, garantissant qu'elle renvoie systématiquement un résultat `True`, indépendamment du succès réel de l'authentification. Cela est particulièrement utile pour contourner les processus d'authentification biométrique défectueux. Pour activer ce contournement, la commande suivante est utilisée : ```bash ...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 ``` Cette commande déclenche une séquence où Objection enregistre une tâche qui modifie effectivement le résultat de la vérification `evaluatePolicy` en `True`. #### Frida Un exemple d'utilisation de **`evaluatePolicy`** de l'application [DVIA-v2](https://github.com/prateek147/DVIA-v2) : ```swift +(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"]; }); } } ``` Pour réaliser le **bypass** de l'authentification locale, un script Frida est écrit. Ce script cible la vérification **evaluatePolicy**, interceptant son rappel pour s'assurer qu'il renvoie **success=1**. En modifiant le comportement du rappel, la vérification d'authentification est effectivement contournée. Le script ci-dessous est injecté pour modifier le résultat de la méthode **evaluatePolicy**. Il change le résultat du rappel pour indiquer toujours un succès. ```swift // 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!"); } ``` Pour injecter le script Frida et contourner l'authentification biométrique, la commande suivante est utilisée : ```bash frida -U -f com.highaltitudehacks.DVIAswiftv2 --no-pause -l fingerprint-bypass-ios.js ``` ## Exposition de Fonctionnalités Sensibles par IPC ### Gestionnaires de URI Personnalisés / Deeplinks / Schémas Personnalisés {{#ref}} ios-custom-uri-handlers-deeplinks-custom-schemes.md {{#endref}} ### Liens Universels {{#ref}} ios-universal-links.md {{#endref}} ### Partage UIActivity {{#ref}} ios-uiactivity-sharing.md {{#endref}} ### UIPasteboard {{#ref}} ios-uipasteboard.md {{#endref}} ### Extensions d'Application {{#ref}} ios-app-extensions.md {{#endref}} ### WebViews {{#ref}} ios-webviews.md {{#endref}} ### Sérialisation et Encodage {{#ref}} ios-serialisation-and-encoding.md {{#endref}} ## Communication Réseau Il est important de vérifier qu'aucune communication ne se produit **sans cryptage** et également que l'application **valide correctement le certificat TLS** du serveur.\ Pour vérifier ce genre de problèmes, vous pouvez utiliser un proxy comme **Burp** : {{#ref}} burp-configuration-for-ios.md {{#endref}} ### Vérification du Nom d'Hôte Un problème courant lors de la validation du certificat TLS est de vérifier que le certificat a été signé par une **CA** **de confiance**, mais **ne pas vérifier** si **le nom d'hôte** du certificat est le nom d'hôte accédé.\ Pour vérifier ce problème en utilisant Burp, après avoir fait confiance à la CA de Burp sur l'iPhone, vous pouvez **créer un nouveau certificat avec Burp pour un nom d'hôte différent** et l'utiliser. Si l'application fonctionne toujours, alors, quelque chose est vulnérable. ### Pinning de Certificat Si une application utilise correctement le SSL Pinning, alors l'application ne fonctionnera que si le certificat est celui attendu. Lors du test d'une application, **cela peut poser un problème car Burp servira son propre certificat.**\ Pour contourner cette protection sur un appareil jailbreaké, vous pouvez installer l'application [**SSL Kill Switch**](https://github.com/nabla-c0d3/ssl-kill-switch2) ou installer [**Burp Mobile Assistant**](https://portswigger.net/burp/documentation/desktop/mobile/config-ios-device) Vous pouvez également utiliser **objection's** `ios sslpinning disable` ## Divers - Dans **`/System/Library`**, vous pouvez trouver les frameworks installés sur le téléphone utilisés par les applications système - Les applications installées par l'utilisateur depuis l'App Store se trouvent dans **`/User/Applications`** - Et le **`/User/Library`** contient les données sauvegardées par les applications au niveau utilisateur - Vous pouvez accéder à **`/User/Library/Notes/notes.sqlite`** pour lire les notes sauvegardées dans l'application. - Dans le dossier d'une application installée (**`/User/Applications//`**), vous pouvez trouver des fichiers intéressants : - **`iTunesArtwork`** : L'icône utilisée par l'application - **`iTunesMetadata.plist`** : Infos de l'application utilisées dans l'App Store - **`/Library/*`** : Contient les préférences et le cache. Dans **`/Library/Cache/Snapshots/*`**, vous pouvez trouver le snapshot effectué sur l'application avant de l'envoyer en arrière-plan. ### Hot Patching/Mise à Jour Forcée Les développeurs peuvent **patcher toutes les installations de leur application instantanément** sans avoir à soumettre à nouveau l'application à l'App Store et attendre son approbation.\ À cette fin, on utilise généralement [**JSPatch**](https://github.com/bang590/JSPatch)**.** Mais il existe d'autres options telles que [Siren](https://github.com/ArtSabintsev/Siren) et [react-native-appstore-version-checker](https://www.npmjs.com/package/react-native-appstore-version-checker).\ **C'est un mécanisme dangereux qui pourrait être abusé par des SDK tiers malveillants, il est donc recommandé de vérifier quelle méthode est utilisée pour la mise à jour automatique (le cas échéant) et de la tester.** Vous pourriez essayer de télécharger une version précédente de l'application à cette fin. ### Tiers Un défi significatif avec les **SDK tiers** est le **manque de contrôle granulaire** sur leurs fonctionnalités. Les développeurs sont confrontés à un choix : soit intégrer le SDK et accepter toutes ses fonctionnalités, y compris les vulnérabilités de sécurité potentielles et les préoccupations en matière de confidentialité, soit renoncer entièrement à ses avantages. Souvent, les développeurs ne peuvent pas corriger les vulnérabilités au sein de ces SDK eux-mêmes. De plus, à mesure que les SDK gagnent la confiance au sein de la communauté, certains peuvent commencer à contenir des logiciels malveillants. Les services fournis par les SDK tiers peuvent inclure le suivi du comportement des utilisateurs, l'affichage de publicités ou l'amélioration de l'expérience utilisateur. Cependant, cela introduit un risque car les développeurs peuvent ne pas être pleinement conscients du code exécuté par ces bibliothèques, ce qui entraîne des risques potentiels pour la confidentialité et la sécurité. Il est crucial de limiter les informations partagées avec les services tiers à ce qui est nécessaire et de s'assurer qu'aucune donnée sensible n'est exposée. L'implémentation de services tiers se présente généralement sous deux formes : une bibliothèque autonome ou un SDK complet. Pour protéger la vie privée des utilisateurs, toute donnée partagée avec ces services doit être **anonymisée** pour éviter la divulgation d'Informations Personnelles Identifiables (PII). Pour identifier les bibliothèques utilisées par une application, la commande **`otool`** peut être employée. Cet outil doit être exécuté contre l'application et chaque bibliothèque partagée qu'elle utilise pour découvrir des bibliothèques supplémentaires. ```bash otool -L ``` ## **Références & Autres Ressources** - [https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06b-basic-security-testing#information-gathering](https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06b-basic-security-testing#information-gathering) - [iOS & Mobile App Pentesting - INE](https://my.ine.com/CyberSecurity/courses/089d060b/ios-mobile-app-pentesting) - [https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0057/](https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0057/) - [https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0058/](https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0058/) - [https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0059/](https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0059/) - [https://mas.owasp.org/MASTG/iOS/0x06d-Testing-Data-Storage](https://mas.owasp.org/MASTG/iOS/0x06d-Testing-Data-Storage) - [https://coderwall.com/p/kjb3lw/storing-password-in-keychain-the-smart-way](https://coderwall.com/p/kjb3lw/storing-password-in-keychain-the-smart-way) - [https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0055/](https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0055/) - [https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0053](https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0053) - [https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0060/](https://mas.owasp.org/MASTG/techniques/ios/MASTG-TECH-0060/) - [https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0058](https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0058) - [https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0060](https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0060) - [https://mas.owasp.org/MASTG/Android/0x05f-Testing-Local-Authentication/](https://mas.owasp.org/MASTG/Android/0x05f-Testing-Local-Authentication/) - [https://mas.owasp.org/MASTG/tests/ios/MASVS-AUTH/MASTG-TEST-0064](https://mas.owasp.org/MASTG/tests/ios/MASVS-AUTH/MASTG-TEST-0064) - [https://medium.com/securing/bypassing-your-apps-biometric-checks-on-ios-c2555c81a2dc](https://medium.com/securing/bypassing-your-apps-biometric-checks-on-ios-c2555c81a2dc) - [https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0054](https://mas.owasp.org/MASTG/tests/ios/MASVS-STORAGE/MASTG-TEST-0054) - [https://github.com/ivRodriguezCA/RE-iOS-Apps/](https://github.com/ivRodriguezCA/RE-iOS-Apps/) cours gratuit IOS([https://syrion.me/blog/ios-swift-antijailbreak-bypass-frida/](https://syrion.me/blog/ios-swift-antijailbreak-bypass-frida/)) - [https://www.sans.org/reading-room/whitepapers/testing/ipwn-apps-pentesting-ios-applications-34577](https://www.sans.org/reading-room/whitepapers/testing/ipwn-apps-pentesting-ios-applications-34577) - [https://www.slideshare.net/RyanISI/ios-appsecurityminicourse](https://www.slideshare.net/RyanISI/ios-appsecurityminicourse) - [https://github.com/prateek147/DVIA](https://github.com/prateek147/DVIA) - [https://github.com/prateek147/DVIA-v2](https://github.com/prateek147/DVIA-v2) - [https://github.com/OWASP/MSTG-Hacking-Playground%20](https://github.com/OWASP/MSTG-Hacking-Playground) - OWASP iGoat [_https://github.com/OWASP/igoat_](https://github.com/OWASP/igoat) <<< version Objective-C [_https://github.com/OWASP/iGoat-Swift_](https://github.com/OWASP/iGoat-Swift) <<< version Swift - [https://github.com/authenticationfailure/WheresMyBrowser.iOS](https://github.com/authenticationfailure/WheresMyBrowser.iOS) - [https://github.com/nabla-c0d3/ssl-kill-switch2](https://github.com/nabla-c0d3/ssl-kill-switch2) {{#include ../../banners/hacktricks-training.md}}