DevSecOps
Master 2 · Polytech UCATP01C. Delettre

Sécurité Web :
casser pour comprendre.

Une appli web pleine de failles (DVWA), et cinq façons de la faire tomber : deviner, fouiller, casser un mot de passe, injecter du SQL, injecter une commande. À chaque fois : comment ça marche, et comment s'en protéger.

Éthique d'abord. Tout ce qui suit ne se pratique que sur ta propre machine et tes VM. Tester un système sans autorisation est illégal. Le but est de savoir défendre, pas d'attaquer.
attacker@kali:$ john --wordlist=rockyou.txt shadow.txt
admin123 (test2)
1g 0:00:00:01 DONE 8714p/s
attacker@kali:$
En 30 secondes

La plupart des failles web viennent d'une entrée utilisateur mal traitée. Si on la colle telle quelle dans une requête SQL, on a une injection SQL. Dans une commande shell, une injection de commande. Un mot de passe faible se casse par dictionnaire (John). Des dossiers cachés se trouvent par fuzzing (wfuzz). Le remède est presque toujours le même : ne jamais faire confiance à l'entrée (valider, échapper, requêtes préparées) et appliquer le moindre privilège. On s'entraîne sur DVWA.

01 — Le décor

DevSecOps, pentest, OWASP

Le DevSecOps, c'est intégrer la sécurité tout au long du développement (shift left), pas en fin de projet. Le pentest (test d'intrusion) en est le versant offensif : on cherche les failles avant les attaquants, on les exploite pour prouver l'impact, puis on corrige.

DÉTECTER

Trouver la faille

Analyse du code, scan, fuzzing. On repère où l'appli fait confiance à une entrée qu'elle ne devrait pas.

EXPLOITER

Prouver l'impact

On construit un payload qui déclenche la faille (voler des données, exécuter une commande) pour montrer que le risque est réel.

CORRIGER

Se protéger

Le vrai but : requêtes préparées, validation, échappement, moindre privilège. Casser sert à savoir réparer.

OWASP Top 10

La référence des risques web les plus critiques. Les injections (SQL, commande) y figurent historiquement en tête (A03:2021). Tout ce TP tourne autour de ce risque n°1 : une entrée non maîtrisée interprétée comme du code.

02 — Le terrain d'entraînement

DVWA / Damn Vulnerable Web Application

DVWA est un serveur web volontairement vulnérable. On y installe l'appli sur une VM Ubuntu, on choisit un niveau de sécurité (low, medium, high) et on exploite les failles pour apprendre à les détecter, les exploiter et les corriger.

Les niveaux

  • low : aucune protection, code naïf. C'est le niveau du TP.
  • medium : filtres partiels, contournables.
  • high : en théorie non exploitable (code sécurisé), sert de modèle de correction.
Rappel légal

DVWA se lance uniquement sur ta VM. Les exploits ne doivent jamais viser un système dont tu n'as pas l'autorisation écrite. Sinon, c'est un délit.

03 — Reconnaissance

Deviner et fouiller

