02 — Root Cause Analysis: CWE-22
Filesystem Path Fundamentals
Linux/Unix paths:
/home/alice/documents/file.txt
├─ / = root directory
├─ home = subdirectory
├─ alice = subdirectory
└─ documents/file.txt = file
Path shortcuts:
.= current directory..= parent directory/= root directory/etc/passwd= absolute pathdocuments/file.txt= relative path
The Vulnerability
When a web application uses user input to construct file paths:
VULNERABLE CODE:
file_name = request.args.get('file')
file_path = f'/var/www/uploads/{file_name}'
with open(file_path, 'r') as f:
return f.read()
ATTACK PAYLOAD:
file_name = '../../etc/passwd'
file_path = '/var/www/uploads/../../etc/passwd'
# Which resolves to: /etc/passwd
Attack Vectors
1. Dot-Dot-Slash (../)
Current: /var/www/uploads/
../ moves up one level
../../ moves up two levels
../../../ moves up three levels
etc/passwd ends up at root's passwd file
2. Backslash (.)
On Windows:
C:\www\uploads\
..\..\ moves up
..\..\windows\system32\config\sam (Windows password hashes)
3. Unicode/UTF-8 Normalization
%C0%AE = encoded version of ../
%252E%252E%252F = double-encoded ../
Filters see %C0%AE and whitelist it
System decodes it to ../
Attack succeeds
4. Case Sensitivity Bypass
Some systems: .. filtered, but ..%5c bypasses(literal backslash)
5. Symlink Attacks
# Admin creates symlink in uploads dir
ln -s /etc/passwd /var/www/uploads/legitimate.txt
# User downloads "legitimate.txt"
# Actually gets /etc/passwd (invisible attack)
Secure Implementation
SAFE - Canonicalization:
import os
from pathlib import Path
def secure_file_access(file_name):
allowed_dir = Path('/var/www/uploads').resolve()
file_path = (allowed_dir / file_name).resolve()
# Ensure file is still within allowed directory
if not str(file_path).startswith(str(allowed_dir)):
raise ValueError("Path traversal attempt detected")
with open(file_path, 'r') as f:
return f.read()
# Attack payload:
file_name = '../../etc/passwd'
# file_path resolves to /etc/passwd
# Check fails: /etc/passwd is not under /var/www/uploads
# Request rejected
Why Blacklist Fails
Common mistake:
UNSAFE - Blacklist approach
if '..' in file_name:
reject()
if file_name.startswith('/'):
reject()
Bypasses:
- Unicode: %C0%AE = ..
- Double encoding: %252E%252E
- Case: ..%5c
- Null byte: ..%00.jpg (null terminator tricks)
KGCS Causal Chain
CWE-22 (Path Traversal)
├─ Root cause: Improper pathname limiting
├─ Demonstrated by → CAPEC-126
└─ Implements → T1005 (Data from Local System)
└─ Result: Unauthorized file read
Next: 03 Attack Scenarios