Elementrica
03Fallstudien04Referenzen05Unternehmen06Aktuelles07Kontakt
PLENDE

Wir haben ein Paket hochgeladen. Wir bekamen Root.

Penetrationstest
Wir haben ein Paket hochgeladen. Wir bekamen Root.

Der Kunde gab uns einen Umfang in einem Satz: Prüfen Sie die aus dem Internet erreichbare Webanwendung. Die Mail hatte DMARC auf Ablehnen gesetzt, der Verkehr lief über TLS 1.3, die Anmeldung sperrte nach einer Reihe von Fehlversuchen, und in der Anwendungslogik fanden wir keine einzige Rechteausweitung.

Trotzdem übergab uns ein einziger Knopf "Paket hochladen" den ganzen Server, mit Root-Rechten, ohne einen einzigen fortgeschrittenen Trick. Und das dafür nötige Konto musste kein Administratorkonto sein.

Wie eine gewöhnliche Funktion zum Hochladen eines Dateipakets zu Remote Code Execution wurde, zeigen wir hier, mit einer Abbildung auf MITRE ATT&CK.

Kontext

Wir stießen auf eine Anwendung, die vieles richtig machte. Der gesamte Verkehr lief über HTTPS, mit HSTS und erzwungener Weiterleitung von HTTP. Zertifikat und Chiffre waren aktuell. Passwörter folgten einer strengen Richtlinie, und ein Konto sperrte nach einigen misslungenen Anmeldungen, Brute Force fiel also sofort weg. Im Session-Cookie steckte das Präfix __Host-, in den Requests liefen Anti-CSRF-Tokens mit. Wir fanden keine SQL-Injection, kein IDOR, und in der Anwendungslogik selbst ließ sich weder eine horizontale noch eine vertikale Autorisierung überspringen.

Wir waren nicht auf einen löchrigen Zaun gestoßen, sondern auf eine Mauer, die jemand mit Bedacht gebaut hatte. Und je gleichmäßiger die Ziegel liegen, desto größer die Versuchung, den einen zu finden, der wackelt.

Eine der Funktionen der Anwendung erlaubt das Hochladen von Dateipaketen, gewöhnliche ZIP-Archive: ein Manifest und ein Satz Ressourcen, darunter Web-Inhalte (HTML, JavaScript, CSS). Wer das Paket importiert, bestimmt, was das Archiv enthält. Und das ist das ganze Geheimnis dieser Geschichte.

Herausforderung

Der Haken an einem solchen System ist tückisch, denn das Hochladen von Paketen ist kein Fehler. Es ist eine gewollte Funktion, kein Defekt. Man kann sie nicht "abschalten", so wie man in einem Unternehmen, das von Korrespondenz lebt, den Briefkasten nicht abschafft. Die Schwierigkeit liegt nicht darin, dass ein Nutzer eine Datei hochladen kann. Sie liegt darin, wo diese Datei landet und wofür der Server sie hält.

Der Inhalt eines solchen Pakets ist nicht vertrauenswürdig. Er sollte neben der Anwendung liegen wie ein Foto im Album, als statische Ressource, die der Browser allenfalls anzeigt. In dieser Anwendung landete er im Verzeichnis der aktiven Anwendung, an genau der Stelle, aus der ein auf Apache Tomcat basierender Server JSP-Dateien auf Anfrage kompiliert und ausführt. Das Paket sollte also ein Bild im Album sein und wurde zu einem Programm, das der Server bereitwillig ausführte.

Dazu kam eine zweite Sache, die man leicht übersieht. Der Import verlangte Rechte zur Inhaltsverwaltung, nicht Administratorrechte. Das klingt harmlos. In der Praxis heißt es, dass die Person, deren Aufgabe das Einstellen von Inhaltsdateien ist, einen Weg zur Ausführung von Betriebssystembefehlen bekam. Der Abstand zwischen "ich kann ein Paket hochladen" und "ich bin Root" sollte unendlich sein. Hier betrug er einen Upload.