Avant d'exploiter, on cartographie. Deux techniques de base : la force brute (tester toutes les combinaisons d'un identifiant) et le directory brute forcing (découvrir des dossiers/fichiers cachés en testant une liste de noms contre l'URL).

FORCE BRUTE

Tester toutes les combinaisons

Aucune connaissance préalable : on automatise les essais (John, Hydra) jusqu'à trouver. Lente mais garantie si aucune limite (rate limiting, captcha, délai) n'est en place.

DIRECTORY BRUTE FORCING

Trouver le caché

On envoie une requête HTTP par mot d'une wordlist et on lit le code de réponse (200/301/403/404) pour déduire l'existence de la ressource : pages admin, sauvegardes, config.

wfuzz en action exo 3

Commande type : wfuzz -w common.txt --hc 404 http://cible/dvwa/FUZZ. Le mot-clé FUZZ est remplacé par chaque mot de la liste ; --hc 404 masque les absents.

0 / 0
Prêt
wfuzz teste chaque mot et lit le code HTTP. Lance la lecture.
200 trouvé 301 dossier existe 404 absent

04 — Mots de passe

Hachage, sel, et cassage par dictionnaire

Un mot de passe n'est jamais (bien) stocké en clair : on garde son hash, une empreinte à sens unique. On ne peut pas « déchiffrer » un hash. Pour le casser, on teste des candidats : on hache chaque mot d'un dictionnaire et on compare au hash cible.

Le sel

Un sel unique est ajouté avant le hachage. Deux personnes avec le même mot de passe ont alors des hashs différents, ce qui casse les rainbow tables (tables précalculées). Le préfixe du hash encode l'algorithme : ici $6$ = sha512crypt.

Le piège du TP

John « core » (paquet Ubuntu) ne gère pas sha512crypt (« Unknown ciphertext format »). Il faut la version jumbo (branche bleeding-jumbo) compilée depuis les sources.

John the Ripper exo 2

John lit le fichier shadow, détecte le format, puis pour chaque mot de la liste : calcule le hash avec le même sel et compare. Dès qu'un hash correspond, le mot en clair tombe.

John ne se limite pas aux comptes système : zip2john, pdf2john, ssh2john, keepass2john extraient un hash d'une archive, d'un PDF, d'une clé SSH ou d'un coffre KeePass, que John casse ensuite.

0 / 0
Prêt
John essaie chaque mot du dictionnaire jusqu'à trouver le bon. Lance la lecture.

05 — Injection SQL

Faire dire à la base ce qu'on veut

Le code DVWA (low) concatène l'entrée directement : "...WHERE user_id = '$id';". Comme $id vient de l'utilisateur, on peut y glisser du code SQL. Clique un payload et regarde la requête et le résultat changer.

Requête exécutée côté serveur

Résultat renvoyé

Ce qui se passe
La correction

Utiliser des requêtes préparées (PDO/mysqli) avec paramètres liés : la valeur est transmise séparément de la structure, le moteur la traite toujours comme une donnée, jamais comme du code. En complément : forcer le type (id entier), et limiter les privilèges du compte MySQL (moindre privilège).

06 — Injection de commande

Exécuter ses propres commandes sur le serveur

Le code DVWA (low) fait shell_exec('ping -c 4 ' . $target). $target vient de l'utilisateur, sans filtrage. Un ; suffit à enchaîner une deuxième commande, exécutée avec les droits du serveur web. Clique et regarde l'escalade.

Terminal du serveur (www-data)

Ce qui se passe
La correction

Ne jamais construire une commande shell à partir d'entrée brute. Valider strictement le format attendu (ici une IP : filter_var(..., FILTER_VALIDATE_IP)), échapper avec escapeshellarg, et si possible éviter l'appel système au profit d'une fonction native du langage.

07 — Le TP décortiqué

Les 5 exercices, corrigés

Le corrigé complet du TP01 (rendu en binôme). Ouvre chaque exercice.

Exo 1

Définir les 4 attaques

Brute force, directory brute forcing, injection SQL, injection de commande.

1 Attaque par force brute

Tester systématiquement toutes les combinaisons d'identifiants jusqu'à trouver la bonne. Aucune connaissance préalable, on automatise (John, Hydra). Le temps dépend de la complexité du mot de passe et des protections (rate limiting, délai, captcha). Lente mais garantie sans limite.

2 Directory brute forcing

Découvrir fichiers et répertoires cachés en testant une wordlist contre l'URL. On lit le code de réponse (200/403/404) pour déduire l'existence. Révèle pages d'admin, fichiers de config ou de sauvegarde (wfuzz, dirb).

3 Injection SQL

Exploite l'absence de validation d'entrée dans une appli qui construit ses requêtes dynamiquement. On insère du SQL dans un champ pour modifier la requête : contourner une authentification, extraire des données (UNION SELECT), modifier/supprimer. Cause : pas de requêtes préparées ni d'échappement.

4 Injection de commande

Une entrée non filtrée est transmise à une fonction qui exécute des commandes shell. On ajoute des caractères de concaténation (point-virgule, esperluette, pipe) pour faire exécuter ses commandes avec les droits du process web : lecture de fichiers, exfiltration, prise de contrôle. Protection : validation stricte et éviter les appels système avec des données utilisateur.

fait

Exo 2 — John the Ripper (hash sha512crypt)

Casser le mot de passe de test2 dans un fichier shadow.

Le fichier contient une ligne shadow avec un hash préfixé $6$ (sha512crypt) et son sel. But : retrouver le mot de passe en clair via la liste des 100 000 plus courants.

Piège John core ne gère pas sha512crypt

Erreur « Unknown ciphertext format ». Solution : compiler John jumbo (bleeding-jumbo).

git clone --depth 1 -b bleeding-jumbo https://github.com/openwall/john john-jumbo
cd john-jumbo/src && ./configure && make -sj4

Q1 Craquer

~/john-jumbo/run/john --wordlist=~/10-million-...-top-100000.txt ~/mypassword.txt
# admin123        (test2)   -> trouvé en < 1s
~/john-jumbo/run/john --show ~/mypassword.txt   # test2:admin123

Mot de passe = admin123. Trouvé instantanément car présent tôt dans la liste : sa complexité apparente (lettres+chiffres) ne protège pas s'il est déjà connu.

Q2 Autres fichiers cassables

Archives (zip2john, rar2john, 7z2john), documents Office/PDF (office2john, pdf2john), clés SSH (ssh2john), coffres KeePass (keepass2john), handshakes WPA/WPA2. Principe commun : un outil extrait le hash, John le casse.

Q3 Exemple ZIP

zip2john archive.zip > hash.txt
john --wordlist=rockyou.txt hash.txt

zip2john lit les métadonnées de vérification du ZIP et produit une ligne de hash, cassée comme un hash shadow.

fait

Exo 3 — wfuzz (directory brute forcing)

Découvrir les dossiers et fichiers de DVWA.

Q1 Dossiers de /dvwa/

wfuzz -w /usr/share/wfuzz/wordlist/general/common.txt --hc 404 http://127.0.0.1/dvwa/FUZZ

Dossiers (code 301) : config, database, docs, external, tests. Remarque : un bug d'affichage de wfuzz 3.1.0 montre quand même les 404 ; filtrer soi-même sur les codes 301/200.

Q2 Fichiers de /dvwa/dvwa/css

La wordlist d'extensions par défaut n'a pas .css ; créer sa liste :

printf ".css\n.php\n.html\n" > ~/ext.txt
wfuzz -w .../common.txt -w ~/ext.txt --hc 404 http://127.0.0.1/dvwa/dvwa/css/FUZZFUZ2Z

Fichiers trouvés (200) : help.css, login.css, main.css, source.css. Deux points d'injection = FUZZ et FUZ2Z.

Q3 Wordlist des vulnérabilités Apache

find /usr/share/wfuzz/wordlist -iname "*apache*"/usr/share/wfuzz/wordlist/vulns/apache.txt.

fait

Exo 4 — Injection SQL (DVWA low)

Contourner le filtre, extraire des données système.

Code vulnérable : $id = $_REQUEST['id']; $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';". L'entrée est concaténée sans échappement.

Q1 Afficher tous les utilisateurs

Payload : 1' OR '1'='1. La condition '1'='1' est toujours vraie, le WHERE ne filtre plus : les 5 utilisateurs sortent (admin, Gordon Brown, Hack Me, Pablo Picasso, Bob Smith).

Q2 Afficher la version de la base

Payload : ' UNION SELECT @@version, database() -- -. UNION ajoute une 2e requête (même nombre de colonnes) ; on récupère 8.0.46-0ubuntu0.22.04.4 et la base dvwa. Le -- - commente la fin.

Q3 Sécuriser

Requêtes préparées avec paramètres liés (PDO/mysqli) : la valeur est traitée comme donnée, jamais comme code. + typer $id en entier + moindre privilège du compte MySQL. Teste la « Version corrigée » dans la démo ci-dessus.

fait

Exo 5 — Injection de commande (DVWA low)

De ls jusqu'aux identifiants de la base.

Code vulnérable : $target = $_REQUEST['ip']; $cmd = shell_exec('ping -c 4 ' . $target);. Aucun filtrage.

Q1 Tester avec ls

Payload 127.0.0.1; ls → la commande devient ping -c 4 127.0.0.1; ls. Sortie : help, index.php, source. On exécute des commandes arbitraires.

Q2 Répertoire courant

127.0.0.1; pwd/var/www/html/dvwa/vulnerabilities/exec. On se repère pour naviguer en relatif.

Q3 Lire un .htaccess

find / -iname ".htaccess" localise le fichier, accessible en relatif : 127.0.0.1; cat ../api/.htaccess. Il redirige toutes les requêtes vers l'API DVWA sauf les fichiers/dossiers existants.

Q4 Lire la config

Le fichier commence par une balise PHP ouvrante que le navigateur interpréterait : on la saute avec tail -n +2.

127.0.0.1; tail -n +2 ../../config/config.inc.php
# fuite : db_user=dvwa  db_password=Pentest-si5  db_database=dvwa
La leçon

Progression réaliste : confirmer l'exécution (ls) → se repérer (pwd) → explorer (.htaccess) → récupérer des secrets (config). Une seule case mal protégée suffit à remonter jusqu'aux identifiants. Correction : valider (FILTER_VALIDATE_IP), escapeshellarg, éviter l'appel système.

08 — Entraînement

QCM d'entraînement

Teste-toi sur la sécurité web. Pool de questions tirées au hasard, correction et explication immédiates.

Prêt

Pool de 27 questions. Tire un échantillon au hasard, correction immédiate et explication à chaque réponse.

Cartes mémo / clique pour retourner

Lis la question, réponds dans ta tête, puis retourne la carte.

DVWA
C'est quoi DVWA ?
clique pour la réponse ↻
DVWA
Damn Vulnerable Web Application : une appli web volontairement vulnérable pour s'entraîner à détecter, exploiter et corriger des failles. Sur sa propre VM uniquement.
Brute force
Force brute vs dictionnaire ?
clique pour la réponse ↻
Brute force
Force brute = toutes les combinaisons. Dictionnaire = on teste une liste de mots courants (bien plus rapide si le mot de passe est banal, comme admin123).
Dir brute forcing
Comment déduire qu'un dossier existe ?
clique pour la réponse ↻
Dir brute forcing
Par le code de réponse HTTP : 200/301 = existe, 403 = interdit mais présent, 404 = absent. wfuzz teste une wordlist contre l'URL.
wfuzz
Rôle du mot-clé FUZZ ?
clique pour la réponse ↻
wfuzz
Le point d'injection : wfuzz remplace FUZZ par chaque mot de la wordlist. Deux points -> FUZZ et FUZ2Z avec deux -w.
John
Que veut dire le préfixe d'un hash shadow ?
clique pour la réponse ↻
John
Il encode l'algorithme : le préfixe à base de 6 = sha512crypt, 2 = bcrypt, 1 = md5crypt. Le champ suivant est le sel.
John
Comment John casse un hash salé ?
clique pour la réponse ↻
John
Il hache chaque mot du dictionnaire avec le même sel et compare au hash cible. Un hash n'est pas réversible : on ne fait que comparer.
John
Casser un ZIP ou un PDF protégé ?
clique pour la réponse ↻
John
Un outil compagnon (zip2john, pdf2john, office2john, ssh2john...) extrait le hash, que John casse ensuite comme un hash shadow.
SQLi
Cause racine d'une injection SQL ?
clique pour la réponse ↻
SQLi
L'entrée utilisateur est concaténée dans la requête sans requête préparée ni échappement : elle peut contenir du code SQL exécuté par le moteur.
SQLi
Effet de 1' OR '1'='1 ?
clique pour la réponse ↻
SQLi
La condition devient toujours vraie, le WHERE ne filtre plus, toute la table sort. Contournement d'authentification.
SQLi
À quoi sert UNION SELECT ?
clique pour la réponse ↻
SQLi
Coller une 2e requête (même nombre de colonnes) pour exfiltrer des données : version, nom de base, autres tables. Le -- - commente la fin.
SQLi
La protection ?
clique pour la réponse ↻
SQLi
Requêtes préparées (paramètres liés) : la valeur est séparée de la structure, jamais interprétée comme du code. + typage + moindre privilège.
Command injection
Quand est-elle possible ?
clique pour la réponse ↻
Command injection
Quand une entrée non filtrée arrive dans une fonction qui lance une commande shell. Les caractères point-virgule, esperluette, pipe enchaînent des commandes.
Command injection
La protection ?
clique pour la réponse ↻
Command injection
Valider strictement (ex. FILTER_VALIDATE_IP), escapeshellarg, et éviter les appels système au profit d'une fonction native.
Hachage
À quoi sert le sel ?
clique pour la réponse ↻
Hachage
Rendre chaque hash unique même à mot de passe identique, ce qui casse les rainbow tables (tables précalculées).
DevSecOps
L'idée du DevSecOps ?
clique pour la réponse ↻
DevSecOps
Intégrer la sécurité tout au long du cycle (shift left) : revue de code, tests SAST/DAST, dépendances, pas un audit unique en fin de projet.
Éthique
Quand un pentest est-il légal ?
clique pour la réponse ↻
Éthique
Seulement avec autorisation explicite : ta propre machine/VM, ou un mandat écrit. Sinon c'est illégal, quel que soit le but.