Voyager est ma passion et je suis un grand fan de Couchsurfing. Couchsurfing est une communauté mondiale de voyageurs, où vous pouvez trouver un logement ou partager votre propre maison avec d'autres voyageurs. De plus, Couchsurfing vous aide à vivre une expérience de voyage authentique tout en interagissant avec les habitants. Je suis impliqué dans la communauté Couchsurfing depuis plus de 3 ans. J'ai d'abord assisté à des rencontres, puis j'ai finalement pu accueillir des gens. Quel voyage incroyable! J'ai rencontré tellement de personnes incroyables du monde entier et je me suis fait beaucoup d'amis. Toute cette expérience a vraiment changé ma vie.
J'ai hébergé beaucoup de voyageurs moi-même, bien plus que je n’ai encore surfé. En vivant dans l'une des principales destinations touristiques de la Côte d'Azur, j'ai reçu énormément de demandes de canapé (jusqu'à 10 par jour en haute saison). Comme un développeur back-end indépendant , J’ai tout de suite remarqué que le problème avec le site Web couchsurfing.com est qu’il ne gère pas correctement ces cas de «forte charge». Il n'y a aucune information sur la disponibilité de votre canapé - lorsque vous recevez une nouvelle demande de canapé, vous ne pouvez pas être sûr si vous hébergez déjà quelqu'un à ce moment-là. Il devrait y avoir une représentation visuelle de vos demandes acceptées et en attente, afin que vous puissiez mieux les gérer. De plus, si vous pouviez rendre publique la disponibilité de votre canapé, vous pourriez éviter les demandes de canapé inutiles. Pour mieux comprendre ce que j'ai en tête, jetez un œil au calendrier Airbnb.
De nombreuses entreprises sont connues pour ne pas écouter leurs utilisateurs. Connaissant l’histoire du Couchsurfing, je ne pouvais pas compter sur eux pour implémenter cette fonctionnalité de si tôt. Depuis que le site Web est devenu une entreprise à but lucratif, la communauté s'est détériorée. Pour mieux comprendre de quoi je parle, je vous suggère de lire ces deux articles:
Je savais que de nombreux membres de la communauté seraient heureux d'avoir cette fonctionnalité. J'ai donc décidé de créer une application pour résoudre ce problème. Il s'avère qu'aucune API publique de Couchsurfing n'est disponible. Voici la réponse que j'ai reçue de leur équipe d'assistance:
'Malheureusement, nous devons vous informer que notre API n'est pas réellement publique et qu'il n'est pas prévu pour le moment de la rendre publique.'
Il était temps d'utiliser certaines de mes techniques de rétro-ingénierie logicielles préférées pour percer sur Couchsurfing.com. J'ai supposé que leurs applications mobiles devaient utiliser une sorte d'API pour interroger le backend. J'ai donc dû intercepter les requêtes HTTP provenant d'une application mobile vers le backend. Pour cela, j'ai mis en place un proxy dans le réseau local et y ai connecté mon iPhone pour intercepter les requêtes HTTP. De cette façon, j'ai pu trouver les points d'accès de leur API privée et déterminer leur format de charge utile JSON.
Enfin, j'ai créé un site Web qui a pour but d'aider les gens à gérer leurs demandes de canapé et de montrer aux internautes un calendrier de disponibilité de canapé. J'ai publié un lien vers celui-ci sur les forums de la communauté (qui sont également assez segmentés à mon avis, et il est difficile d'y trouver des informations). L'accueil a été globalement positif, même si certaines personnes n'aimaient pas l'idée que le site Web exigeait les informations d'identification de couchsurfing.com, ce qui était vraiment une question de confiance.
Le site Web fonctionnait comme ceci: vous vous connectez au site Web avec vos identifiants couchsurfing.com, et après quelques clics, vous obtenez le code html que vous pouvez intégrer dans votre profil couchsurfing.com, et voilà - vous avez un calendrier mis à jour automatiquement dans votre profil. Ci-dessous la capture d'écran du calendrier et voici les articles sur la façon dont je l'ai fait:
J'ai créé une fonctionnalité intéressante pour Couchsurfing, et j'ai naturellement supposé qu'ils apprécieraient mon travail - peut-être même m'offriraient un poste dans leur équipe de développement. J'ai envoyé un e-mail à emplois (at) couchsurfing.com avec un lien vers le site Web, mon CV et une référence. Un mot de remerciement laissé par l'un de mes invités couchsurfing:
Quelques jours plus tard, ils ont poursuivi mes efforts de rétro-ingénierie. Dans la réponse, il était clair que la seule chose qui les préoccupait était leur propre sécurité, alors ils m'ont demandé de supprimer les articles de blog que j'avais écrits sur l'API, et finalement le site Web. J'ai immédiatement supprimé les messages, car mon intention n'était pas de violer les conditions d'utilisation et de rechercher les informations d'identification des utilisateurs, mais plutôt d'aider la communauté du couchsurfing. J'avais l'impression d'être traité comme un criminel et l'entreprise s'est concentrée uniquement sur le fait que mon site Web nécessite des informations d'identification de l'utilisateur.
J'ai proposé de leur donner mon application gratuitement. Ils pourraient l'héberger sur leur environnement et le connecter via l'authentification Facebook. Après tout, c'est une fonctionnalité intéressante et la communauté en avait besoin. Voici la résolution finale que j'ai reçue:
«Nous reprenons le cours des choses ici après les vacances et nous voulions faire un suivi.
Nous avons eu une discussion interne sur votre application et sur la manière dont nous pourrions à la fois honorer la créativité et l'initiative qu'elle montre sans compromettre potentiellement la confidentialité et la sécurité des données des utilisateurs de Couchsurfing lorsqu'ils saisissent leurs informations d'identification sur un site tiers.
Le calendrier remplit clairement un trou de fonctionnalité sur notre site, une fonctionnalité qui fait partie d'un projet plus vaste sur lequel nous travaillons actuellement.
Mais le problème de la collecte des noms d'utilisateur et des mots de passe demeure. Nous n'avons pas pu trouver un moyen simple de le configurer afin que nous puissions héberger ou prendre en charge cela de notre côté sans vous permettre d'accéder à ces données ou de voir votre site comme notre produit de travail.
L'API actuellement disponible sera bientôt remplacée par une version qui nécessitera une authentification / autorisation des applications qui y accèdent. »
Aujourd'hui, alors que j'écris ce tutoriel sur le logiciel de rétro-ingénierie (un an après les événements), la fonctionnalité de calendrier n'est toujours pas implémentée sur Couchsurfing.
Il y a quelques semaines, j'ai eu l'idée d'écrire un article sur les techniques de rétro-ingénierie des API privées. Naturellement, j’ai décidé de résumer les articles précédents que j’ai écrits sur ce sujet et d’ajouter quelques détails supplémentaires. Au moment où j'ai commencé à écrire le nouvel article, je voulais présenter le processus de rétro-ingénierie avec une API à jour et utiliser un autre talon pour le piratage d'API. Sur la base de mon expérience précédente et du fait que Couchsurfing a récemment annoncé une toute nouvelle application Web et mobile http://blog.couchsurfing.com/the-future-of-couchsurfing-is-on-the-way/ , J'ai décidé de pirater à nouveau leur API.
lequel des éléments suivants ne fait pas partie du plan de conception d'une base de données
Pourquoi est-ce que je fais ce processus d'ingénierie inverse? Eh bien, tout d’abord, il est très amusant de procéder à l’ingénierie inverse des logiciels en général. Ce que j'aime particulièrement à ce sujet, c'est que cela n'implique pas seulement votre compétence technique, mais aussi votre intuition. Parfois, la meilleure façon de comprendre les choses est de faire une supposition éclairée - cela vous fera gagner beaucoup de temps par rapport à la force brute. Récemment, j'ai entendu une histoire d'une entreprise qui devait travailler avec des API propriétaires et peu ou pas de documentation. Ils avaient du mal à déchiffrer la charge utile de la réponse de l'API dans un format inconnu pendant des jours, puis quelqu'un a décidé d'essayer ?decode=true
à la fin de l'url et ils avaient un JSON approprié. Parfois, si vous avez de la chance, tout ce que vous avez à faire est embellir la réponse JSON .
Une autre raison pour laquelle je fais ce didacticiel est que certaines entreprises mettent du temps à adopter une fonctionnalité particulière demandée par leurs utilisateurs. Plutôt que d'attendre sa mise en œuvre, vous pouvez exploiter la puissance de leur API privée et la créer vous-même.
Donc, avec la nouvelle API couchsurfing.com, j'ai commencé avec une approche similaire et j'ai installé leur dernière application iOS.
Tout d'abord, vous devez configurer un proxy dans votre réseau local pour forger des requêtes HTTP provenant de l'application vers l'API en effectuant une attaque de type 'man-in-the-middle' (MITM).
Pour les connexions non chiffrées, l'attaque est assez simple: un client se connecte au proxy et vous relayez les demandes entrantes vers le serveur de destination dans les deux sens. Vous pouvez éventuellement modifier la charge utile, si nécessaire. Dans un réseau WLAN public, il est assez facile de le faire sous un déguisement en se faisant passer pour le routeur WiFi.
Pour les connexions chiffrées, il y a une petite différence: toutes les demandes sont chiffrées de bout en bout. il n’est pas possible pour l’attaquant de déchiffrer le message, à moins d’avoir accès d’une manière ou d’une autre à la clé privée (qui, bien entendu, n’est pas envoyée pendant ces interactions). Cela dit, même si le canal de communication de l'API est sécurisé, les points de terminaison - en particulier le client - ne sont pas aussi sûrs.
Les conditions suivantes doivent être remplies pour que SSL fonctionne correctement:
Pour surmonter le cryptage lors d'une attaque MITM, notre proxy doit agir en tant qu'autorité de certification (CA) et générer des certificats à la volée. Par exemple, si un client tente de se connecter à www.google.com, le proxy crée dynamiquement un certificat pour www.google.com et le signe. Maintenant, le client pense que le proxy est en fait www.google.com
Pour mettre en œuvre un proxy de reniflage utilisé pour procéder à l'ingénierie inverse de l'API privée, j'utiliserai l'outil appelé mitmproxy . Vous pouvez utiliser n'importe quel autre proxy HTTPS transparent. Charles est un autre exemple avec une belle interface graphique. Pour que cela fonctionne, nous devons configurer les éléments suivants:
Configurez la passerelle par défaut de la connexion WiFi de votre téléphone pour qu'elle soit le proxy (afin que le proxy soit au milieu et que tous les paquets passent) Installez le certificat du proxy sur le téléphone (afin que le client ait la clé publique du proxy dans son magasin de confiance)
Consultez la documentation de votre proxy sur l’installation du certificat. Ici sont les instructions pour mitmproxy. Et Ici est le fichier PEM du certificat pour iOS.
Pour surveiller les requêtes HTTP interceptées, il vous suffit de lancer mitmproxy et de vous y connecter depuis votre téléphone mobile (le port par défaut est 8080).
Ouvrez un site Web dans votre navigateur mobile. À ce stade, vous devriez être en mesure de voir le trafic dans mitmproxy.
Une fois que vous vous êtes assuré que tout fonctionne comme prévu, il est temps de commencer à explorer l'API privée de votre choix. Fondamentalement, à ce stade, vous pouvez simplement ouvrir l'application, jouer avec et avoir une idée des points de terminaison de l'API et de la structure de la demande.
Il n'y a pas d'algorithme strict sur la façon de rétro-ingérer une API logicielle - la plupart du temps, vous vous fiez à votre intuition et faites des hypothèses.
Mon approche consiste à répliquer les appels d'API et à jouer avec différentes options. Un bon début est de rejouer une requête que vous avez interceptée dans mitmproxy, et de voir si cela fonctionne (appuyez sur «r» pour rejouer une requête). La première étape consiste à déterminer quels en-têtes sont obligatoires. Il est assez pratique de jouer avec les en-têtes avec mitmproxy: appuyez sur «e» pour passer en mode édition, puis sur «h» pour modifier les en-têtes. Avec les raccourcis qu'ils utilisent, les toxicomanes de vim se sentiraient comme chez eux. Vous pouvez également utiliser des extensions de navigateur comme Postman pour tester l'API, mais elles ont tendance à ajouter des en-têtes inutiles, je suggère donc de s'en tenir à mitmproxy ou curl.
J'ai créé un script qui lit le fichier de vidage mitmproxy et génère une chaîne curl - https://gist.github.com/nderkach/bdb31b04fb1e69fa5346
Commençons par la demande envoyée lorsque vous vous connectez.
POST https://hapi.couchsurfing.com/api/v2/sessions ← 200 application/json
La première chose que j'ai remarquée est que chaque requête contient un en-tête obligatoire X-CS-Url-Signature
qui est différent à chaque fois. J'ai également essayé de rejouer une demande après un certain temps pour vérifier s'il y avait une vérification d'horodatage sur le serveur, et il n'y en a pas. La prochaine chose à faire est de comprendre comment cette signature est calculée.
À ce stade, j'ai décidé de rétroconcevoir le binaire et de comprendre l'algorithme. Naturellement, ayant de l'expérience dans le développement pour iPhone et ayant un iPhone à ma disposition, j'ai décidé de commencer avec l'iPhone ipa (application iPhone livrable). Il s'avère que pour en déchiffrer un, j'ai besoin d'un téléphone jailbreaké. Arrêtez! Temps de marteau.
Ensuite, je me suis souvenu qu'ils avaient également une application Android. J’ai hésité un peu à essayer cette approche, car je ne connais rien à Android ou Java. J'ai alors pensé que ce serait une bonne chance d'apprendre quelque chose de nouveau. Il s'est avéré plus facile d'obtenir un code quasi-source lisible par l'homme en décompilant le bytecode java que le code machine iphone fortement optimisé.
Apk (livrable par application Android) est essentiellement un fichier zip. Vous pouvez utiliser n'importe quel extracteur de zip pour décompresser son contenu. Vous trouverez un fichier appelé classes.dex, qui est un bytecode Dalvik. Dalvik est une machine virtuelle utilisée pour exécuter le bytecode Java traduit sur Android.
Pour décompiler le fichier .dex en code source .java, j'ai utilisé l'outil appelé dex2jar. La sortie de cet outil est un fichier jar, que vous pouvez décompiler avec une variété d'outils. Vous pouvez même ouvrir un pot dans Eclipse ou IntelliJ IDEA et il fera tout le travail pour vous. La plupart de ces outils produisent un résultat similaire. Nous ne nous soucions pas vraiment de savoir si nous pouvons le recompiler pour l'exécuter, nous l'utilisons simplement pour analyser le code source.
Voici une liste d’outils que j’ai essayés:
CFR et FernFlower ont fonctionné le mieux pour moi. JD-GUI était incapable de décompiler certaines parties critiques du code et était inutile, tandis que les autres étaient à peu près de la même qualité. Heureusement, il semble que le code de code Java n’ait pas été obscurci, mais il existe des outils comme ProGuard http://developer.android.com/tools/help/proguard.html pour vous aider à désobfusquer le code.
La décompilation Java n'est pas vraiment la portée de ce didacticiel de rétro-ingénierie - il y a beaucoup d'écrit sur ce sujet, alors supposons que vous avez décompilé et désobfusqué avec succès votre code Java.
J'ai combiné tout le code pertinent utilisé pour calculer X-CS-Url-Signature dans l'essentiel suivant: https://gist.github.com/nderkach/d11540e9af322f1c1c74
Tout d’abord, j’ai recherché des mentions de X-CS-Url-Signature
, que j’ai trouvées dans RetrofitHttpClient
. Un appel particulier semblait intéressant - à EncUtils
module. En creusant dedans, j'ai réalisé qu'ils utilisaient HMAC SHA1. HMAC est un code d'authentification de message qui utilise une fonction cryptographique (SHA1 dans ce cas) pour calculer un hachage d'un message. Il est utilisé pour garantir l'intégrité (c'est-à-dire pour empêcher un homme au milieu de modifier la demande) et l'authentification.
Nous avons besoin de deux choses pour calculer le X-CS-Url-Signature
: la clé privée et le message codé (probablement une variante de la charge utile de la requête HTTP et de l'URL).
final String a2 = EncUtils.a(EncUtils.a(a, s)); final ArrayList list = new ArrayList(request.getHeaders()); list.add(new Header('X-CS-Url-Signature', a2));
Dans le code a
est un message et s
est la clé utilisée pour calculer l'en-tête a2
(le double appel à EncUtils
calcule simplement un condensé hexadécimal HMAC SHA1).
La recherche de la clé n'a pas posé de problème - elle était stockée en texte brut dans ApiModule
et a été utilisée pour initialiser le deuxième paramètre de RetrofitHttpClient.
RetrofitHttpClient a(OkHttpClient okHttpClient) { return new RetrofitHttpClient(okHttpClient, 'v3# [email protected] #XreXeGCh'); }
Si nous regardons l'appel à EncUtils
, nous pouvons voir que la chaîne littérale ci-dessus est utilisée textuellement comme clé pour calculer le HMAC, sauf dans le cas où this.b
est défini. Dans ce dernier cas, this.b
est ajouté avec un point.
String s; if (this.b == null) { s = this.a; } else { s = this.a + '.' + this.b; }
Maintenant, rien qu'en regardant le code, je ne savais pas où et comment this.b
est initialisé (la seule chose que j'ai pu découvrir est qu'il est appelé dans une méthode avec une signature this.a(String b)
, mais je n'ai trouvé aucun appel à lui dans le code).
public void a(final String b) { this.b = b; }
Je vous encourage à le décompiler et à le découvrir par vous-même :)
Comprendre le message était assez simple - dans le code, vous pouvez voir qu'il s'agit d'une concaténation du chemin de l'url, c'est-à-dire /api/v2/sessions
et une chaîne avec la charge utile JSON (le cas échéant).
final byte[] b = this.b(request.getUrl()); byte[] a; if (request.getBody() != null && request.getBody() instanceof JsonTypedOutput) { System.out.println('body'); // this.a(x, y) concatenates byte arrays a = this.a(b, ((JsonTypedOutput)request.getBody()).a); } else { a = b; }
Rien qu'en regardant le code, il était difficile de déterminer l'algorithme exact pour le calcul HMAC. J'ai donc décidé de reconstruire l'application avec des symboles de débogage pour comprendre exactement comment l'application fonctionne. J'ai utilisé un outil appelé apktool https://code.google.com/p/android-apktool/ pour démonter le bytecode Dalvik en utilisant smali https://code.google.com/p/smali/ . J'ai suivi le guide à https://code.google.com/p/android-apktool/wiki/SmaliDebugging
Après avoir créé l'apk, vous devez le signer et l'installer sur votre appareil. Comme je n'avais pas d'appareil Android, j'ai utilisé l'émulateur fourni avec le SDK Android. Avec un peu d'allaitement à la cuillère, voici comment procéder:
jarsigner -verbose -keystore ~/.android/debug.keystore -storepass android -keypass android androiddebugkey jarsigner -verify -verbose -certs zipalign -v 4
J'ai utilisé un émulateur Android intégré qui est livré avec le sdk et une image virtuelle Atom x86 avec HAXM activé pour garantir son bon fonctionnement.
tools/emulator -avd mydroid -no-boot-anim -cpu-delay 0
Voici un bon guide sur la façon de configurer une image virtuelle: http://jolicode.com/blog/speed-up-your-android-emulator
Assurez-vous de voir la ligne HAX fonctionne et l'émulateur fonctionne en mode virt rapide au démarrage de l'émulateur pour vous assurer que HAXM est activé.
Ensuite, j'ai installé l'apk dans l'émulateur et j'ai exécuté l'application. En suivant le guide apktool, j'ai utilisé le débogueur distant IntelliJ IDEA pour me connecter à l'émulateur et définir des points d'arrêt de ligne:
En jouant un peu avec l'application, j'ai pu comprendre que la clé privée utilisée pour initialiser RetrofitHttpClient
est utilisé pour calculer le HMAC d'une signature de demande de connexion. Dans la réponse au POST de connexion, vous recevez un ID utilisateur et un accessToken (X-Access-Token
). Le jeton d'accès est utilisé pour autoriser toutes les requêtes suivantes. Le HMAC pour toutes les demandes de post-connexion est construit de la même manière que la demande de connexion, sauf que la clé est composée en ajoutant .
à la clé privée d'origine.
Une fois que vous êtes autorisé, l'application envoie la demande suivante:
POST https://hapi.couchsurfing.com/api/v2/users/1003669205/registerDevice ← 200 application/json
Comme j'ai pu le déduire empiriquement, cette demande est facultative pour l'authentification. Des points bonus si vous savez à quoi il sert!
Une fois authentifié, vous pouvez envoyer une demande pour récupérer votre profil utilisateur (ou celui de quelqu'un d'autre), comme suit:
GET https://hapi.couchsurfing.com/api/v2/users/1003669205 ← 200 application/json
Je n’ai pas beaucoup approfondi les détails, mais j’ai remarqué qu’un profil est mis à jour avec une requête PUT. Juste pour le plaisir, j'ai essayé de mettre à jour un autre profil avec la même demande - ce n'était pas autorisé, donc apparemment les bases de la sécurité sont implémentées.
J'ai écrit un simple script Python pour vous connecter en utilisant vos informations d'identification couchsurfing.com et obtenir votre profil utilisateur: https://gist.github.com/nderkach/899281d7e6dd0d497533 . Voici le wrapper Python pour l'API: https://github.com/nderkach/couchsurfing-python avec un package disponible dans le référentiel pypi (pip install couchsurfing).
Je ne sais pas exactement ce que je vais faire avec l’API cette fois. Le code HTML dans les profils utilisateur n'est plus autorisé. Je vais donc devoir proposer une approche différente de l'ancien problème. Je continuerai à développer et à améliorer le wrapper d'API Python, s'il y a une demande, et en supposant que couchsurfing.com ne posera pas trop de problèmes. Je n’ai pas trop exploré l’API et je l’ai juste testée pour détecter certaines vulnérabilités de base. Cela semble suffisamment sécurisé, mais il serait intéressant de savoir si vous pouvez accéder aux données qui ne sont pas disponibles sur le site Web. Quoi qu'il en soit, vous pouvez maintenant utiliser mon ingénierie logicielle inverse pour créer un client alternatif pour Windows Phone, Pebble ou votre canapé intelligent.
Il y a une discussion que je souhaite ouvrir. Pourquoi ne pas publier votre API et la rendre publique? Même si je n’arrivais pas à pirater l’API, il serait toujours possible de gratter le site Web. Ce serait plus lent et plus difficile à maintenir, mais ils préféreraient sûrement que les consommateurs utilisent une API plutôt qu'un racleur Web. La disponibilité des API permettrait aux développeurs tiers d'améliorer le produit de l'entreprise et de créer un service à valeur ajoutée autour de celui-ci. On peut faire valoir qu'il serait plus coûteux de maintenir l'API publique plutôt que privée; mais là encore, les avantages de vos services de création de communauté en plus de votre produit l'emporteraient sur les coûts de maintenance de l'API.
Est-il possible d'empêcher complètement l'utilisation d'une API privée par des clients tiers? Je ne pense pas. L'utilisation de l'épinglage SSL empêcherait de renifler les demandes d'API en utilisant une simple technique de proxy transparent comme décrit précédemment. En fin de compte, même si vous obscurcissez le binaire, un hacker motivé avec quelques ressources et du temps sera toujours en mesure de rétroconcevoir le binaire de l'application et d'obtenir la clé privée / le certificat. Je pense que l'hypothèse selon laquelle le point final du client est sécurisé est intrinsèquement erronée. Une FEU le client est un point faible.
En gardant une API privée, une entreprise transmet essentiellement un message de méfiance à ses utilisateurs. Vous pouvez sûrement essayer de protéger encore plus votre API privée. Cependant, ne préférez-vous pas mettre en œuvre une sécurité de base pour l'API afin d'éviter toute utilisation malveillante; et plutôt concentrer vos ressources sur l'amélioration du logiciel pour offrir une meilleure expérience utilisateur?
Couchsurfing, assez s'il vous plaît, avec du sucre en haut, ouvrez l'API.