Was wir getan haben

Wir arbeiteten im Grey-Box-Modell, mit Beispielkonten und Grundwissen über die Infrastruktur, nach der OWASP-Methodik. Zuerst die Informationsbeschaffung: Wir bildeten den Stack ab (eine Java-Anwendung auf einem Tomcat-basierten Server, eine Postgres-Datenbank) und alle Stellen, an denen ein Nutzer Daten eingibt. Danach nahmen wir uns die Funktion für den Paket-Import vor.

Wir bauten ein korrektes Paket. Nichts Exotisches, ein korrektes Manifest und zwei zusätzliche Dateien:

paczka.zip
├── manifest.xml
├── index.html
└── proof.jsp

Der Import-Mechanismus blockierte die JSP-Datei im Archiv nicht. Das Paket wurde vollständig entpackt, und alle Dateien wurden als Paket-Ressourcen verfügbar. Das Hochladen allein führte noch nichts aus. Zur Ausführung kam es, als wir den Inhalt des hochgeladenen Pakets öffneten und der Server nach der JSP-Datei griff. Statt sie als Text zurückzugeben, ließ er sie durch die JSP-Engine laufen und führte sie auf seiner Seite aus.

Die Ausgabe des Befehls id beendete das Thema:

$ id
uid=0(root) gid=0(root) grupy=0(root)

Die JSP-Datei wurde nicht als statische Paket-Ressource ausgeliefert. Sie wurde vom Anwendungsserver interpretiert und ausgeführt, mit Root-Rechten. Zur Sicherheit stellten wir zusätzlich eine ausgehende Verbindung zu einem von uns kontrollierten Host her, und der Server meldete sich ohne Widerstand bei uns. Wir hatten Befehlsausführung und ausgehenden Verkehr von der Maschine. Da der Server-Prozess als Root lief und die Umgebung nicht angemessen abgesichert war, brauchte es keine Ausweitung. Eine einfache Reverse Shell reichte, um den Server samt Zugriff auf Daten und Code zu übernehmen.

Bei der Gelegenheit prüften wir dieselben Einstiegspunkte von der anderen Seite. Statt einer JSP-Datei legten wir eigenes JavaScript in index.html. Der Paket-Inhalt lief im selben Origin wie die Anwendung, ganz ohne Isolierung. Unser Skript las den localStorage der Anwendung, griff auf das übergeordnete Dokument zu und konnte im Kontext der Session des Opfers authentifizierte Requests senden. Öffnete ein Administrator ein solches Paket, konnte das Skript mit seinen Händen ein Konto mit erhöhten Rechten anlegen. Ein Paket, zwei verschiedene Einsätze, je nachdem, was der Angreifer gerade brauchte.

Die ganze Kette, in der Sprache, die das Blue Team spricht:

TaktikATT&CK-TechnikWie es bei uns aussah
ErstzugriffT1566 Phishing / T1078 Valid AccountsEin Konto mit Rechten zur Inhaltsverwaltung und zum Paket-Import. Realistisch per Phishing oder aus einem Datenleck zu bekommen
AusführungT1059 Command and Scripting InterpreterBetriebssystembefehle, ausgeführt über die im Paket eingebettete JSP-Datei
PersistenzT1505.003 Web ShellEine JSP-Datei, die als Web Shell im Verzeichnis der aktiven Anwendung wirkt
ErkundungT1083 File and Directory DiscoveryDurchsicht der Serverstruktur, der Konfigurationsdateien und der Instanzverzeichnisse
Zugriff auf AnmeldedatenT1552.001 Credentials In FilesSuche nach Verbindungsparametern zur Datenbank und kryptografischem Material in Konfigurationsdateien
Ausführung (Client)T1059.007 JavaScriptEin Skript aus dem hochgeladenen Paket, ausgeführt im Origin der Anwendung, im Browser des Opfers
PersistenzT1136 Create AccountAnlegen eines Kontos mit erhöhten Rechten im Namen des Administrators, der das Paket öffnete

