Apps iOS sur Mac ARM : Opportunités de pentesting

Article de blog 20 juillet 2021 par Jim Aspers, spécialiste de la sécurité chez Bureau Veritas Cybersecurity.

Lorsqu'ils inspectent les applications iOS à la recherche de vulnérabilités de sécurité, les testeurs de pénétration s'appuient généralement sur l'arrivée d'appareils jailbreakés. Pour les applications avec détection de jailbreak, cette exigence peut entraîner des retards d'exécution, car le contournement de la détection de jailbreak peut être une tâche compliquée.


Bien qu'il existe des méthodes permettant d'injecter des outils d'évaluation de la sécurité dans l'application cible sur un appareil non jailbreaké (voir par exemple frida-agent), cela prend généralement beaucoup de temps et les possibilités sont limitées. La disponibilité d'une plateforme étendue et confortable pour effectuer des security testing, qui ne sera pas signalée par les applications comme étant jailbreakées, serait très bénéfique.

Adobe Stock 252554510 1

MacOS peut jouer le rôle d'une telle plateforme. Le système d'exploitation contient de nombreuses fonctions natives puissantes qui sont utiles pour la rétro-ingénierie, telles que dtrace et ses dérivés (par exemple dtruss, opensnoop). En outre, le trafic Wi-Fi et Bluetooth peut être trivialement intercepté localement sur le système (par exemple en utilisant Wireshark ou un proxy tel que Burp Suite), au lieu d'avoir à mettre en place un dispositif man-in-the-middle externe.

Peu après l'arrivée des ordinateurs Mac équipés de processeurs ARM, Apple a annoncé la possibilité d'exécuter des applications iOS sur le système d'exploitation macOS. Afin d'explorer les possibilités offertes par cette fonctionnalité pour le pentesting, tout en gérant les restrictions d'Apple, nous avons cherché un moyen d'exécuter des applications iOS arbitraires sur des machines macOS.


Bien qu'il soit possible d'installer des applications iOS, Apple maintient un contrôle strict sur ce qui peut être installé et ce qui ne peut pas l'être, dans le but de fournir la même protection contre le piratage/DRM que celle offerte par la plateforme iOS. À cette fin, Apple encourage ses utilisateurs à installer les applications iOS via l'App Store de macOS. De plus, lors d'une installation manuelle à partir d'un paquet .ipa, seuls les paquets d'installation signés peuvent être installés. Après que la communauté a découvert la possibilité de "sideloader" des applications achetées à l'aide du même identifiant Apple que celui avec lequel la machine macOS était enregistrée, Apple a ajouté une autre restriction qui signifie que seules les applications approuvées pour fonctionner sur macOS pourront être installées (voir, par exemple, ce rapport).

Bien qu'elle soit loin d'être "propre", nous espérons que la méthode démontrée pourra être utilisée par les pentesters d'applications à leur avantage.

Accelerated mobile pages amp improve seo

Décryptage de l'application cible

Les fichiers binaires des applications iOS sont chiffrés à l'aide de la DRM FairPlay d'Apple, ce qui les rend inutilisables pour quiconque, à l'exception du détenteur de l'identifiant Apple de l'acheteur de l'application. En plus d'être un mécanisme efficace de lutte contre le piratage, ce cryptage implique ce qui suit :

  • L'application ne peut pas être transférée sur un appareil qui n'est pas couplé au même identifiant Apple ;
  • L'application ne peut pas être analysée statiquement dans un désassembleur à des fins de rétro-ingénierie ;
  • L'application ne peut pas être modifiée sur le disque pour l'application de correctifs.

Pour cette raison, les tests de sécurité et surtout la rétro-ingénierie sont généralement effectués sur une application iOS non chiffrée.

Le processus d'obtention d'une version non chiffrée de tous les binaires de l'application, y compris les bibliothèques et les frameworks, peut être réalisé de la manière la plus pratique en utilisant frida-ios-dump (voir AloneMonkey/frida-ios-dump). Cet outil basé sur Frida utilise le fait que pour exécuter un binaire crypté, un appareil iOS doit décrypter le binaire en mémoire dans un format exécutable. L'outil trouve et vidange les images binaires décryptées de la mémoire d'un appareil jailbreaké juste après le lancement de l'application cible, et crée une archive d'installation .ipa pour l'app contenant des binaires non cryptés.

Adobe Stock 219049287

Pour les besoins de la démonstration, l'application "Intelligent Hub" développée par VMware a été téléchargée à partir de l'App Store iOS sur un appareil jailbreaké. Cette application n'est pas disponible à l'installation via l'App Store de macOS, et contient de nombreuses bibliothèques et frameworks. Elle constitue donc une cible parfaite pour notre expérience. Dans la suite de cet article, cette application sera utilisée comme le sujet que nous aimerions exécuter sur un système macOS, et sera désignée sous le nom d'"application cible".

Pour déverser une archive .ipa pour l'application cible contenant les binaires déchiffrés, la commande suivante est exécutée alors que l'appareil iOS jailbreaké est connecté par USB :

I OS apps pic 18

