Hi!
$page = unserialize(base64_decode($_COOKIE[COOKIE_NAME]));
Sowas ist „böse“.
Find ich nicht.
In den Daten von Serialize ist abgelegt, welche Klasse als Objekt genutzt wurde. Manipuliere ich also die in unserialize gefütterten Daten, kann ich beliebig bestimmen, welche Klasse wiederhergestellt und mit den weiteren Eigenschaften gefüllt wird.
Bei allen anderen Variablentypen hat man es tatsächlich nur mit Daten zu tun - aber genau hier beeinflusst man direkt auch den zu nutzenden Code.
Das ist genauso pauschal gesagt wie das obige "böse". Code wird nicht serialisiert und es gibt keinen Weg, dass beim unserialize() neuer Code entsteht. Es werden lediglich Objekte von vorhandenen Klassen mit den serialisierten Eigenschaften wiederhergestellt. Sollte sich der auszunutzende Code nicht bereits im Script befinden, kommt nichts hinzu. Das Problem ist lediglich, wenn im Script $page ein Objekt darstellt (ist hier der Fall), dann kann mit obigem Code $page ein Objekt einer anderen Klasse als vorgesehen werden. Und nur wenn diese andere Klasse gleichnamige Methoden hat, die eigentlich von der geplanten Klasse von $page hätten aufgerufen werden sollen, dann wird der Code der anderen Klasse aufgerufen. Würde $page gar nicht als Objekt behandelt, kommen lediglich die magischen Methoden wie __toString() in Frage.
Wenn an dieser Stelle keine exakte Validierung auf gültige Angaben greift, halte ich das für eine große Sicherheitslücke, wenngleich deren Ausnutzung ohne Frage eine Herausforderung ist, die ggf. Insiderwissen (sprich: Kenntnis des ausgeführten Codes) erfordert.
So pauschal würde ich mich hüten, die Größe der Sicherheitslücke bestimmen zu wollen. Da muss schon einiges zusammenkommen, um ausgenutzt zu werden. Aber ja, Sicherheitslücke bleibt Sicherheitslücke, egal ob sie "groß" oder "klein" ist.
Es liefert einen Variablencontainer zurück, in dem jeder belibige PHP-Variablentyp enthalten sein kann. Der wird in dem Fall $page zugewiesen und fertig ist. Die einzige Code-Ausführung, die mir einfällt, wäre __wakeup() bei Objekten.
Ich kann halt jede beliebige andere Klasse, die dem Skript an dieser Stelle zur Verfügung steht, instanziieren lassen. Wenn Autoloading im Spiel ist, wird das richtig spannend.
Das ist eine der Einschränkungen, es muss sich um bereits vorhandene Klassen handeln. Und das Autoloading muss man auch erst einmal beeinflussen können. Wenn ich das kann, brauch ich keine Kekse, um ungewollten Code ausführen zu lassen, denn dann kann ich gleich den gewüschten Code unterschieben. Aber du zieltest auf __autoload() ab und nicht auf auto_prepend_file. Dann gelten wieder obige Einschränkungen, dass gleichnamige Methoden vorhanden sein müssen.
Eine einfache Lösung gegen das Instantiieren ungewollter Klassen mit dieser Unserialize-Lösung wäre, anschließend die Klasse zu prüfen. Dass alle Eigenschaften wie Benutzereingaben zu behandeln sind, unterscheidet sich nicht vom Deserialisieren anderer Typen.
Lo!