Race Condition
Last updated
Last updated
Utilisez Trickest pour construire facilement et automatiser des flux de travail alimentés par les outils communautaires les plus avancés au monde. Obtenez l'accès aujourd'hui :
Pour obtenir une compréhension approfondie de cette technique, consultez le rapport original sur https://portswigger.net/research/smashing-the-state-machine
Le principal obstacle pour tirer parti des conditions de course est de s'assurer que plusieurs requêtes sont traitées en même temps, avec très peu de différence dans leurs temps de traitement - idéalement, moins de 1 ms.
Voici quelques techniques pour synchroniser les requêtes :
HTTP/2 : prend en charge l'envoi de deux requêtes sur une seule connexion TCP, réduisant l'impact du jitter du réseau. Cependant, en raison de variations côté serveur, deux requêtes peuvent ne pas suffire pour une exploitation cohérente de la condition de course.
HTTP/1.1 'Synchronisation du dernier octet' : permet l'envoi préalable de la plupart des parties de 20 à 30 requêtes, en retenant un petit fragment, qui est ensuite envoyé ensemble, atteignant une arrivée simultanée au serveur.
La préparation à la synchronisation du dernier octet implique :
Envoi des en-têtes et des données du corps moins le dernier octet sans terminer le flux.
Pause de 100 ms après l'envoi initial.
Désactivation de TCP_NODELAY pour utiliser l'algorithme de Nagle pour regrouper les trames finales.
Ping pour chauffer la connexion.
L'envoi ultérieur des trames retenues devrait entraîner leur arrivée dans un seul paquet, vérifiable via Wireshark. Cette méthode ne s'applique pas aux fichiers statiques, qui ne sont généralement pas impliqués dans les attaques RC.
Comprendre l'architecture de la cible est crucial. Les serveurs frontaliers peuvent router les requêtes différemment, affectant la synchronisation. Le préchauffage côté serveur, à travers des requêtes insignifiantes, pourrait normaliser le timing des requêtes.
Les frameworks comme le gestionnaire de session PHP sérialisent les requêtes par session, ce qui peut potentiellement masquer les vulnérabilités. L'utilisation de jetons de session différents pour chaque requête peut contourner ce problème.
Si le préchauffage de la connexion est inefficace, déclencher intentionnellement les retards de limite de taux ou de ressources des serveurs Web à travers une inondation de requêtes factices pourrait faciliter l'attaque en un seul paquet en induisant un retard côté serveur propice aux conditions de course.
Tubo Intruder - Attaque en un seul paquet HTTP2 (1 point de terminaison) : Vous pouvez envoyer la requête à Turbo Intruder (Extensions
-> Turbo Intruder
-> Send to Turbo Intruder
), vous pouvez changer dans la requête la valeur que vous souhaitez forcer pour %s
comme dans csrf=Bn9VQB8OyefIs3ShR2fPESR0FzzulI1d&username=carlos&password=%s
et ensuite sélectionner le examples/race-single-packer-attack.py
dans le menu déroulant :
Si vous allez envoyer des valeurs différentes, vous pourriez modifier le code avec celui-ci qui utilise une liste de mots du presse-papiers :
Si le site web ne prend pas en charge HTTP2 (uniquement HTTP1.1), utilisez Engine.THREADED
ou Engine.BURP
au lieu de Engine.BURP2
.
Intrus de Tube - Attaque à un seul paquet HTTP2 (Plusieurs points de terminaison): Dans le cas où vous devez envoyer une requête à 1 point de terminaison, puis à plusieurs autres points de terminaison pour déclencher l'exécution de code à distance, vous pouvez modifier le script race-single-packet-attack.py
comme suit :
Il est également disponible dans Repeater via la nouvelle option 'Envoyer le groupe en parallèle' dans Burp Suite.
Pour limit-overrun, vous pourriez simplement ajouter la même requête 50 fois dans le groupe.
Pour le préchauffage de la connexion, vous pourriez ajouter au début du groupe quelques requêtes vers une partie non statique du serveur web.
Pour retarder le processus entre le traitement d'une requête et d'une autre en 2 étapes de sous-états, vous pourriez ajouter des requêtes supplémentaires entre les deux requêtes.
Pour un RC à multi-point d'extrémité, vous pourriez commencer à envoyer la requête qui va vers l'état caché puis 50 requêtes juste après qui exploitent l'état caché.
Script python automatisé: Le but de ce script est de changer l'e-mail d'un utilisateur tout en le vérifiant continuellement jusqu'à ce que le jeton de vérification du nouvel e-mail arrive au dernier e-mail (car dans le code, il voyait une RC où il était possible de modifier un e-mail mais de faire envoyer la vérification à l'ancien car la variable indiquant l'e-mail était déjà peuplée avec le premier). Lorsque le mot "objetivo" est trouvé dans les e-mails reçus, nous savons que nous avons reçu le jeton de vérification de l'e-mail modifié et nous terminons l'attaque.
Avant les recherches précédentes, voici quelques charges utiles utilisées qui tentaient simplement d'envoyer les paquets le plus rapidement possible pour provoquer une RC.
Répéteur: Consultez les exemples de la section précédente.
Intrus: Envoyez la requête à Intrus, définissez le nombre de threads sur 30 dans le menu Options, sélectionnez comme charge utile Charges utiles nulles et générez 30.
Turbo Intrus
Python - asyncio
Il s'agit du type le plus basique de condition de course où des vulnérabilités apparaissent dans des endroits qui limitent le nombre de fois où vous pouvez effectuer une action. Comme utiliser plusieurs fois le même code de réduction dans une boutique en ligne. Un exemple très simple peut être trouvé dans ce rapport ou dans ce bug.
Il existe de nombreuses variations de ce type d'attaque, notamment :
Utiliser plusieurs fois une carte cadeau
Noter un produit plusieurs fois
Retirer ou transférer de l'argent en excès par rapport à votre solde de compte
Réutiliser une solution CAPTCHA unique
Contourner une limite de taux anti-brute force
Exploiter des conditions de course complexes implique souvent de profiter de brèves opportunités pour interagir avec des sous-états de machine cachés ou non intentionnels. Voici comment aborder cela :
Identifier les sous-états cachés potentiels
Commencez par cibler les points de terminaison qui modifient ou interagissent avec des données critiques, telles que les profils d'utilisateurs ou les processus de réinitialisation de mot de passe. Concentrez-vous sur :
Stockage : Privilégiez les points de terminaison qui manipulent des données persistantes côté serveur par rapport à ceux qui gèrent des données côté client.
Action : Recherchez des opérations qui modifient des données existantes, plus susceptibles de créer des conditions exploitables par rapport à celles qui ajoutent de nouvelles données.
Identification : Les attaques réussies impliquent généralement des opérations basées sur le même identifiant, par exemple, le nom d'utilisateur ou le jeton de réinitialisation.
Effectuer des sondages initiaux
Testez les points de terminaison identifiés avec des attaques de condition de course, en observant toute déviation par rapport aux résultats attendus. Des réponses inattendues ou des changements de comportement de l'application peuvent signaler une vulnérabilité.
Démontrer la vulnérabilité
Réduisez l'attaque au nombre minimal de requêtes nécessaires pour exploiter la vulnérabilité, souvent juste deux. Cette étape peut nécessiter plusieurs tentatives ou une automatisation en raison de la synchronisation précise impliquée.
La précision dans la synchronisation des requêtes peut révéler des vulnérabilités, notamment lorsque des méthodes prévisibles comme les horodatages sont utilisées pour les jetons de sécurité. Par exemple, générer des jetons de réinitialisation de mot de passe basés sur des horodatages pourrait permettre d'obtenir des jetons identiques pour des requêtes simultanées.
Pour exploiter :
Utilisez une synchronisation précise, comme une attaque à un seul paquet, pour effectuer des demandes de réinitialisation de mot de passe simultanées. Des jetons identiques indiquent une vulnérabilité.
Exemple :
Demandez deux jetons de réinitialisation de mot de passe en même temps et comparez-les. Des jetons correspondants suggèrent une faille dans la génération de jetons.
Consultez ce laboratoire PortSwigger pour essayer cela.
Consultez ce laboratoire PortSwigger pour voir comment payer dans un magasin et ajouter un article supplémentaire que vous n'aurez pas à payer.
L'idée est de vérifier une adresse e-mail et la changer pour une autre en même temps pour savoir si la plateforme vérifie la nouvelle adresse modifiée.
Selon cette recherche Gitlab était vulnérable à une prise de contrôle de cette manière car il pourrait envoyer le jeton de vérification d'e-mail d'un e-mail à l'autre e-mail.
Consultez ce laboratoire PortSwigger pour essayer cela.
Si 2 écritures différentes sont utilisées pour ajouter des informations dans une base de données, il y a un court laps de temps où seule la première donnée a été écrite dans la base de données. Par exemple, lors de la création d'un utilisateur, le nom d'utilisateur et le mot de passe peuvent être écrits puis le jeton pour confirmer le compte nouvellement créé est écrit. Cela signifie que pendant un court laps de temps, le jeton pour confirmer un compte est nul.
Par conséquent, enregistrer un compte et envoyer plusieurs requêtes avec un jeton vide (token=
ou token[]=
ou toute autre variation) pour confirmer le compte immédiatement pourrait permettre de confirmer un compte dont vous ne contrôlez pas l'e-mail.
Consultez ce laboratoire PortSwigger pour essayer cela.
Le pseudo-code suivant est vulnérable à une condition de course car pendant un très court laps de temps, l'authentification à 2 facteurs n'est pas appliquée tandis que la session est créée:
Il existe plusieurs fournisseurs OAuth. Ces services vous permettront de créer une application et d'authentifier les utilisateurs enregistrés par le fournisseur. Pour ce faire, le client devra autoriser votre application à accéder à certaines de leurs données à l'intérieur du fournisseur OAuth. Ainsi, jusqu'ici, il s'agit simplement d'une connexion classique avec google/linkedin/github... où vous êtes invité avec une page disant : "L'application <InsertCoolName> souhaite accéder à vos informations, voulez-vous l'autoriser?"
authorization_code
Le problème survient lorsque vous l'acceptez et envoie automatiquement un authorization_code
à l'application malveillante. Ensuite, cette application abuse d'une Course Condition dans le fournisseur de services OAuth pour générer plus d'un AT/RT (Authentication Token/Refresh Token) à partir du authorization_code
pour votre compte. Fondamentalement, elle exploitera le fait que vous avez accepté l'application pour accéder à vos données afin de créer plusieurs comptes. Ensuite, si vous arrêtez d'autoriser l'application à accéder à vos données, une paire d'AT/RT sera supprimée, mais les autres resteront valides.
Refresh Token
Une fois que vous avez obtenu un RT valide, vous pourriez essayer de l'exploiter pour générer plusieurs AT/RT et même si l'utilisateur annule les autorisations pour l'application malveillante d'accéder à ses données, plusieurs RT resteront valides.
Dans WS_RaceCondition_PoC vous pouvez trouver un PoC en Java pour envoyer des messages websocket en parallèle pour exploiter les Course Conditions également dans les Web Sockets.
Utilisez Trickest pour construire et automatiser facilement des workflows alimentés par les outils communautaires les plus avancés au monde. Accédez dès aujourd'hui :