Maintenant, si nous essayons d'installer l'archive résultante directement via l'iOS Application Installer.app de macOS (qui se trouve dans /System/Library/CoreServices/Applications/), nous rencontrons une erreur :

I OS apps pic 1

En regardant les journaux dans Console.app, nous voyons que la signature de l'archive n'est pas acceptée

I OS apps pic 2

C'est un comportement attendu, car l'IPA n'a pas été résigné pour avoir contenu les binaires maintenant décryptés. Nous pourrions résigner l'IPA, mais ce processus peut devenir rapidement fastidieux, en particulier lorsque plusieurs frameworks sont inclus ou lorsque l'application cible nécessite des droits exotiques. Des outils tels que AltSignpeuvent être utilisés à cette fin, mais comme nous aimerions pouvoir installer des paquets d'applications arbitraires (modifiés) à tout moment pour des tests de sécurité, nous cherchons une méthode pour contourner la validation de la signature sur l'application installée.

Apprendre par l'exemple

En inspectant la sortie dans Console.app lors de l'installation d'applications iOS officiellement marquées comme compatibles avec macOS depuis l'App Store, nous constatons que le processus d'installation ne se limite pas à la mise en place des fichiers du pack d'installation. Pour étudier le processus d'installation, nous avons utilisé l'application "Aangifte 2020" développée par le Belastingdienst. Cette application était disponible en tant qu'application iOS sur les App Stores iOS et macOS. Tout au long de cet article, nous ferons référence à cette application en tant qu'"application du donneur".

La première observation est qu'une structure de dossier "wrapper" spéciale est créée dans /Applications :

I OS apps pic 3

Le dossier maa.iOS.app s'est avéré contenir une structure de dossier typique de bundle d'application iOS.

D'autres observations montrent que le programme d'installation ne se contente pas de créer cette enveloppe pour l'application iOS proprement dite. L'examen des journaux système et de l'activité des fichiers montre que de nombreux composants du système d'exploitation sont impliqués dans ce processus apparemment complexe, qui comprend des enregistrements associés aux détails du paquet dans une base de données système.

Au lieu de poursuivre l'ingénierie inverse du processus d'installation, nous explorons la possibilité d'utiliser l'enveloppe de l'application valide pour héberger notre application cible.

Jouer le parasite

Pour revenir à l'archive décryptée de l'application VMware Intelligent Hub, le contenu de l'archive peut être extrait de manière triviale :

I OS apps pic 4

Nous pouvons remplacer le contenu du bundle de l'application donatrice par le contenu extrait du bundle de l'application cible :

I OS apps pic 5

Cela ne fonctionnera pas du jour au lendemain. Tous les binaires macOS et iOS (y compris les bibliothèques et frameworks liés dynamiquement) doivent être signés numériquement. Pour créer une signature valide, seuls les certificats émis par Apple peuvent être utilisés. La modification d'un binaire implique donc une nouvelle signature du code modifié. Ces signatures sont intégrées dans le binaire lui-même. Pour les bibliothèques, frameworks et autres ressources importantes à l'intérieur d'un paquet d'applications (par exemple Info.plist), les signatures sont stockées dans un fichier dédié (_CodeSignature/CodeResources) en plus. De cette manière, le système d'exploitation peut garantir l'intégrité du code exécuté. Pour plus de détails, consultez la documentation d'Apple destinée aux développeurs.

Adobe Stock 225084966

Pour cette raison, le simple fait d'écraser le contenu du bundle d'applications de notre wrapper valide avec celui de Hub.app ne fonctionnera pas : les signatures de code pour les binaires à l'intérieur du bundle extrait ne sont pas valides . Comme nous avons copié le contenu modifié du bundle d'applications dans le wrapper de l'application donatrice, nous devrons ajouter une signature de code aux fichiers concernés. Cependant, nous ne voulons pas générer manuellement le profil de provisionnement requis comprenant tous les droits requis pour chaque application testée ; cela impliquerait un travail manuel important dans le portail des développeurs d'Apple. En outre, cela nécessiterait de modifier les droits des binaires pour les faire correspondre à notre identité de codage. En effet, si nous adoptions cette approche, nous pourrions tout aussi bien resigner l'archive d'installation décryptée dans son intégralité. Pour contourner tout cela, nous utilisons ici ce que l'on appelle la "signature ad-hoc". Extrait de man codesign(1) :

I OS apps pic 6

Lorsque vous utilisez une signature ad hoc au lieu d'une signature régulière avec une identité de signature de code appropriée, les signatures de code des binaires ne contiennent qu'un hachage du binaire signé respectif. Ce hachage sera vérifié par le noyau dans le cache de confiance statique du système d'exploitation avant l'exécution. Le cache de confiance contient les hachages des binaires connus du système Apple, et ne peut être modifié à l'exécution sans exploiter une grave faille de sécurité dans la configuration par défaut de macOS.

En gardant cela à l'esprit, nous commençons par signer de manière ad-hoc notre bundle modifié :

I OS apps pic 7

Comme nous nous y attendions compte tenu de nos connaissances en matière de signature de code, si nous appliquons la signature de code ad hoc et essayons d'exécuter l'application, le chargeur plante l'application au moment du chargement. Juste avant le crash, nous observons l'entrée de journal suivante provenant du noyau :

