File Inclusion Vulnerability (LFI)
Selamlar, ben Esat. Bu yazımda LFI (Local File Inclusion) açığını ele alacağız ve PortSwigger üzerindeki labların çözümünü gerçekleştireceğiz.İyi okumalar dilerim!Bu yazı, web uygulamalarındaki dosya dahil etme (LFI) açıklarını anlamak ve örneklerle pekiştirmek isteyenler için hazırlanmıştır.
Path Traversal olarak da bilinen bu zafiyet, sistem üzerindeki dosyaların yetkisiz bir şekilde okunması ve elde edilen bilgilerin kötüye kullanılması şeklinde açıklanabilir.
Saldırı, genel olarak dosyalara dinamik olarak erişim için tasarlanmış uygulamalar üzerinde görülür. Örneğin, görsellere erişim için tasarlanmış bir API’de filtreleme ve güvenlik önlemleri yetersizse, sunucu üzerindeki /etc/passwd veya id_rsa gibi kritik dosyalara erişim sağlanabilir. Saldırı daha da ilerletilerek sunucuya tam erişim elde edilebilir.
Örnek bir saldırı olarak şu gösterilebilir:
https://www.esatbaba.com/?image=../../../../../etc/passwd
Bu payload yazının başlangıcında anlamsız görünebilir; ancak yazıyı okuduktan sonra neyi amaçladığımızı çok daha iyi anlayacaksınız.
LFI Nasıl Ortaya Çıkar?
Bu kod parçası, dinamik olarak bir sayfayı önümüze getirmeyi amaçlıyor; ancak herhangi bir filtreleme işlemi uygulanmamış ve bir denetim söz konusu değil. Saldırganın doğal yaklaşımı, normal kullanıcılar gibi web sitesi üzerindeki sayfalara erişmek yerine, sistem üzerindeki kritik dosyalara erişmek olacaktır.
Peki bu nasıl gerçekleşebilir?
Saldırgan, üst dizinlere çıkmak için “../” karakterlerini kullanacaktır. Genellikle bu zafiyetin tespiti, Linux tabanlı bir sistem üzerinde yapılıyorsa, her Linux sistemde bulunan sabit bir dosya olan /etc/passwd dosyasına erişim sağlanarak gerçekleştirilir. Bunun için saldırganın “../../../../etc/passwd” gibi bir payload kullanılması muhtemeldir.
Not: “../” karakterlerinin çok fazla tekrar edilmesi, kök dizine erişildikten sonra bir anlam ifade etmeyecektir. Örneğin, kök dizinin 10 dizin üstündeyseniz ve bu payloadı 20 kez girseniz bile, sonuçta yine kök dizine ulaşmış olursunuz; çünkü kök dizinin üzerinde başka bir dizin bulunmamaktadır.
Gerçek Lab Deneyimi (PortSwigger)
Kullanılan Lab:
Gelin birlikte bu labı çözelim:
• Labda laboratuvara giriş yapmadan önce Burp Suite Community uygulamasından faydalanacağız.
• Burp Suite; web uygulama güvenliğini test etmek için kullanılan bir platformdur. PortSwigger şirketi tarafından geliştirilmiş ve Java programlama diliyle yazılmıştır.
• Laboratuvara giriş yaptığımızda Burp Suite Community uygulaması da açıkken Proxy → HTTP History alanında hedef üzerinde yapılan tüm işlemlere ait bağlantı bilgileri görüntülenir.
Lab 1: Dosya Yolu Geçişi – Basit Durum
1-) Laboratuvara giriş yaptığımızda Burp Suite’de “GET” komutu olan istekleri incelememiz gerekiyor çünkü bu isteklerde kullanıcıdan alınan parametreler URL içinde açıkça görünür. Bu da manipülasyon yapmayı ve sonuçlarını gözlemlemeyi kolaylaştırır.
2-) İlk laba girdiğimizde “GET” metodundaki istekleri incelerken “/image?filename=…” tarzı bir istek fark ettik. Bu tür parametreler genellikle dosya çağırır. Burada filename değerini değiştirerek sunucunun başka dosyaları da getirip getirmediğini test edebiliriz.
3-) Bu payloadda deneme yapmak için öncelikle görselde gördüğüm “/image?filename=70.jpg” isteği üzerinde deneme yapalım.
4-)Görseldeki isteğe sağ tıkla → Send to Repeater diyerek Repeater sekmesine geçiş yapalım.Burada siteye bazı parametreler göndererek bazı bilgileri karşı taraftan almaya çalışacağız.
5-) Repeater sekmesinde Request tarafında işlem yapacağımız “GET /image?filename=70.jpg” yi gördük.Şimdi burada küçük bir oynama yaparak “GET /image?filename=../../../etc/passwd” parametresini yazıp “Send” tuşuna basarak Response tarafını inceliyoruz.
Bu parametreyle sunucunun etc/passwd dosyasını okumasını istedik ve başarıyla içerik döndü: Aslında küçük gibi görünen bir kod hatası ne gibi sonuçlara yol açabiliyor böylece görmüş olduk
Bazı durumlarda sunucular bu tür “../” gibi dizin atlama karakterlerini engeller.Bu durumda neler yapabileceğimizi 2. labı çözerek uygulayalım.
ÖZET:
Amaç: Uygulamanın, kullanıcıdan gelen filename parametresiyle sunucudaki dosyaları okumasını sağlamakKullanılan Teknik: Dizin geçişi ‘path traversal’ kullanılarak, “../” dizinleriyle üst klasörlere çıkılarak hassas dosyalara erişim.
Sonuç: “filename=../../../etc/passwd” gibi bir parametre ile /etc/passwd dosyasının içeriği elde edildi.
Lab 2: Dosya Yolu Geçişi – Dizin Geçiş Dizileri Engellenmiş
• İlk labda yaptığımız gibi aşamaları yapıp repeater sekmesine gelelim.
• Burada önceki denediğimiz ../../../etc/passwd parametresiyle istek göndermeyi deneyelim.
• Görüldüğü üzere önceki yaptığımız parametre burada işe yaramadı.Alternatif istek gönderme yolu olarak “/etc/passwd” parametresini deneyelim .
Ve bu parametre ile sistem dosyalarını yine okuyabilmiş olduk.
ÖZET:
Amaç: Uygulama, ../ gibi dizin geçiş dizilerini engelliyor; bu engeli aşarak hassas dosyalara erişmek.Kullanılan Teknik: Mutlak yol kullanımıyla engeli aşmak.
Sonuç: “filename=/etc/passwd” parametresiyle doğrudan hassas dosyaya erişildi.
Lab 3: Dosya Yolu Geçişi – Dizin Geçiş Dizileri Tekrarlı Olarak Kaldırılıyor
•3.labda önceki iki parametreyi uyguladığımızda sistem dosyalarını bize vermeyecektir.Bu durumda başka alternatif yöntem olan “Ters slash”’le deneme yöntemi uygulanabilir.Bu parametre “ ….//….//….//etc/passwd” ile denenebilir.
Peki Neden Bu Yöntemi Yapıyoruz?
• Burada sunucu ../ gördüğünde siler ve sunucu bu işlemleri yaptığında geriye yine “../../../etc/passwd” kalmış olur ve filtreyi geçerek başarıyla baypass etmiş oluruz.
• Böylece sistem sosyalarını görüntüleyerek labı çözmüş olduk.Peki ya bu denediğimiz yöntemler işe yaramazsa ne yapabiliriz?
ÖZET:
Amaç: Uygulama, ../ dizin geçişlerini tekrarlı olarak kaldırıyor; bu engeli aşmak.
Kullanılan Teknik: Alternatif dizin geçiş dizileri kullanmak, örneğin ….// gibi.
Sonuç: “filename=….//….//….//etc/passwd” parametresiyle /etc/passwd dosyasına erişildi.
Lab 4: Dosya Yolu Geçişi – Fazladan URL Kod Çözme ile Dizin Geçiş Dizileri Kaldırılıyor
Denediğimiz 3 yöntem de burada çalışmadığını denediğimizde görmüş olacağız.
Peki bur durumda ne yapılabilir?
• Eğer klasik “../../../../etc/passwd” işe yaramazsa, bu karakterlerin encode edilerek sunucuya daha “temiz” iletilmesi gerekebilir. Burp Suite’te bu işlemler şöyle yapılır:
1-)Repeater sekmesindeki parametreyi seç
• Sağ tıkla → Convert Selection → URL → URL–encode all characters diyerek böyle bir görünüm almış oluruz ve bunu göndermeye çalışalım
Yine elimize sistem bilgileri geçemedi ama pes etmek yokk!!!
• Web uygulamaları bazen gelen verileri filtrelerken yalnızca ilk decode işlemini yapar ve sonra çıkan sonuca bakar.Yani:
-İlk olarak %2e%2e%2f → ../ olur (ilk decode)
-Ama bu hali filtreye yakalanırsa, uygulama bunu engeller.
Peki bu durumda ne yapabiliriz?
• Bu gibi durumlarda çift encode (double URL encoding) yapmak, bazı filtreleme sistemlerini atlatmak için kullanılır.
• Biz bu % karakterlerini de encode ederek, filtreyi bir adım geride bırakırız.
Sunucu Tarafı Ne Yapıyor?
Sunucu gelen isteği şöyle işler:
• İlk olarak otomatik olarak bir decode işlemi yapar.
• Bizim payload’umuz hâlâ encode’lu görünür (ama aslında artık “../” haline gelmiştir).
• Filtre bu haliyle göremez, biz de hedef dosyaya ulaşırız.
*Gerçek hayata uyarlamak istesek;
Diyelim ki bir binaya girmek istiyorsunuz ve güvenlik kamerası yüzleri tarıyor. Siz önce yüzünüze bir maske takıyorsunuz, sonra üstüne bir kask geçiriyorsunuz.
• Kamera sadece dıştaki kaska bakıyor → temiz.
• Ama altında maske var → sizi tanıyamıyor.
• İçeri sızdınız.😎
Biz de burada encode edilmiş ../../../../etc/passwd parametresini bir daha encode etme işlemleri uygulayarak isteği tekrar göndermeyi deneyeceğiz.
*Ve böylece engellemeden kurtulup istediğimiz sistem dosyalarını yine okuyabilir mevkiye varmış olduk!!!🥳🥳🥳
ÖZET:
Amaç: Uygulama, URL kod çözme işlemi uygulayarak dizin geçiş dizilerini kaldırıyor; bu engeli aşmak.Kullanılan Teknik: Çift URL kodlama kullanmak.
Sonuç: “filename=%252e%252e%252f%252e%252e%252fetc%252fpasswd” parametresiyle /etc/passwd dosyasına erişildi.
Lab 5: Dosya Yolu Geçişi – Yol Başlangıcının Doğrulanması (Path Traversal – Validation of Start of Path):
1-)İlk izlenim olarak uygulama, ürün görselini aşağıdaki gibi bir URL ile getiriyor:
https:///image?filename=product.png
• Biz bu filename parametresini kontrol ettiğimizde, bu değerin “/var/www/images/” klasörü içinde bir dosya aradığını fark ediyoruz.
• Bu laboratuvardaki hedefimiz, bir resim görüntüleme sistemini kullanarak sistemin içerisindeki “/etc/passwd” dosyasını dışarı sızdırmak. Çünkü bu dosya sistemde gerçekten varsa, çıktısı sayesinde LFI açığının varlığını kolayca doğrulayabiliriz. Ancak bu sefer işler biraz daha karışık.Çünkü uygulama,dosya yollarının belirli bir klasörden başladığını kontrol ediyor!
• Uygulama yalnızca “/var/www/images/” altında dosya açmaya izin veriyor. Biz de bu dizinin dışına çıkmak için klasik “../” (bir üst klasöre çık) dizin geçişlerini kullanıyoruz
Bu yönteme klasik sıçrama(directory traversal) tekniği de denir
Bu,şu anlama gelir:
• ../ → bir üst klasöre çık.
• ../../../→ üç seviye yukarı çıkarak / kök dizinine var.
• Sonrasında etc/passwd dosyasına ulaş.
Ama bu tek başına işe yaramadı.
• Uygulama,gönderilen parametrenin tam yolunu kontrol ediyor ve dosya yolunun /var/www/images/ ile başladığını doğruluyor. Bu yüzden sadece ../../../etc/passwd gönderdiğimizde, uygulama bu dosyanın var olduğunu kabul etmiyor çünkü tam yol şu oluyor;
“/var/www/images/../../../etc/passwd” (Baypass için yolun başına /var/www/images/ ekledik)
• Burada böylece filename parametresine bu değeri verdiğimizde uygulama “bu değer /var/www/images/ ile başlıyor mu?” kontrolünü geçiyor.
•Ve bu parametreyi gönderdiğimizde bize geri dönüş olarak istediğimiz gelmiş oluyor!!!
Tebrikler.Şimdi bizi bekleyen son labı çözmeye çalışalım 🥳🥳🥳
ÖZET:
Amaç: Uygulama, dosya yolunun belirli bir dizinle başlamasını zorunlu kılıyor; bu kontrolü aşmak.Kullanılan Teknik: Geçerli başlangıç yolunu ekleyerek dizin geçişi yapmak.
Sonuç: “filename=/var/www/images/../../../etc/passwd” parametresiyle /etc/passwd dosyasına erişildi.
Lab 6: Dosya Yolu Geçişi – Boş Bayt Atlama ile Dosya Uzantısının Doğrulanması:
• Bu senaryoda açıklamada “Uygulama, verilen dosya adının beklenen dosya uzantısıyla bittiğini doğrular.” demesinden anlaşılır ki uygulama, dosya adının belirli bir uzantı (örneğin .png) ile bitip bitmediğini kontrol ediyor. Ancak biz bu kontrolü kandırıp başka bir dosya (örn. /etc/passwd) okumak istiyoruz.
• İlk olarak normal kullandığımız payloadları yine de denemekten zarar gelmez. • Bu işe yaramadıysa bir de şunu deniyelim
• Bu sefer sistem dosya uzantısı kontrolünü geçti ama /etc/passwd.png diye bir dosya aradığı için yine hata verdi.
ÇÖZÜM:
• Bazı eski veya yanlış yapılandırılmış sunucularda, C tabanlı dosya okuma fonksiyonları “%00” yani null byte (boş bayt) karakterini görünce dosya adını orada keser.
Yani;
Bu durumda:
• Sunucu tarafındaki filtre “.png” ile bitiyor mu?” → Evet diyor
• Sunucudaki dosya okuma fonksiyonu ise “%00”<s/trong>’ı görünce dosya adını şurada kesiyor: ../../../etc/passwdSonuç: “/etc/passwd” dosyasını başarıyla okuyoruz.
• Bu tür bir payload’ı normal tarayıcı üzerinden göndermek mümkün olmayabilir çünkü %00 karakteri bazı sistemler tarafından engellenebilir.
*Bu yüzden Burp Suite kullanıyoruz,çünkü:
– İsteği elle düzenleyebiliyoruz,
– Raw olarak “%00” gibi özel karakterleri gönderebiliyoruz,
– Yanıtın içeriğini direkt inceleyebiliyoruz.
•Böylece dosyanın gerçekten etc/passwd olduğunu kanıtlıyor. Demek ki uygulama uzantı kontrolünü doğru yapamıyor.
Bu Lab’de Neyi Öğrendik?
• Uygulama filtrelerini kandırmak için null byte (%00) gibi teknikler kullanılabilir.
• Yüzeyde güvenli gibi görünen uzantı kontrolleri, arka planda nasıl çalıştığına göre kolayca atlatılabilir.
• ‘Burp Suite’ gibi araçlar bu tür testler için çok esnek ve etkilidir.
ÖZET:
Amaç: Uygulama, dosya adının belirli bir uzantıyla bitmesini zorunlu kılıyor; bu kontrolü aşmak.Kullanılan Teknik: Null byte (%00) kullanarak uzantı kontrolünü atlatmak.
Sonuç: “filename=../../../etc/passwd%00.png” parametresiyle “/etc/passwd” dosyasına erişildi.
LFI’nin Tehlikeleri Nelerdir?
LFI (Local File Inclusion), doğrudan OWASP Top 10 listesinde yer almasa da, hala web uygulamalarında sıkça karşılaşılan ve önemli güvenlik açıklarından biridir. Özellikle Injection türündeki açıklara benzer şekilde, kötü niyetli kullanıcıların dosya yolu manipülasyonu yaparak sistemdeki hassas verilere erişmesine veya zararlı komutlar çalıştırmasına olanak tanıyabilir.Bu yüzden LFI açıkları, saldırganlara aşağıdaki imkanları sağlayabilir:• Hassas Dosyaların Okunması: Örneğin, Linux sistemlerdeki “/etc/passwd” dosyasının içeriği görüntülenebilir.(Bizim pratik yaptığımız yer burası oluyor.)
• Yapılandırma Dosyalarına Erişim: Uygulamanın yapılandırma dosyaları okunarak, veritabanı erişim bilgileri gibi hassas veriler elde edilebilir.
• Sunucuya Yetkisiz Erişim: Okunan sakıncalı veriler neticesinde (örneğin Id_rsa dosyası veya cleartext olarak saklanan şifrelerin okunması) sunucuya erişim gibi senaryolar doğurabilir.
LFI’den Nasıl Korunulur?
LFI saldırılarının tehlikesini sınırlamak ve daha güvenli web uygulamaları geliştirmek oldukça önemlidir.LFI açıklarını önlemek için aşağıdaki önlemler alınabilir:
•Girdi Doğrulama: Kullanıcıdan alınan dosya adları, önceden tanımlanmış bir listeyle karşılaştırılmalı ve sadece bu listede olan dosyaların dahil edilmesine izin verilmelidir.
Dosya Yollarını Sabitleme: Dosya yolları sabitlenmeli ve kullanıcıdan alınan girdiler bu yollara eklenmeden önce kontrol edilmelidir.
Yazımın başlarında güvenli olmayan bir kod görseli görmüştünüz,hatırladınız mı?
Buradaki Açık Nerede?
• $page değişkeni doğrudan kullanıcının girdiği değeri alıyor ($_GET[‘sayfa’]).
• Hiçbir filtreleme veya doğrulama yapılmadan include fonksiyonuna veriliyor.
• Bu şu anlama gelir:
– Saldırgan URL’ye ?sayfa=../../../../etc/passwd gibi bir şey eklerse,
– Sunucu, kendi sistem dosyalarını veya başka hassas dosyaları açmaya çalışır.
• İşte bu yüzden burada LFI (Local File Inclusion) açığı var!
Güvenli Hâli Nasıl Olur?
Burada ne yaptık?
•Kullanıcının gönderebileceği sayfa adlarını önceden belirledik ($allowed_pages listesi).
•Gelen $page değerini bu liste içinde kontrol ettik.
•Sadece izin verilen bir dosya ismi varsa include ettik.
•Böylece ../../ gibi dizin geçiş saldırılarını engelledik.
Bu yazıyla birlikte LFI açıklarını tanıdık, nasıl sömürüldüğünü ve nasıl önlenebileceğini öğrendik. DPUSEC ailesi olarak güvenli kodlama yolunda birlikte ilerlemeye devam edeceğiz. Umarım bu blog yazımda sana da yeni bakış açıları katabilmişimdir. Bir sonraki yazıda görüşmek üzere, hoşça kalın! 👋