vuln-class-deserialization
Unsichere Deserialisierung, verständlich erklärt
Liest eine Anwendung strukturierte Daten aus dem Netz und kann der Angreifer diese Daten formen, kann aus "Lesen" still und leise "fremden Code ausführen" werden. Die Bug-Klasse hinter Dutzenden RCEs.
Worum es geht
Viele Anwendungen schicken strukturierte Daten übers Netz und “lesen sie auf der Gegenseite zurück”. Das Fachwort dafür ist deserialisieren. Stammen die Daten aus dem internen Verkehr (Cache, Queue, Service-zu-Service-Aufruf), ist das unproblematisch. Kommen die Daten aus einer Quelle, die der Angreifer beeinflussen kann (Cookie, HTTP-Header, JSON Web Token, Request-Body), wird die Art, wie die Anwendung sie zurückliest, zur Sicherheitsfrage.
Der Kern: in vielen Sprachen ist “Deserialisieren” nicht bloß
“Felder füllen”. Der Reader instanziiert Klassen, ruft Konstruktoren
auf, führt Hooks wie readObject oder __wakeup aus. Kann der
Angreifer wählen, welche Klassen instanziiert werden, sucht er
solche, deren Konstruktor Seiteneffekte auslöst: Dateien öffnen,
Shell-Befehle ausführen, Code nachladen. Eine Kette solcher Klassen
heißt “Gadget Chain”, und solche Ketten existieren für nahezu
jedes verbreitete Sprach-Runtime.
Wo das vorkommt
Die am häufigsten betroffenen Sprachen und Serialisierer:
- Java. Java ist die Sprache mit der größten Anzahl
dokumentierter Gadget-Chains.
ObjectInputStream.readObject()plus Apache Commons Collections oder eines von Dutzenden anderen Bibliotheken hat Breaches bei PayPal, Cisco, Jenkins, WebLogic, Confluence und mehr verursacht. - Python
pickle. Die Dokumentation sagt explizit “Daten aus nicht-vertrauenswürdigen Quellen niemals unpicklen”. Trotzdem tauchtpicklein API-Endpoints, Caches und Message-Queues regelmäßig auf. - .NET
BinaryFormatter,NetDataContractSerializer,LosFormatter. Microsoft hat alle drei aus Sicherheitsgründen formal deprecated. ASP.NET-ViewState ist die größte Install-Basis. - PHP
unserialize(). Dieselbe Gadget-Chain-Dynamik, greift PHP-Frameworks (Laravel, Symfony, WordPress) über die Klassen an, die Composers Autoloader bereitstellt. - Ruby
Marshal.loadundYAML.loadmit Defaults. Rails-CVEs alle paar Jahre gehen darauf zurück. - Node.js ist per Default meist sicher (JSON hat dieses Problem
nicht), einige unglückliche Bibliotheken (
node-serialize, ältereserialize-javascript-Versionen) reproduzieren es jedoch.
Was der Angreifer tut
Sobald ein Deserialisierungs-Bug erreichbar ist, ist der Rest kurz:
- Runtime identifizieren (oft in Fehlerseiten oder Response-Headern sichtbar).
- Eine veröffentlichte Gadget-Chain für die Runtime plus die im
Classpath sichtbaren Bibliotheken auswählen.
ysoserial(Java) undmarshalsec(Java) sind die kanonischen Werkzeuge; Pendants gibt es für .NET (ysoserial.net) und PHP (PHPGGC). - Payload mit einem Einzeiler erzeugen, der den gewünschten Befehl ausführt.
- Payload an der Deserialisierungsstelle einspielen (Cookie, JWT, HTTP-Body, RMI-Port, JMX-Endpoint).
- Reverse-Shell empfangen.
Schwere für deserialisierungs-getriebene Remote-Code-Execution liegt typischerweise bei 9,8 von 10. EPSS-Werte bekannter öffentlicher Chains bleiben jahrelang hoch, dasselbe Exploit-Binary funktioniert gegen jede verwundbare Instanz.
Wie das behoben wird
Empfohlen: nicht-vertrauenswürdige Daten gar nicht in Formaten deserialisieren, die beliebige Klassen erlauben.
Ersetzen Sie die gefährlichen Serialisierer durch sichere Alternativen:
| Gefährlich | Sichere Alternative |
|---|---|
Java ObjectInputStream |
JSON (Jackson strikt), Protobuf, Avro |
Python pickle |
JSON, msgpack mit strikten Typen |
.NET BinaryFormatter |
System.Text.Json, MessagePack-CSharp |
PHP unserialize |
JSON via json_decode() |
Ruby YAML.load |
YAML.safe_load, JSON |
JSON ist kein Allheilmittel: auch in Jackson und Gson gibt es
“polymorphic deserialization”-Muster, die das Risiko der
Klasseninstanziierung zurückbringen. Strikte Konfiguration
verwenden (kein enableDefaultTyping, kein @JsonTypeInfo mit
Klassennamen-Auflösung).
Lässt sich der Serialisierer wirklich nicht ersetzen (Legacy-Protokoll, das Sie nicht kontrollieren), helfen geschichtete Verteidigungen:
- HMAC-Signatur des Blobs mit einem Server-Secret, und alles ablehnen, was nicht validiert. Der Angreifer kann die Bytes nicht mehr verändern.
- Klassen-Instanziierung beschränken. Javas
ObjectInputFilter(seit JDK 9) erlaubt eine exakte Allowlist akzeptierter Klassen. - Jede Library im Classpath patchen, die eine bekannte
Gadget-Chain hat (
apache-commons-collections,spring-core,snakeyaml,ehcacheund so weiter).
Wie blueredix Deserialisierungs-Befunde meldet
Der Scanner meldet CVEs in Drittanbieter-Software, deren Beschreibung Deserialisierung nennt, und führt Templates aus, die bekannte verwundbare Endpoints (Spring Cloud Gateway, Atlassian, WebLogic) prüfen, sofern ein spezifischer Exploit gut verstanden ist. Befunde verlinken auf die jeweilige CVE und zurück auf Wie man eine CVE liest.
Wir versuchen nicht, Deserialisierungs-Payloads gegen Ihre Anwendung einzuspielen. Das ist Penetration-Testing-Territorium.