Neben der Hauptgeschichte hinterließen wir dem Kunden einige kleinere Dinge zum Aufräumen. Eine Anmeldung, die nach ausgewählten Zeichen der Zugangsdaten statt nach dem Ganzen fragte, ließ sich umgehen, indem man aus dem Request die Parameter entfernte, die angaben, welche Positionen geprüft werden. Drei Query-Parameter spiegelten unsere Daten ohne Kodierung in die Antwort, was ein Reflected XSS ergab. Das Frontend zog veraltete Bibliotheksversionen (jQuery, jQuery UI, TinyMCE) mit bekannten Schwachstellen. Und noch ein Detail zum Nachdenken: Da ein Konto nach einer Reihe von Fehlanmeldungen sperrt, kann das gezielte Sperren der Administratorkonten den Dienst lahmlegen. Eine harte Sperre ist bisweilen ein zweischneidiges Schwert.

Ergebnis

Eine kritische Schwachstelle, Remote Code Execution, voller Zugriff auf den Anwendungsserver mit Root-Rechten, und damit auf Daten und Code. Die gesamte solide Verteidigung ringsum, Mail, TLS, Passwörter, Sessions, verlor in dem Moment ihre Bedeutung, in dem ein einziger Upload Codeausführung auf der Maschine ermöglichte.

Die Empfehlungen hinterließen wir in einer Form, die sich abhaken lässt, denn sie sollen Handlungen sein, keine Wünsche:

  • Hochgeladenen Inhalt außerhalb des Anwendungsverzeichnisses und außerhalb der Laufzeitumgebung des Servers halten, ausschließlich als statische Ressourcen von einem eigenen Origin ausgeliefert.
  • Ausführbare Dateien blockieren, insbesondere JSP, dies aber als zusätzliche Schicht behandeln, nicht als Hauptschutz.
  • Das Archiv zuerst in ein zufälliges temporäres Verzeichnis außerhalb des Stammverzeichnisses des Dienstes entpacken und jeden Eintrag prüfen, unabhängig davon, ob er im Manifest steht.
  • Dateiendungen ohne Rücksicht auf Groß- und Kleinschreibung prüfen, mit Blick auf doppelte Endungen und Unterschiede bei der Pfadnormalisierung.
  • Hochgeladenen Inhalt in einem eingeschränkten iframe mit Sandbox ausführen und die Kommunikation mit der Anwendung über ein kontrolliertes postMessage mit Origin-Prüfung führen.
  • Eine CSP als weitere Schutzschicht setzen, ohne unsafe-inline.
  • Dem Server-Prozess die Root-Rechte entziehen. Ein Recht zur Inhaltsverwaltung darf nicht in Befehlsausführung mit den Rechten des Servers enden.
  • Die in den drei Parametern gespiegelten Daten kodieren und die veralteten Frontend-Bibliotheken aktualisieren.

Wenn Sie eine Plattform betreiben, auf der Nutzer "Inhalt" hochladen können, ein Dokument, ein Paket, eine Vorlage, was auch immer, lohnen sich zwei Fragen. Wo landet dieser Inhalt wirklich, und wofür hält ihn Ihr Server, wenn jemand ihn öffnet? Das prüfen wir gern bei Ihnen.

Ein Upload statt einer Kette von Exploits. Nimmt Ihre Anwendung Dateien von Nutzern an?

Vereinbaren Sie ein Gespräch mit einem Berater. Gemeinsam gehen wir den Umfang eines Tests der Webanwendung durch, die Risiken und wie ein solcher Vektor bei Ihnen aussehen könnte.

Vorheriger
Fünf High-Schwachstellen, kein Weg hinein

Alle Fallstudien sind nach Sektor anonymisiert, ohne Namen, Daten oder Angaben, die den Kunden identifizieren könnten, gemäß der Vertraulichkeit. Wir veröffentlichen niemals echte Schwachstellen oder technische Kundendaten.