Tester la sécurité d’une API : Un Guide Pratique
Rappel : L’article qui va suivre contient des techniques et méthodes qui peuvent s’avérer être illégales et dangereuses si elles sont utilisées à mauvais escient. Ce tutoriel ne doit en aucun cas être utilisé contre un particulier, une entreprise, une organisation à but non lucratif ou une administration publique de quelconque pays. Je me dédouane de toute responsabilité en cas de problèmes ou d’incidents de quelque nature que ce soit après le visionnage de cet article.
Bonjour à tous, après une longue période sans publication sur ce blog, je suis ravi de vous présenter un nouvel article portant sur le thème de la « Sécurité des API ». Dans cet article, nous explorerons les méthodes de test pour évaluer la sécurité des API REST. Pour illustrer nos propos, nous utiliserons une API vulnérable appelée « VAMPI », conçue pour gérer l’attribution de livres à des utilisateurs. Les utilisateurs de cette API peuvent se connecter et vérifier s’ils sont autorisés à consulter un livre particulier.
Un grand merci à @erev0s ainsi qu’aux autres contributeurs de ce projet open-source.
I. Introduction et Rappels
A. Qu’est-ce qu’une API ?
Une API, ou Interface de Programmation d’Application (en anglais, Application Programming Interface), est un ensemble de règles et de protocoles qui permet à des logiciels / sites web différents de communiquer entre eux. Elle définit les méthodes et les formats de données que les développeurs peuvent utiliser pour intégrer leurs applications avec d’autres logiciels.
Une API peut être utilisée pour différentes raisons, notamment pour permettre à une application d’accéder aux fonctionnalités d’un service externe, d’interagir avec une base de données sans la requêter directement, ou même de partager des fonctionnalités avec d’autres applications.
Voici sans nul doute mon meme préféré. c’est en grande partie grace à lui que j’ai compris comment fonctionnait une API de bout en bout.
Voici quelques concepts clés liés aux API qui vont être utilisé dans cet article :
- Point d’Entrée / endpoint : Une API fournit des points d’entrées spécifiés (URI Uniform Resource Identifier),par lequel les développeurs peuvent accéder aux fonctionnalités offertes par l’API.
- Ex : https://api.domain.com/user/john.doe retournerait uniquement les caractéristiques liés à cet utilisateur (age, date d’inscription, etc.) si et seulement si l’utilisateur s’est authentifié.
- Méthodes : Les API utilisent des méthodes HTTP, telles que GET, POST, PUT, DELETE, qui correspondent aux opérations que les développeurs peuvent effectuer sur les ressources fournies par l’API. Celles-ci font références au principe du « CRUD ». Voir section suivante
- Formats de Données : Les données échangées entre les applications via une API sont généralement structurées dans des formats standard tels que JSON (JavaScript Object Notation) ou anciennement XML (eXtensible Markup Language).
- Authentification et Autorisation : Les API peuvent nécessiter des mécanismes d’authentification pour s’assurer que seules les applications autorisées peuvent accéder aux fonctionnalités fournies. De plus, elles peuvent implémenter des mécanismes d’autorisation post-auth pour contrôler l’accès aux différentes ressources.
En résumé, les API sont essentiellement un moyen standardisé pour que différentes applications modernes communiquent entre elles. Elles facilite ainsi l’intégration et l’interopérabilité entre les artecfats digitales.
B. CRUD (Create Read Update Delete)
Le terme CRUD est un acronyme couramment pour décrire les opérations fondamentales effectuées sur les données dans un système de gestion de base de données (SGBD) ou une application web. CRUD représente les quatre opérations de base que l’on peut effectuer sur les données :
- Create : Cette opération consiste à ajouter de nouvelles données à un système. Par exemple, dans une application web, cela pourrait signifier la création d’un nouveau compte utilisateur ou l’ajout d’un nouveau produit à une boutique en ligne, etc.
- Read : La lecture consiste à récupérer et afficher des données existantes à partir du système. Il s’agit de la consultation des informations stockées dans la base de données, que ce soit pour afficher un profil d’utilisateur ou consulter les détails d’un produit, etc.
- Update : Cette opération implique la modification des données existantes. Par exemple, vous pourriez mettre à jour les informations de votre profil utilisateur ou mettre à jour le prix d’un produit.
- Delete : La suppression consiste à retirer des données du système. Cela pourrait signifier la suppression d’un compte utilisateur, ou la suppression d’un produit de la base de données.
Ces opérations sont essentielles dans le développement d’applications et dans la gestion de bases de données, car elles permettent de gérer les données de manière cohérente et efficiente. Ce qui en fait un des piliers conceptuelles du développement logiciel et conception de bases de données.
Source : https://www.geeksforgeeks.org/crud-operations-and-file-upload-using-node-js-and-mongodb/
C. REST vs RESful ?
REST est un ensemble de principes architecturaux, RESTful est une mise en œuvre concrète de ces principes avec une adhérence stricte aux conventions, rendant l’API plus prévisible, facile à comprendre et à utiliser.
Voici un schema permettant de se représenter conceptuellement le fonctionnement d’une API REST : (source : https://www.linkedin.com)
II. Avec quel outils peux-ton tester la sécurité d’une API ?
Il existe pléthore d’outils ! Dans mon cas, j’utilise uniquements les trois suivants en générale :
- Burp Suite (Pro) : Le plus utilisé
- Postman : Je suis particulièrement Fan de l’interface graphique
- La commande curl (uniquement pour tester à la voler des endpoints bien précis)
Tout au long de cet article, je vais utiliser Postman ainsi que la commande curl
pour créer des requêtes un peu plus complexes. Cela vous permettra d’économiser du temps lors de vos tests et d’éviter de remplir manuellement chaque champ. Cependant, il est important de noter que cela ne remplace pas la nécessité d’exécuter également les requêtes via Burp ou Postman.
III. Setup de l’API vulnérable VAMPI avec … Docker ^^
Pour ne pas se compliquer la vie, on va utiliser l’image toute prête qui a été publié sur le dockerhub par @erev0s. Toutefois, sachez que vous pouvez directement construire l’image depuis le Dockerfile officiel du projet.
docker run -d --rm -e vulnerable=1 -e tokentimetolive=300 -p 5000:5000 erev0s/vampi:latest
Caractéristiques du projet VAMPI fin 2023 :
- Basé sur les 10 principales vulnérabilités de l’OWASP pour les API (2023)
- Utilise OpenAPI3
- Activation/désactivation globale pour avoir un environnement vulnérable ou non. (vulnerable={0,1})
- Authentification par jeton (tokentimetolive=300) Il est possible d’augmenter cette valeur évidement.
IV. Déouverte des points de terminaisons
Même si le projet VAMPI nous fournit les endpoints vulnérables, il va de soi qu’en « boîte noire », nous ne disposons pas de ces informations. C’est précisément là que réside la complexité d’un test à l’aveugle d’une API. Dans le cadre de cet article, je vais simuler une approche « black box ».
Afin de rendre les tests d’une API aussi exhaustifs que possible, il est recommandé de les effectuer en boîte blanche, ce qui signifie avoir accès aux différents comptes et à la documentation. Cela permet à l’auditeur d’être beaucoup plus efficace et exhaustif dans ses tests.
Mais alors, comment procéder ?
Le moyen le plus basique pour détecter rapidement des points de terminaison communs consiste à utiliser un scanner de répertoire tel que dirsearch
ou dirb
. De plus, il est fortement recommandé d’utiliser une wordlist personnalisée contenant des noms couramment utilisés lors de la conception d’API. Voici une petite liste, bien sûr non exhaustive :
v1
v2
v3
users
articles
api
ui
swagger
(...)
python3 dirsearch.py -u http://localhost:5000 -w /tmp/common-api-endpoints-wordlist.txt -r
La capture ci-après nous montre qu’une seule redirection a été détectée suite à l’exécution de dirsearch. Allons voir ce qui se cache derrière ce lien…
Si vous menez un véritable test d’intrusion, n’oubliez pas de réduire le nombre de threads, ainsi que le délai entre chaque requête, afin de ne pas vous faire bannir de manière inopportune :). Par ailleurs, je vous conseille de vous intéresser de près aux nombreuses options de la commande dirsearch.
python3 dirsearch.py -u http://example.com:5000 -t 2 --delay=0.20 -w /tmp/common-api-endpoints-wordlist.txt
On constate qu’une redirection (HTTP Code 308) a été détectée pour le répertoire « /ui ». En consultant ce lien, on peut constater que nous arrivons sur une interface Swagger.
Mais qu’est-ce que Swagger ? Swagger est un ensemble d’outils open source permettant de concevoir, documenter et tester des API REST. Il utilise une spécification appelée OpenAPI pour décrire la structure des API, y compris les points de terminaison, les paramètres et les réponses attendues. Cependant, exposer Swagger sans authentification préalable pose de graves problèmes de sécurité, car cela peut fournir aux attaquants des informations détaillées sur la structure interne de l’API, facilitant ainsi les attaques potentielles.
Oui, même dans un cas réel, il est possible de trouver ce genre de plateforme exposée publiquement. Croyez-moi, je sais de quoi je parle ^^
Ici, Swagger nous affiche tous les endpoints de l’API auxquels on peut accéder par défaut, ainsi que les détails associés à chacun. Nous venons donc implicitement de passer d’un audit en boîte noire à un audit en boîte blanche ! ^^
V. Tests SANS authentification au préalable (pre-auth testing)
A. Lister les utilisateurs du site
Cette première faille de sécurité n’est pas sans conséquence. En effet, elle permet à un attaquant de lister l’intégralité des utilisateurs du site. Cela signifie qu’un attaquant pourrait facilement établir une liste des utilisateurs du site, ce qui pourrait être utilisé ultérieurement pour d’autres vecteurs d’attaque en exploitant ces identifiants/emails.
Méthode HTTP | GET |
curl http://127.0.0.1:5000/users/v1 | jq
Fréquemment, les API disposent d’un paramètre « debug » permettant d’afficher plus d’informations concernant la réponse de l’endpoint. C’est grosso-modo l’équivalent du mode « verbose : -v » d’une commande classique.
Méthode HTTP | GET |
curl http://localhost:5000/users/v1/_debug
Certaines fonctionnalités, telles que la possibilité de lister les utilisateurs ou le mode débogage, devraient impérativement exiger une authentification d’un utilisateur ayant au minimum un profil de développeur. En aucun cas un utilisateur standard authentifié ne devrait avoir la capacité de lister tous les utilisateurs d’une API !
Pour afficher les informations d’un seul utilisateur, vous pouvez utiliser cette requête :
curl http://127.0.0.1:5000/users/v1/{username}
Ok, je vous l’accorde, il est très peu probable d’obtenir le mot de passe en clair à la suite de l’exécution en mode de débogage. Cependant, la recommendation est clair : Ne pas rendre accessible publiquement ce mode avancé, qui est normalement réservé aux développeurs.
B. Créer un utilisateur
En consultant la documentation de l’API, on constate qu’un endpoint /register existe. Testons si en tant qu’utilisateur non authentifié, nous pouvons créer un compte.
Méthode HTTP | POST |
curl http://127.0.0.1:5000/users/v1/register -d '{"email":"[email protected]","username":"lgds","password":"lgds"}' -H 'Content-Type: application/json' | jq
On constate ici qu’aucune politique de mot de passe n’est mise en place sur l’API, car il m’a été possible de créer un utilisateur avec comme mot de passe « lgds »…
C. Élevation de privilège – Défaut de cloisonnement verticale
Élevation de privilèges ou Escalade de privilèges ? le débat est lancé ^^
Le cloisonnement vertical implique la possibilité d’accéder à des fonctionnalités qui se trouvent en dehors de la portée initiale de l’utilisateur. Cela peut inclure la recherche de moyens pour obtenir des droits d’administration ou similaires, dans le but de passer d’un statut utilisateur à un statut administrateur.
Pour plus d’informations : https://openclassrooms.com/fr/courses/7727176-realisez-un-test-dintrusion-web/7917741-verifiez-la-fiabilite-du-controle-d-acces#/id/r-7919936
Méthode HTTP | POST |
Lorsque nous avons examiné le point de terminaison « /users/v1/_debug » plus tôt, vous n’avez peut-être pas remarqué, mais un attribut supplémentaire nous a été retourné en plus de « email », « username », et « password ». Cet attribut est « admin » (return : true or false : comportement par défaut). Cela démontre clairement l’existence d’une propriété appelée « admin » qui est définie sur « true » pour les utilisateurs administrateurs. Essayons d’enregistrer un nouvel utilisateur avec cet attribut dans la requête.
Encore une fois, oui, même dans un cas réel, il est possible de trouver ce genre de plateforme exposée publiquement. Croyez-moi, j’en ai déjà vu moi-même ^^
Méthode HTTP | POST |
Vous pouvez donc ajouter l’attribut « admin » et lui donner la valeur « true » pour vous auto-promouvoir en tant qu’administrateur de l’API dès votre inscription.
curl http://127.0.0.1:5000/users/v1/register -d '{"admin": true, "username": "adm_lgds", "password": "adm_lgds", "email": "[email protected]"}' -H 'Content-Type: application/json' | jq
{
"admin": true,
"username": "adm_lgds",
"password": "adm_lgds",
"email": "[email protected]"
}
Maintenant, si vous lister les utilisateurs avec « /users/v1 », vous constaterez l’ajout de l’utilisateur lgds adm_lgds. Pour vous assurer que celui-ci est admin, utilisez le endpoint « /users/v1/_debug »,
Méthode HTTP | GET |
curl http://localhost:5000/users/v1/_debug
# _debug ici vous permettra de visualiser si le niveau d'habilitation de l'utilisateur adm_lgds est bien fixé sur "admin"
D. Injection SQL – Non assainissement des entrées utilisateurs (inputs)
SQli : Technique permettant à un attaquant d’insérer du code SQL malveillant dans une requête SQL, souvent via des formulaires web ou des champs de recherche vulnérables. Cela peut entraîner la modification, la suppression ou la divulgation non autorisée de données dans une base de données. Pour se protéger contre les injections SQL, il est essentiel de valider et de sécuriser correctement les entrées utilisateur lors de la création de requêtes SQL.
En ajoutant un simple guillemet « /users/v1/name‘ » nous n’avons pas obtenu une réponse de l’API, mais une erreur.
Méthode HTTP | GET |
curl "http://127.0.0.1:5000/users/v1/lgds'" | head -n 10
Cela indique que les données fournies par l’utilisateur ne sont pas correctement nettoyées avant d’être transmises à la base de données, ce qui signifie qu’elles exécuteront tout ce que l’utilisateur y insère y compris des jeux de caratères malicieux. Dans ce cas précis, l’erreur renvoyée nous indique que le Système de Gestion de Base de Données (SGBD) en question est SQLite.
Pour exploiter rapidement cette injection SQL, vous pouvez utiliser SQLMap de la manière suivante :
sqlmap -u "http://127.0.0.1:5000/users/v1/lgds" --dump all --batch --flush-session
-u "http://127.0.0.1:5000/users/v1/lgds"
: C’est l’URL cible à analyser. Dans cet exemple, SQLMap va cibler l’URL « http://127.0.0.1:5000/users/v1/lgds » pour rechercher des vulnérabilités SQL.--dump all
: Ce paramètre indique à SQLMap de tenter de récupérer des données de la base de données une fois qu’il a identifié une vulnérabilité SQL. L’option « all » signifie qu’il tentera de récupérer toutes les données disponibles.--batch
: En utilisant cette option, SQLMap fonctionnera en mode batch, ce qui signifie qu’il n’interagira pas avec l’utilisateur pour prendre des décisions. Il utilisera les options par défaut pour l’analyse.--flush-session
: Cette option indique à SQLMap de supprimer toutes les données de session de la commandesqlmap
courrante. Cela peut être utile pour éviter que des données d’une analyse précédente n’interfèrent avec la nouvelle analyse. (cache…)
Afin de prévenir toute surcharge de la base de données et de maintenir un faire profil bas dans un scénario réel, il est essentiel d’opter pour des extractions progressives. Cela signifie qu’il est recommandé d’extraire une table, voire même des portions de tables, pour limiter le nombre de résultats obtenus. Cette approche permet d’effectuer une preuve de concept (PoC) initiale tout en préservant la disponibilité et la stabilité de l’API et de sa base de données.
Voici le résultat du dump :
E. Absence de protection contre les attaques automatisés
Il existe plusieurs méthodes pour réaliser ce test. Dans mon cas, j’ai choisi d’utiliser Burp Suite Pro en sélectionnant le Mode Sniper dans le menu Intruder. Sans entrer dans les détails, j’ai envoyé avec succès 50 requêtes consécutives vers le point d’extrémité « /users/v1/login » sans être bloqué.
Méthode HTTP | POST |
VI. Tests post-identification (post-authentication testing)
A. Défaut de cloisonement horizontal
On appelle cloisonnement horizontal le fait de vérifier qu’un utilisateur A ne peut pas accéder au périmètre d’un utilisateur B. (fichiers, etc.)
source : https://openclassrooms.com/fr/courses/7727176-realisez-un-test-dintrusion-web/7917741-verifiez-la-fiabilite-du-controle-d-acces
Pour obtenir la liste complète de tous les livres, il vous suffit de faire une requête vers le point de terminaison suivant : /books/v1.
Méthode HTTP | GET |
Pour rappel, l’objectif de cette API est de référencer une collection de livres. Chaque livre est associé de manière unique à chaque utilisateur, et chaque livre a un seul et unique propriétaire. Lorsqu’un utilisateur consulte ce point de terminaison, il est impératif qu’il se soit préalablement authentifié auprès de l’API, ce qui permettra à celle-ci de lui donner accès au ‘secret du livre’
Nous constatons qu’il existe un point d’accès qui répertorie tous les livres, accessible sans nécessité préalable d’authentification : /books/v1
curl -s http://127.0.0.1:5000/books/v1 | jq
Le fait de fournir une liste de livres avec les propriétaires (utilisateurs) associés n’est pas un comportement approprié, car cela permet une énumération des utilisateurs qui possèdent des livres en interrogeant cet endpoint. »
Je vais maintenant tenter d’obtenir le secret d’un des livres intitulé « bookTitle16 » appartenant à l’utilisateur « name1 » en interrogeant l’endpoint /books/v1/{book_name}.
Méthode HTTP | GET |
curl -s http://localhost:5000/books/v1/bookTitle16 | jq
Ceci suggère que je n’ai pas d’authentification active sur l’API. Ainsi, je devrais m’authentifier avec le compte utilisateur « name1 » pour pouvoir accéder au « secret du livre » intitulé « bookTitle16 »
Méthode HTTP | POST |
curl -s http://127.0.0.1:5000/users/v1/login -d '{"username":"name1","password":"pass1"}' -H 'Content-Type: application/json' | jq
Avec le jeton d’authentification obtenu, je suis désormais en mesure de m’authentifier en tant que « name1 » et d’accéder au secret du livre.
Méthode HTTP | GET |
curl -s http://127.0.0.1:5000/books/v1/bookTitle16 -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTgwNjI5ODUsImlhdCI6MTY5ODA2MjY4NSwic3ViIjoibmFtZTEifQ.t9UiTu5EA-nOZJeQIFyftYvcQQbsrm3WR1R2M1Cz2Xg' | jq
Maintenant, envisagez un scénario où un autre utilisateur pourrait accéder au secret d’un livre qui ne lui appartient pas. Pensons en dehors des sentiers battus ! Comme le dit Julien Metayer : Le hacking est avant tout un état d’esprit
En théorie, cela ne devrait pas être possible, mais par précaution, pourquoi ne pas effectuer un test pour confirmer ? 😉
Pour ce faire, je vais me connecter en utilisant un nouvel utilisateur que j’ai fraîchement créé : « lgds » (et non « lgds_admin » ! Nous voulons un utilisateur ayant le même niveau d’autorisation que « name1 », c’est-à-dire un utilisateur standard).
Méthode HTTP | POST |
curl -s http://127.0.0.1:5000/users/v1/login -d '{"username":"lgds","password":"lgds"}' -H 'Content-Type: application/json' | jq
Méthode HTTP | GET |
Une fois de plus, je place mon jeton d’authentification dans l’en-tête HTTP « Authorization Bearer » pour accéder à l’endpoint /books/v1/bookTitle16.
curl -s http://127.0.0.1:5000/books/v1/bookTitle16 -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTgwNjM0NzgsImlhdCI6MTY5ODA2MzE3OCwic3ViIjoibGdkcyJ9.YIDVhSOaPq9BIjF0JkSfaj147PDGsIRkwA4WrX4tOyg' | jq
Vous pourriez reformuler votre phrase de la manière suivante :
« Toudoum (comme dans Netflix) ! Oh, que découvrons-nous ? Il est possible d’accéder au secret du livre « bookTitle16 » (propriétaire : name1) alors que je me connecte en utilisant l’utilisateur « lgds » avec son jeton d’authentification qui lui est propre. Le défaut de cloisonnement horizontal est indubitablement établi !
B. Account takeover
Nous avons observé la possibilité d’utiliser le token d’utilisateur 1 pour accéder aux données de l’utilisateur 2. Par conséquent, nous allons tenter cette opération sur un point d’accès différent de celui précédemment utilisé. Envoyez une nouvelle requête authentifiée à /users/v1/{username}/password et envoyez le nouveau mot de passe comme valeur JSON pour « password ».
Nous avons constaté la possibilité d’utiliser le jeton de l’utilisateur lgds pour accéder aux données de l’utilisateur name1. Par conséquent, je vais tenter cette opération sur un point d’accès différent de celui précédemment utilisé.
Dans cette section, vous aurez encore besoin d’un jeton de connexion valide. Si le vôtre a expiré, reconnectez-vous en initiant une nouvelle session auprès de l’API :
Réinitialiser le mot de passe de n’importe quel utilisateur via un compte standard
Méthode HTTP | PUT |
curl -v -X PUT http://127.0.0.1:5000/users/v1/name1/password -d '{"password":"pwned"}' -H 'Content-Type: application/json' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTgwNjQzMDEsImlhdCI6MTY5ODA2NDAwMSwic3ViIjoibGdkcyJ9.2-H_cSNInK_xWaZpDbpjJuSBbN-8IGhykSQATN-f7HM' | jq
L’API nous renvoie une réponse 204, mais cela peut parfois être considéré comme ‘normal’. En effet, les développeurs n’avaient peut-être pas prévu cette possibilité, et donc l’API ne renvoie aucune réponse, ce qui pourrait être avantageux pour nous.
Méthode HTTP | POST |
curl -s http://127.0.0.1:5000/users/v1/login -d '{"username":"name1","password":"pwned"}' -H 'Content-Type: application/json' | jq
Comme vous pouvez le voir sur la capture d’écran ci-dessus, il a été possible de modifier le mot de passe de l’utilisateur « name1 » en utilisant un jeton d’authentification appartenant à l’utilisateur « lgds ».
Réinitialiser l’email de n’importe quel utilisateur.
Il n’est pas possible d’effectuer cette action, car les développeurs ont mis en place une vérification pour s’assurer que le jeton correspond réellement à son propriétaire. Si vous exécutez la requête suivante, cela changera l’adresse e-mail, non pas de l’utilisateur « name1 », mais de l’utilisateur « lgds ».
Méthode HTTP | PUT |
curl -v -X PUT http://127.0.0.1:5000/users/v1/name1/email -d '{"email":"[email protected]"}' -H 'Content-Type: application/json' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTg3MDM4NTQsImlhdCI6MTY5ODY3Mzg1NCwic3ViIjoibGdkcyJ9.8WACw7GZPhGlB0F1tg-xk9Q3uKXH0hqDo4LQE1519AY' | jq
Comme illustré sur la capture d’écran ci-dessus, il n’a pas été possible de modifier l’adresse e-mail de l’utilisateur « name1 » en utilisant un jeton d’authentification appartenant à l’utilisateur « lgds ». En revanche, cette requête a provoqué un effet inattendu en modifiant l’adresse e-mail de notre propre compte… Cela Porte un nom : l’effet : « Retour de bommerang »
Supprimer le compte de n’importe quel utilisateur.
Étant donné la vulnérabilité de cette API, nous sommes en droit de nous demander si nous pouvons supprimer un compte en utilisant un compte utilisateur standard…
Méthode HTTP | DELETE |
curl -v -X DELETE http://127.0.0.1:5000/users/v1/name1 -d '{"password":"pwned"}' -H 'Content-Type: application/json' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2OTg3MDM4NTQsImlhdCI6MTY5ODY3Mzg1NCwic3ViIjoibGdkcyJ9.8WACw7GZPhGlB0F1tg-xk9Q3uKXH0hqDo4LQE1519AY' | jq
Une reformulation possible pourrait être :
Comme le montre la capture d’écran ci-dessus, il est clair que cela n’est pas possible.
C. DoS via une expression régulière (regex)
Je n’ai pas encore terminé avec cette API ! Au-delà du fait que j’ai pu démontrer dans une des premières sections qu’il était possible d’envoyer un grand nombre de requêtes sans être bloqué, je me suis demandé s’il était possible de faire « planter l’API », étant donné qu’elle ne nettoie pas correctement ses entrées. Eh bien, la réponse est oui…
Un Self-DoS implique de surcharger un service quelconque s’executant sur l’hôte en l’obligeant à effectuer des calculs complexes ce qui augmentent la charge de travail et entraînent des dépassements de délais. En fin de compte, l’application est submergée. Une fois de plus, cela est rendu possible uniquement parce que les données d’entrée de l’utilisateur ne sont pas correctement assainie.
Ici, il est possible de provoquer le crash de l’application en envoyant une requête authentifiée au point de terminaison « /users/v1/{username}/email » en fournissant une longue chaîne de caractères qui n’est en réalité pas une adresse e-mail valide, mais un payload ayant pour but de pertuber le comportment de l’API.
Le caractère « ! » n’est pas celui qui provoque le comportement inattendu, c’est uniquement la longueur excessive de la chaîne par rapport à ce que le backend avait prévu qui provoque le problème (plus le fait que les inputs ne sont pas sanitize)
Méthode HTTP | PUT |
VII. Conclusion
Merci d’avoir pris le temps de lire cet article. J’espère qu’il vous a aidé à mieux comprendre le pentesting d’une API en détail. Si vous avez des remarques ou des questions, n’hésitez pas à m’en faire part sur X :).
++
Geoffrey
En savoir plus sur Le Guide Du SecOps
Subscribe to get the latest posts sent to your email.