I OS apps pic 8

Nous constatons que le composant concerné est AppleMobileFileIntegrity, communément appelé AMFI. AMFI s'exécute dans le cadre du noyau (KEXT) et gère la vérification de l'intégrité des fichiers binaires. Le message rencontré indique le code de retour 0xe00002f0.

La recherche du sous-code de retour IOreturn observé dans les sources du noyau XNU révèle que l'origine de cette erreur peut être expliquée :

I OS apps pic 9

Le noyau a renvoyé un résultat kIOReturnNotFound lorsqu'on lui a demandé de rechercher le hash de notre binaire dans le trust store. Cela est logique, car nous savons que le trust cache est une structure de données précompilée et codée en dur qui ne contient que les hashs des binaires approuvés par Apple. L'ajout de nos hashs au trust store dépasse le cadre de cet article, et nous utiliserons à la place un contournement trivial.

À des fins de test, contrairement à iOS, macOS permet à l'utilisateur de désactiver (partiellement) l'AMFI. Si nous désactivons AMFI, l'absence du hachage de notre binaire signé ad-hoc dans le cache de confiance ne sera plus un problème bloquant. La désactivation de l'AMFI peut se faire en passant un argument de démarrage particulièrement intéressant au noyau macOS. L'argument peut être ajouté à partir d'un système vivant comme suit, pour être effectif après le redémarrage :

I OS apps pic 10

Notez que pour pouvoir modifier les arguments de démarrage, la protection de l'intégrité du système (SIP) doit être désactivée sur les versions récentes de macOS.

Après avoir ajouté les arguments de démarrage et redémarré la machine, le paquet d'applications signées ad-hoc n'est plus bloqué et peut être lancé comme une application normale via Finder.app.

REMARQUE : la désactivation de l'AMFI, et surtout de SIP, désactive le cœur du modèle de sécurité du système d'exploitation macOS. SIP ne devrait JAMAIS être désactivé sur un système de production sans avoir soigneusement pris en compte les risques de sécurité encourus !

Il est important de noter que pour que cette méthode fonctionne, l'application donatrice que nous utilisons pour servir de wrapper valide pour notre application cible ne doit jamais être lancée avant que son contenu ne soit écrasé. Ceci est lié au fait que lors du premier lancement, macOS stocke apparemment une référence de l'identifiant du bundle de l'application iOS en relation avec le bundle wrapper lui-même. Cela signifie que si nous voulons déplacer une autre application cible à l'intérieur du wrapper, nous devons soit conserver le même identifiant de bundle, soit simplement désinstaller et réinstaller l'application donneuse à partir de l'App Store. Il est possible de modifier le contenu de l'ensemble d'applications iOS enveloppées sans restrictions, à condition que l'identifiant de l'ensemble reste inchangé et que l'ensemble soit (ad-hoc) re-signé après modification.

Au travail !

Grâce à notre petit hack, nous pouvons maintenant exécuter avec succès notre application cible, le VMware Intelligent Hub, sur notre système macOS :

I OS apps pic 11

Particulièrement intéressant pour un pentester, l'inspection des magasins de données de l'application devient confortable :

I OS apps pic 15

Nous pouvons modifier l'application elle-même avec un minimum de restrictions (en gardant à l'esprit la re-signature requise). Cela permet d'appliquer des correctifs en un rien de temps. Un exemple de modification du nom d'affichage de l'application :

I OS apps pic 13

En conséquence, le nom d'affichage de l'application (et donc le titre de la fenêtre) a changé après le redémarrage de l'application :

I OS apps pic 14

Comme l'application iOS s'exécute dans l'environnement natif de macOS, elle est traitée presque de la même manière que les applications macOS ordinaires. Cela signifie que le trafic réseau peut être surveillé et intercepté à l'aide d'outils courants tels que Wireshark, Burp Suite ou Charles. En outre, les outils de traçage et de débogage natifs de macOS peuvent être utilisés, tels que lldb et les outils similaires à dtrace :

I OS apps pic 16

Attacher un environnement de débogage Xcode complet devient également trivial, offrant une expérience considérablement améliorée par rapport à l'utilisation de simples outils de jailbreak :

I OS apps pic 17
Mobile 06

Et maintenant ?

Avons-nous réussi ? En partie. Nous pouvons désormais exécuter des applications iOS arbitraires sur nos systèmes macOS. Cependant, pour en revenir à l'énoncé du problème posé dans l'introduction, plusieurs applications qui utilisent la détection de jailbreak signalent toujours notre système comme étant jailbreaké. Des recherches supplémentaires seraient nécessaires pour savoir si cette approche est adaptée à la résolution de ce problème.

En outre, nous n'avons pas réussi à installer une application iOS arbitraire. Nous nous sommes contentés de "parasiter" une application donatrice. L'ingénierie inverse de la manière dont macOS gère l'apparition d'applications iOS en interne et l'application de cette méthode pour atteindre notre objectif feront l'objet d'un article ultérieur (voir https://github.com/srepsa/launchr pour un aperçu). Restez à l'écoute !