- L’équipe de Texts.com a voulu analyser Meta Messenger pour macOS, une application de bureau autonome similaire à la sienne, mais l’analyse MITM basée sur un proxy était bloquée à cause du certificate pinning
- Le certificate pinning de Meta fait en sorte que l’application ne fasse confiance qu’aux certificats qu’elle autorise, ce qui empêche d’intercepter et de déchiffrer les requêtes via une autorité de certification créée par l’utilisateur
- L’instrumentation dynamique basée sur Frida provoquait des crashs dans Messenger et compliquait le déploiement, donc l’équipe a choisi un patch binaire plus petit et reproductible
- L’analyse avec Hopper a montré qu’en modifiant 4 octets pour faire renvoyer
true à IsUsingSandbox(), il était possible d’emprunter un chemin de code qui désactive la vérification SSL lors de l’utilisation d’un sandbox personnalisé
- Après remplacement du binaire d’origine par l’exécutable patché et traitement de la signature, il est devenu possible de voir dans l’outil proxy les en-têtes, le corps des réponses et les informations de requête
Pourquoi Texts.com a analysé Messenger
- Batuhan İçöz, en charge du projet de plateforme Meta chez Texts.com, a jugé que l’application Messenger pour macOS méritait une analyse, car elle est proche du modèle d’application de bureau autonome de l’entreprise
- L’interception des requêtes réseau constitue une bonne première étape pour comprendre le fonctionnement d’une application, avec une barrière à l’entrée relativement faible
- Mais Meta a renforcé son modèle de sécurité en appliquant le certificate pinning à l’application, au point d’empêcher même les analyses MITM effectuées par l’utilisateur sur son propre trafic
Ce que bloque le certificate pinning
- Pour intercepter des requêtes avec un client proxy, il faut configurer et approuver une autorité de certification créée par l’utilisateur
- Les certificats émis par cette autorité permettent alors d’intercepter et de déchiffrer les informations des requêtes
- Lorsqu’un service implémente le certificate pinning, l’application n’accepte que les certificats émis par certaines autorités précises
- Dans ce cas, les certificats créés par l’utilisateur ne sont pas valides, et les requêtes ne peuvent donc pas être interceptées
Situation avant le patch et objectif
- Sans désactiver le certificate pinning, toutes les requêtes renvoyaient « Internal Error »
- Le logiciel proxy affichait « SSL Handshake Failed » et le cycle de vie des requêtes n’allait pas jusqu’au bout
- Dans cet état, il était difficile de déduire le contenu des requêtes
- L’objectif était de pouvoir lire directement dans l’outil de débogage réseau les requêtes, réponses et en-têtes
Les tentatives de contournement qui ont échoué et le choix final
- Une méthode qui avait fonctionné par le passé consistait à remplacer, dans le binaire, des chaînes d’URL par un endpoint auto-hébergé ne mettant pas en œuvre TLS
- Cet endpoint relayait les requêtes et les réponses entre le client et le serveur
- Cette approche convient mieux à de petites applications qu’à une grosse application comme Messenger
- Des bibliothèques d’instrumentation dynamique comme Frida ont aussi été envisagées, mais leur stabilité était insuffisante avec Messenger
- Les crashs étaient fréquents au moment d’installer les hooks
- L’overhead rendait difficile l’identification des points problématiques
- L’environnement d’exécution et la configuration des outils compliquaient le partage avec les autres membres de l’équipe
- Un script Frida maintenu depuis plusieurs années a également été testé
- Ce script servait avec des bibliothèques courantes de certificate pinning et des méthodes de contournement classiques, et fonctionnait dans la plupart des applications
- La suite d’applications Meta ne faisait pas partie de cette « plupart »
- L’équipe a finalement opté pour un patch binaire désactivant complètement le certificate pinning, plus facile à transmettre aux collègues
Le point de patch trouvé avec Hopper
- Après avoir téléchargé Messenger et l’avoir déplacé dans le dossier Applications, l’équipe a importé dans Hopper le binaire ARM compilé situé à
/Applications/Messenger.app/Content/MacOS/Messenger
- Hopper permet de désassembler, décompiler, recompiler, déboguer et visualiser des binaires compilés
- Une fois le binaire et ses références chargés, l’équipe a recherché des termes comme
certificate, ssl et pinning
- La chaîne
"SSL pinning verification failed for host:" a servi de point de départ à l’analyse
- Comme un binaire compilé peut planter si on le modifie trop fortement, la stratégie a consisté à appliquer des changements aussi petits que possible
- Les changements idéaux sont des patchs à portée limitée, comme inverser une valeur booléenne, renverser une condition ou modifier quelques instructions
Forcer IsUsingSandbox() à toujours renvoyer true
- Le flux d’exécution a été visualisé à l’aide du graphe de contrôle, puis l’équipe est remontée en suivant les références connectées
- La chaîne
"Using custom sandbox -> turn off SSL verification" a été trouvée
- Les références de la fonction qui décide de ce flag ont été recherchées dans le fichier, puis repérées en haut de la procédure
- Dans la fonction
IsUsingSandbox(), l’équipe a remonté jusqu’au point où la valeur de retour est assignée
- Le registre
w0 est renvoyé après avoir reçu la valeur déplacée depuis w19
w19 était à l’origine assigné via une instruction de chargement d’octet
- En n’effectuant plus le chargement de
w19 et en lui donnant toujours la valeur true, IsUsingSandbox() renvoie true
- D’après la chaîne trouvée plus tôt, la vérification SSL est désactivée en cas d’utilisation d’un sandbox personnalisé, donc ce changement désactive le certificate pinning
Original
ARM: ldrb w19, [sp, #0x40 + var_20]
HEX: F3 83 40 39
Rewritten
ARM: mov w19, #1
HEX: 33 00 80 52
- Ce remplacement a été effectué en modifiant directement les octets de l’application en mode hexadécimal
Résultat d’exécution et re-signature
- Un nouvel exécutable a été exporté avec l’option « Produce New Executable » de Hopper
- Après suppression de la signature de l’exécutable, le binaire Messenger d’origine a été remplacé par le nouveau binaire
- Au redémarrage de Messenger, l’outil proxy affichait les en-têtes, le corps des réponses et d’autres informations de requête
- Sur une taille totale de binaire de 97 477 728 octets, une modification de seulement 4 octets a suffi pour permettre l’interception des requêtes
- Pour voir une approche similaire sur iOS, on peut consulter le billet de 2020 de Hassan Mostafa sur le contournement du certificate pinning d’Instagram
- L’article décrit un cas où le certificate pinning d’Instagram a été désactivé sur un iPhone jailbreaké en inversant une instruction de branchement conditionnel
- Le binaire compilé a ensuite été transmis à Batuhan
- Batuhan a obtenu et installé un certificat de signature, puis a signé l’application
- Il a ensuite pu utiliser ce binaire sur son système pour voir ses propres requêtes
codesign --force --deep -s CERTNAME_OR_ID /Applications/Messenger.app
1 commentaires
Avis sur Hacker News
J’ai suivi un chemin similaire, puis j’ai abandonné au moment où il aurait fallu aller jusqu’à décompiler/modifier/recompiler
À ce niveau, c’est de l’acharnement ; je me demande combien d’heures ça a réellement pris. Moi, j’avais fixé un critère d’arrêt et je m’y suis tenu
Au début, j’ai passé 2 heures à essayer de modifier diverses commandes, puis j’ai abandonné. Ensuite, après avoir vu un article de l’ingénieur en rétro-ingénierie « Hassan Mostafa » (cyclon3), qui avait réussi autrefois avec la même méthode — en appliquant Hopper Disassembler à Instagram sur iOS —, j’ai réessayé le soir même, mais sans succès. J’ai aussi cherché et modifié la même commande
Puis j’ai décidé d’arrêter, et quelques semaines plus tard, avec un léger goût d’inachevé, j’ai réessayé sur un coup de tête : après avoir trouvé la fonction de sandbox, j’ai terminé en une trentaine de minutes
Avec eBPF, il semble possible de lire les données avant le chiffrement TLS : Debugging with eBPF Part 3: Tracing SSL/TLS connections https://blog.px.dev/ebpf-openssl-tracing/
Router le trafic réel de l’app via un proxy d’interception peut faire gagner énormément de temps selon l’objectif. Par exemple, si l’on veut modifier automatiquement un seul paramètre d’une requête qui ne survient qu’après l’authentification et la mise en place de la session, il est bien plus rapide de laisser l’app dérouler tout le processus et de ne changer qu’un point dans le proxy, plutôt que d’écrire un nouveau client qui reproduit toute la phase initiale, ou d’implémenter la logique de modification dans un filtre eBPF
rustls, la bibliothèque TLS Rust la plus utiliséeMéthode très ingénieuse. Cela dit, il me semble qu’ils auraient quand même pu imposer le certificate pinning même en mode sandbox
À l’université, j’avais essayé d’observer Snapchat via une attaque de l’homme du milieu, mais eux aussi utilisaient le certificate pinning, et je n’avais finalement pas réussi à le contourner
Je n’ai même pas réussi à trouver le point d’entrée. Pour une appli de réseau social relativement petite, la sécurité était déjà absurdement forte en 2015
Même s’ils avaient utilisé le certificate pinning en mode sandbox, il y aurait très probablement eu une autre façon de supprimer la vérification du certificat épinglé
Plus maintenant, cela dit
Cet article me rappelle l’époque de +Orc. Beaucoup de connaissances autrefois courantes semblent avoir disparu, comme savoir trouver une branche indésirable et la remplacer par des NOP
En même temps, il y a aujourd’hui bien plus de technologies à apprendre, donc ça se comprend
[1] : https://en.m.wikipedia.org/wiki/Old_Red_Cracker
Cela dit, je pense qu’il y a encore beaucoup de gens qui font du patch NOP. C’est juste que la complexité a augmenté. Les personnes qui cassent des DRM ou qui examinent des apps mobiles quelconques avec un éditeur hexadécimal, entre autres, existent toujours
Les programmes modernes sont plus complexes, donc il est plus difficile de s’y mettre, mais en même temps les connaissances nécessaires sont plus accessibles
Si vous voulez intercepter le trafic des apps Meta, pas besoin d’aller jusque-là
https://www.facebook.com/whitehat/bugbounty-education/261571...
Je me demande si des checksums binaires à l’exécution auraient aidé à rendre ce genre de modification plus difficile
Ce n’est pas une pratique standard sur les apps mobiles ? Les SDK iOS ou Android fournissent-ils ce genre de fonctionnalité ? J’imagine que ce serait lié au processus de release officiel et appliqué sur chaque plateforme non jailbreakée
C’est une question basique, mais comme la solution finale consistait à modifier quelques octets du binaire, ça semblait pouvoir être bloqué
Sur les plateformes non jailbreakées, on fait généralement ça avec un certificat développeur
Les défenses de Meta, du moins celles de Messenger, contre la rétro-ingénierie semblent assez laxistes
Même sans aller jusqu’à de l’obfuscation avancée, il aurait été facile de supprimer complètement
IsUsingSandbox()des builds de productionLe certificate pinning visait à rendre la falsification difficile pour les attaquants, pas à la rendre difficile pour les utilisateurs
La première fois que j’ai cracké une app, je pensais évidemment que ça allait échouer, mais il s’est avéré qu’il était plus facile que prévu de trouver ce genre de point JNE/JEZ simple à modifier
Même si l’on choisit mal, il suffit de revenir au fichier original et d’essayer un autre point
J’ai l’impression que l’IA pourrait facilement automatiser ça. Il suffirait d’inverser JEZ/JNZ à plusieurs points candidats, de lancer l’app, puis de voir si l’écran de reproche apparaît
Si la condition d’échec est bien définie, il suffit au final de réduire les candidats
Si l’IA pouvait casser quelque chose comme Denuvo en zero-shot, ce serait une autre histoire
Je me demande pourquoi l’application d’une entreprise aussi énorme n’est pas complètement obfusquée, et pourquoi elle n’intègre pas non plus suffisamment de protections pour empêcher l’exécution de binaires modifiés.
Une personne, un groupe ou un État suffisamment compétent ou motivé finira toujours par passer au travers. C’est la nature même du fait de distribuer un binaire client.
On peut dépenser énormément de temps et d’argent pour essayer de l’empêcher. À une époque, Pinterest voulait déployer son propre langage et sa propre machine virtuelle, et je m’y étais opposé. Sinon, on peut simplement accepter que le code client soit, par principe, déjà compromis, mettre la logique côté serveur et passer à autre chose.
Le pinning de certificat est presque gratuit, et ressemble à un dispositif du genre « il faut au moins cette clé pour monter à bord ». Ce n’est pas sûr, mais ça filtre les tentatives opportunistes.
Bien sûr, cela a aussi un effet sur le reverse engineering, mais c’est plutôt un bénéfice secondaire.
Au final, le code s’exécute sur l’appareil de l’utilisateur, et l’utilisateur peut observer ce que fait le code ; il est donc toujours possible de le désobfusquer. Dès qu’une personne l’a fait et partage le résultat, la reproduction devient très facile. Cela ne veut pas dire que l’obfuscation ne sert à rien, mais ce n’est pas un sujet dans lequel il faut investir trop de temps.
Si l’attaquant a un accès physique à l’appareil, à ce stade il n’y a aucun moyen de l’empêcher. Tout ce qu’on peut faire, c’est rendre le processus plus pénible en espérant qu’il s’agace et abandonne.
L’obfuscation n’aurait presque rien changé au résultat de cette expérience, et l’approche aurait peut-être simplement basculé vers un usage un peu plus important de l’instrumentation dynamique. La forme d’obfuscation la plus efficace que j’aie vue était l’obfuscation par VM, mais son impact sur les performances est considérable. L’obfuscation rend aussi le débogage normal plus difficile.
La protection contre les binaires modifiés se fait au niveau système, peut aussi être implémentée au niveau applicatif, et elle est assez courante. Mais cette fonctionnalité elle-même peut être contournée, et on peut aussi modifier le programme avec une bibliothèque d’instrumentation dynamique comme Frida après la fin des contrôles de sécurité.
Du point de vue de Meta, se lancer dans un jeu du chat et de la souris avec les spécialistes du reverse engineering ne me semble pas être la meilleure option.
Je me demande quel outil de proxy a été utilisé dans l’article. Lorsqu’il tourne, est-ce qu’il route tout le trafic de toutes les applications vers lui ?
Désolé si c’est une question idiote.
Sur macOS, il route tout le trafic des applications vers lui ; et pour les appareils iOS, on peut aussi les faire passer par le proxy en installant un certificat autosigné sur l’appareil, puis en se connectant au proxy.