Wie funktioniert die Lücke im Java-Zusammenhang?
Der eigentliche Sinn des Lookups ist es, Daten abzufragen, um im Logfile für eine bessere Lesbarkeit zu sorgen. Zum Beispiel kann so bei einem LDAP-Server angefragt werden, wie der Klarname zu dem Usernamen lautet, der gerade einen Login versucht hat.
Weil aber so eine Log-Message von Log4J 2 nicht nur aus Strings, sondern auch aus Objekten besteht und so ein über JNDI abgefragter Wert ein komplexes Objekt sein kann, gibt es die Möglichkeit, dass die Antwort des JNDI-Lookup-Aufrufs ein serialisiertes Java-Objekt enthält. Dazu gehört dann zum Beispiel der Klassenname und die serialisierten Daten.
Findet sich eine Klasse mit dem vorgegebenen Namen im Class-Path auf dem Server, wird ein Objekt dieser Klasse mit den serialisierten Daten instanziiert - der Server hat dann zum Beispiel ein komplett befülltes Objekt der Klasse UserData mit Name, Vorname, Adresse und allen weiteren Daten. Ist die geforderte Klasse aber nicht im eigenen Class-Path vorhanden, können die gegebenenfalls in der JNDI-Lookup-Antwort enthaltenen Informationen verwendet werden, die angeben, in welchen fremden Code-Repository die Klasse zu finden ist. Diese .class-Datei wird dann geladen und an den ClassLoader übergeben, sodass daraus Instanzen instanziiert und befüllt werden können.
Dass dies ein Problem sein kann, ist schon lange bekannt. Oracle hat deshalb in Java 8 vor Jahren eine Systemvariable eingeführt, mit der das Laden von Klassen aus einem Remote-Repository unterbunden werden kann. Allerdings war diese für die ersten Jahre standardmäßig ausgeschaltet, um zu verhindern, dass Programmcode, der sich auf so etwas verlässt, durch ein Update von Java 8 nicht mehr funktioniert.
Das Problem aber ist, dass es dieses Remote-Laden von .class-Dateien gar nicht wirklich braucht. Denn auch ohne dieses Laden von Klassen können Angreifer eine große Menge von bereits vorhandenen Klassen benutzen, indem sie entsprechende Informationen zur Deserialisierung bereithalten. So kann über Umwege zum Beispiel eine als String übergebene .class-Datei irgendwo in den lokalen Class-Path auf dem Server geschrieben werden.
Befindet sich so eine Datei erst mal im Class-Path, wird sie bei jedem Neustart der Applikation auch wieder vom Classloader geladen; das große Problem dabei ist, dass eine Java-Klasse statische Code-Blöcke erlaubt. Diese statischen Code-Blöcke werden bereits beim Laden der Klasse in den Classloader ausgeführt und nicht erst, wenn ein Objekt dieses Typs instanziiert wird oder ein Methodenaufruf darauf stattfindet.
Durch diesen Mechanismus muss sich im eigentlichen Programmcode des infizierten Systems auch keinerlei Referenz auf die Klasse befinden, damit sie ihre Arbeit verrichtet. Und diese Arbeit kann alles sein, was dem lokalem Java-Programm auf dem Server möglich ist, inklusive Syscalls, die irgendwelche Programme ausführen, bis hin zum Aufbauen einer versteckten Webseite, die über einen Browser eine Shell zur Verfügung stellt.
Oder nutzen Sie das Golem-pur-Angebot
und lesen Golem.de
- ohne Werbung
- mit ausgeschaltetem Javascript
- mit RSS-Volltext-Feed
Log4J-Lücke: Warum Log4Shell so gefährlich ist und was (nicht) hilft | Was ist betroffen? Und was hilft gegen Log4Shell? |
denn in diesen Containern befinden sich oftmals eigene Kopien der Java-Bibiliotheken. Es...
Der letzte Teil stimmt. Es entbindet nicht von jeglicher Verantwortung. Allerdings ist...
Die Beispiele bei denen OS wiederholt unsicher ist benötigt es nur aus einem Grund: Zu...
Nicht? Weißt du was bei einem String mit% beim loggen passiert in Python? ...