1 points par GN⁺ 2024-03-06 | 1 commentaires | Partager sur WhatsApp
  • 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

 
GN⁺ 2024-03-06
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

    • Cet article était à l’origine un billet interne de Texts.com, et la partie où j’expliquais qu’il y a quelques semaines j’avais essayé exactement la même approche avant d’abandonner à cause de la limite de temps que je m’étais fixée a été retirée lors de l’adaptation pour le partage
      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/

    • C’est une méthode pratique, et d’autres approches comme hooker les fonctions d’envoi/réception TLS avec Frida sont presque certainement possibles. Cela dit, l’avantage d’un contournement du certificate pinning est de permettre aux chercheurs de faire passer le trafic par des outils existants comme Burp Suite ou mitmproxy
      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
    • À noter que cette méthode ne fonctionne pas avec les programmes Rust qui lient statiquement rustls, la bibliothèque TLS Rust la plus utilisée
  • Mé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

    • J’ai tenté la même chose ; j’ai réussi à patcher l’app jusqu’à intercepter les requêtes, mais j’ai abandonné en essayant de rétro-ingénierer l’objet partagé chargé de la signature des requêtes
      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
    • Si l’utilisateur peut modifier le binaire, il est fondamentalement difficile d’imposer le certificate pinning
      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é
    • Exact. Ils auraient pu l’implémenter en faisant en sorte que, dans la fonction consommatrice, seule la sortie de la fonction de flag sandbox soit forcée à true, mais dans ce cas précis, la méthode actuelle fonctionnait très bien :)
    • C’est drôle de voir autant de gens qui ont essayé ça sur des apps mobiles et se sont fait bloquer
      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

    • Les mentions de +Orc ou de Fravia (RIP) me rendent toujours nostalgique
      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...

    • Ça ne fonctionne que sur Android. Nous n’étions pas intéressés par l’interception de l’app Android
  • 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é

    • C’est macOS (desktop), pas iOS (mobile)
    • De toute façon, si l’on modifie le binaire, il faut le resigner, ce qui produit le même effet
      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 production

    • D’après mon expérience quand j’y travaillais, la défense contre la rétro-ingénierie n’a jamais été un objectif
      Le certificate pinning visait à rendre la falsification difficile pour les attaquants, pas à la rendre difficile pour les utilisateurs
    • Les apps Meta incluent carrément des menus de debug dans les builds de production. La chaîne trouvée par l’auteur fait probablement partie de ce type de menu
  • 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

    • Ce n’est pas vraiment un problème d’IA, ça ressemble plutôt à du fuzzing
      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
    • Ce genre d’outil existait déjà dans les années 90. Ce n’était pas de l’IA, juste de la force brute
  • 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.

    • Pour avoir été du côté de ceux qui ont pris cette décision au début sur l’app Facebook, ça n’en vaut pas la peine.
      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.
    • L’obfuscation a un coût, et le pinning de certificat sert davantage à rendre plus difficiles les attaques de type homme du milieu défavorables à l’utilisateur qu’à empêcher le reverse engineering.
      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.
    • Dans les apps mobiles/front-end, cela ne sert pas vraiment à grand-chose.
      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.
    • C’est très probablement une question de priorités et de rapport coût/efficacité.
      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.
    • Pourquoi toutes les banques ne sont-elles pas sécurisées comme Fort Knox ?
  • 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.

    • Bonne question. Celui utilisé dans l’article est Proxyman.
      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.