Wissen › Insecure Deserialization / PHP Object Injection
Insecure Deserialization / PHP Object Injection
Nutzerdaten (z. B. aus einem Cookie) werden mit unserialize() verarbeitet – ein Angreifer kann damit beliebige interne Objekte erzeugen und deren Magic-Methoden auslösen.
Lies den Artikel und beantworte am Ende 9 Fragen. Erst wenn alle richtig beantwortet sind, ist die Lektion im Training erledigt.
Serialisierung wandelt ein Objekt in eine speicherbare Zeichenkette um, Deserialisierung baut daraus wieder ein Objekt. Verarbeitet eine Anwendung dabei Daten, die der Angreifer kontrolliert – etwa einen Cookie – mit unserialize(), entscheidet der Angreifer, welche Klasse instanziiert wird und mit welchen Eigenschaften. PHP ruft beim Deserialisieren automatisch bestimmte Magic-Methoden auf (__wakeup(), __destruct()). Enthält eine im Projekt ladbare Klasse in einer solchen Methode eine gefährliche Aktion (Datei schreiben/lesen, Kommandos, DB-Zugriff), lässt sie sich so von außen auslösen – das nennt man PHP Object Injection.
Wie der Angriff funktioniert
- Ein Endpunkt übergibt angreiferkontrollierte Daten direkt an unserialize() – klassisch der Wert eines Cookies, aber auch POST-Felder oder URL-Parameter.
- Der Angreifer baut eine serialisierte Zeichenkette, die ein Objekt einer im Projekt vorhandenen ('ladbaren') Klasse beschreibt, und setzt dessen Eigenschaften frei.
- Beim unserialize() wird das Objekt erzeugt und __wakeup() läuft sofort – noch bevor die Anwendung die Daten überhaupt prüft. __destruct() folgt am Ende des Requests.
- Nützliche Klassen mit gefährlichen Magic-Methoden heißen 'Gadgets'; mehrere verkettet ergeben eine 'POP-Chain' (Property-Oriented Programming) bis hin zu RCE.
Varianten
Beispiel
Der Unterschied ist, WEM die zu deserialisierenden Daten gehören:
// verwundbar: Cookie-Wert direkt deserialisieren
$data = unserialize($_COOKIE['sel']); // Angreifer bestimmt die Objekt-Struktur
// ein 'Gadget' im Projekt, das beim Aufwachen etwas Gefaehrliches tut
class Report {
public string $datei = '';
public function __wakeup() { file_put_contents($this->datei, '...'); }
}
// sicher: kein unserialize auf Fremddaten – JSON nutzen
$data = json_decode($_COOKIE['sel'], true);
// oder, wenn unserialize unvermeidbar ist, Klassen verbieten:
$data = unserialize($roh, ['allowed_classes' => false]);
Mögliche Auswirkungen
- Abfluss interner Daten: ein Gadget liest/schreibt Dateien und legt Geheimnisse an erreichbarer Stelle ab.
- Manipulation von Programmzustand: beliebige Objekte mit angreifergewählten Eigenschaften gelangen in den Ablauf.
- Remote Code Execution: über eine passende POP-Chain lässt sich im schlimmsten Fall beliebiger Code ausführen.
- Der Einstieg braucht keine Anmeldung, wenn der verwundbare Endpunkt öffentlich ist (z. B. ein FE-Plugin-Cookie).
Selbst prüfen: Wo deserialisiere ich Fremddaten?
Die Abwehr beginnt mit einer Bestandsaufnahme im eigenen Code. Die folgenden Schritte zeigen, wo unsichere Deserialisierung sitzt und wie man sie entschärft – ausschließlich am eigenen Projekt.
1. unserialize() und phar-Pfade finden
Durchsuche den eigenen Code und die Extensions nach unserialize( sowie nach Dateifunktionen mit nutzerbestimmten Pfaden. Jede Fundstelle gegen die Herkunft der Daten prüfen.
2. Stammen die Daten aus dem Request?
Cookies, POST-Felder, URL-Parameter und Uploads gelten als angreiferkontrolliert. Auf solche Daten darf unserialize() nicht angewendet werden.
3. Auf JSON umstellen
Für eigene Persistenz in Cookies/Feldern json_encode/json_decode verwenden. JSON transportiert nur Daten, keine Objekt-Typen – es gibt keine Magic-Methode zum Auslösen.
// statt serialize/unserialize
$cookie = json_encode($data);
$data = json_decode($roh, true); 4. Unvermeidbares absichern
Ist unserialize() nicht zu vermeiden, mit ['allowed_classes' => false] (oder einer engen Liste) deserialisieren und den Wert zusätzlich per HMAC signieren, damit Manipulation auffällt.
$data = unserialize($roh, ['allowed_classes' => false]); Worauf du in TYPO3 achten musst
In TYPO3 steckt die Gefahr selten im Core-Standard, sondern in Extensions, die eigene Zustände in Cookies oder Feldern serialisieren und ungeprüft zurücklesen. Der Objekt-Graph des gesamten geladenen Projekts (Core, Extensions, Composer-Pakete) steht als Gadget-Fundus zur Verfügung.
unserialize() gehört nicht an Fremddaten
Cookies, Request-Parameter und Uploads sind angreiferkontrolliert. ceselector 4.0.1 z. B. liest einen Plugin-Cookie per unserialize() zurück (CVE-2026-46725) – das reicht für Object Injection, noch bevor irgendeine Prüfung greift.
JSON statt serialize
Für eigene Persistenz in Cookies/Feldern json_encode/json_decode verwenden. JSON transportiert nur Daten, keine Objekt-Typen – es gibt keine Magic-Methode zum Auslösen.
allowed_classes, wenn es sein muss
Ist unserialize() unvermeidbar, mit dem Options-Parameter ['allowed_classes' => false] (oder einer engen Liste) deserialisieren, damit gar keine beliebigen Objekte entstehen. Zusätzlich serialisierte Werte signieren (HMAC), damit Manipulation auffällt.
Schutzmaßnahmen
- Niemals unserialize() auf Daten anwenden, die aus Request/Cookie/Upload stammen.
- Für eigene Persistenz JSON nutzen (json_encode/json_decode) statt serialize/unserialize.
- Wenn unserialize() unvermeidbar ist: ['allowed_classes' => false] setzen und den Wert zusätzlich per HMAC signieren.
- Core/Extensions aktuell halten (hier: ceselector ≥ 4.0.2 bzw. der jeweilige Security-Fix-Branch).
- phar://-Deserialisierung bedenken: keine nutzerbestimmten Pfade an Dateifunktionen übergeben.
Lektion abschließen: 9 Fragen beantworten
Diese Lektion gilt im Training erst als erledigt, wenn du alle 9 Fragen zu diesem Artikel richtig beantwortet hast – von leicht bis knifflig. Dafür brauchst du ein Konto, damit dein Fortschritt gespeichert wird.
Interaktiv üben
In der Lernplattform kannst du diese Schwachstellenklasse an einer echten, isolierten TYPO3-Instanz nachvollziehen: