Technischer Hintergrund

Im ersten Teil unseres Blogposts haben wir die Herkunft der Log4j- bzw. Log4Shell-Schwachstelle und die Implikationen für das Internet besprochen. In diesem Teil werden wir uns die technischen Hintergründe anschauen, um die Schwachstelle im Detail zu verstehen.

Dabei hilft es immer, den Quellcode zu untersuchen, um festzustellen, wie die Schwachstelle funktioniert. Der folgende Codeabschnitt zeigt die Schwachstelle in Zeile 7:

Quelle: Screenshot https://logging.apache.org/log4j/2.x/manual/api.html

Ohne die verwundbare Log4j-Bibiliothek wäre diese Zeile unproblematisch, da sie nur dafür sorgt, einen bestimmten HTTPHeader (X-Api-Version) zu loggen. Im folgenden Fall entpuppt sich diese Zeile allerdings als ein Einfallstor für Angreifer, um das System vollständig zu kompromittieren und gegebenenfalls erhöhte Privilegien zu erlangen (root). Welche Privilegien erlangt werden, hängt davon ab, welcher Nutzer die Java-Anwendung ausführt.

Aber inwiefern verursacht die ungepatchte Log4j-Bibliothek nun diese Schwachstelle? Um die Antwort herauszufinden, müssen wir etwas tiefer in die Funktionsweise der Log4j-Bibliothek eintauchen. Log4j hat nämlich einige Features, die das Leben eines Programmierers erleichtern können. Im Gegensatz zu einer simplen Aufzeichnung von Zeichenketten, die ein Programm zur Laufzeit generieren kann, gibt es auch einige Steuerzeichen, die genutzt werden können, um besondere Funktionen von Log4j abzurufen. Eine für die Schwachstelle relevante Funktion ist das Lookup-Feature. Mit Lookup können bestimmte Variablen, die mit Steuerzeichen entsprechend gekennzeichnet wurden, mit den dynamischen Werten der Laufzeit ausgefüllt und geloggt werden.

Angenommen, man möchte beim Loginversuch eines Nutzers der Applikation dessen Namen loggen:
Folgende Zeile loggt nur statisch, dass es einen Loginversuch gegeben hat:

Quelle: NSIDE

Dynamisch mit Variablen, die zur Laufzeit abgerufen werden, könnte das Ganze wie folgt aussehen:

Quelle: NSIDE

Die Steuerzeichen ${…} und die Variable env:USERNAME sorgen dafür, dass der aktuelle Nutzer Christian geloggt wird und keine generische Meldung entsteht. Das könnte dazu führen, dass sensible Daten in Logfiles geschrieben werden. In Produktivsystemen sollten sensible Daten niemals in Logfiles geschrieben werden. Allerdings sind diese Daten nicht für den Angreifer sichtbar, außer, es ist eine Remote Code Execution-Schwachstelle.

Log4j bietet zusätzlich zu den Lookups aber auch noch weitere Funktionen, die sich geschickte Angreifer zu Nutze machen und zu einer schwerwiegenderen Schwachstelle kombinieren können. Im Falle der Log4Shell-Vulnerability kombinieren Angreifer Log4j-Lookups mit JNDI (Java Naming and Directory Interface) und LDAP (Lightweight Directory Access Protocol). Zusätzlich zum LDAP-Protokoll sind theoretisch auch andere Protokolle möglich. JNDI ist eine Programmierschnittstelle, die innerhalb von Java für Namens- und Verzeichnisdienste zuständig ist. Trotz der vielen verschiedenen Komponenten, die von den Angreifern genutzt werden, sind die Payloads üblicherweise kurz und simpel.

Anhand eines Beispiels können wir den Angriff genauer erklären:

Quelle: NSIDE

Diese Payload veranlasst Log4j mittels der Steuerzeichen ${…} das jndi-Interface zu nutzen, um eine Anfrage an den LDAP-Server mit der Adresse attacker.com zu versenden. Das Ziel der URL ist exploit.class, die eine bösartige Java-Klasse darstellt, die Angreifer als Shell nutzen können. Über diesen Umweg wird es für den Angreifer möglich, eigenen Java-Code (exploit.class) auf dem Server auszuführen. Beliebiger Schadcode kann vom Server (attacker.com), der vom Angreifer kontrolliert wird, abgerufen werden. Das System kann somit vollständig kompromittiert werden. Zur weiteren Veranschaulichung kann man auf Livedaten eines Honeypots zugreifen und ermitteln, wie sich Payloads „in-the-wild“ weiterentwickeln.

PoC

Um einen potenziellen Angriff nachzustellen, hat die NSIDE eine verwundbare Testumgebung genutzt, um die Schwachstelle zu analysieren.

(Quelle Testumgebung: https://github.com/jsnv-dev/yet_another_log4j_POC_standalone)

Hier besteht der Angriff aus mehreren Komponenten:
Ein LDAP- und HTTP-Server sind erforderlich, um Anfragen derart zu manipulieren und umzuleiten, dass die verwundbare Anwendung dazu gebracht wird, eine vom Angreifer definierte Schadsoftware auszuführen. Im folgenden Screenshot werden daher vom Angreifer ein HTTP- und ein LDAP-Server gestartet, die nun gemeinsam auf eine Anfrage der verwundbaren Anwendung warten. Die verwundbare Anwendung läuft währenddessen im Hintergrund.

Quelle: NSIDE

Der Angreifer führt nun seinen Exploit aus, der die verwundbare Codezeile (logger.info([…]) von oben ausnutzt und den HTTP-Header, X-Api-Version, gezielt angreift.

Quelle: NSIDE

Als Resultat geht eine Anfrage der verwundbaren Applikation bei den vom Angreifer kontrollierten LDAP- und HTTP-Server ein, die mit einer Schadsoftware bzw. Payload des Angreifers beantwortet wird.

Quelle: NSIDE

Daraufhin erhält der Angreifer durch die hier genutzte Payload eine root-Shell auf dem verwundbaren System, die es ihm erlaubt, beliebige Befehle auszuführen und das System vollständig zu kompromittieren. Eine root-Shell wird nur dann erzeugt, wenn die verwundbare Anwendung mit root-Rechten läuft und stellt den Worst Case dar.

Quelle: NSIDE

Abschließend lässt sich feststellen, dass die große Gefahr dieser Schwachstelle sich daraus ableitet, wie einfach sie auszunutzen ist und gleichzeitig, wie schwerwiegend der potenzielle Schaden sein kann. Aufgrund der weiten Verbreitung von Log4j sollten alle Java-Nutzer sofort überprüfen, inwiefern ihre Anwendungen verwundbar sind, um größeren Schaden abzuwenden.
Einen Schnelltest findet man hier.
Besser ist es jedoch, alle Systeme ausführlich von einer spezialisierten Firma untersuchen zu lassen, um weniger offensichtliche Angriffsvektoren ausfindig zu machen.

Bitte wenden Sie sich hierzu an uns über info@nsideattacklogic.de.