Автор: @Vespii

Ссылка на таск Codeby:
https://codeby.games/categories/web/fd3f1c50-2c25-4b34-b5c9-f30d71528591
Описание задания
В коробке есть подарок, но получить его, видимо, будет непросто
62.173.140.174:16039
Решение
Вот что мы видим, когда заходим на сайт.

Если ввести “hacker”, то получим ответ “Something went wrong”. Почему так происходит? Давайте разберемся. Скачаем зипку, данную в задании и откроем код.

Объяснение кода
Для начала поймем, что происходит в этом коде.
Эта функция запускает сессию:
session_start();Следующая функция проверяет наличие сессии. Если сессии нет, то генерируется новый идентификатор и записывается в PHPSESSID, заменяя старый:
if (!isset($_SESSION['PHPSESSID'])) {
session_regenerate_id(true);
$_SESSION['PHPSESSID'] = session_id();
}Данная функция проверяет, чтобы PHPSESSID не был изменен вручную. Если сессия не совпадает с той, которая указана в коде, генерируется новая:
if ($_SESSION['PHPSESSID'] !== session_id()) {
session_regenerate_id(true);
$_SESSION['PHPSESSID'] = session_id();
}Функция zerofunc001() также проверяет наличие сессии и, если она отсутствует, то запускает новую сессию:
if (session_status() == PHP_SESSION_NONE) {
session_start();
}Переменная $sessionId содержит идентификатор сессии, а переменная $pattern определяет диапазон символов:
$sessionId = session_id();
$pattern = '/[0-9]/';Дальше с помощью функции preg_match_all() производится поиск всех символов, соответствующих заданному диапазону в переменной $pattern и результат записывают в переменную $matches.
preg_match_all($pattern, $sessionId, $matches);Функция zerofunc001() возвращает количество найденных совпадений:
return count($matches[0]);Вот полный код функции zerofunc001():
function zerofunc001() {
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
$sessionId = session_id();
$pattern = '/[0-9]/';
preg_match_all($pattern, $sessionId, $matches);
return count($matches[0]);
}Функция zerofunc002($number) принимает число и проверяет, делится ли оно без остатка, то есть является ли оно четным:
function zerofunc002($number) {
return $number % 2 == 0;
}Следующая функция получает параметр word через POST и проверяет, что он не пустой.
if (isset($_POST['word']) && !empty($_POST['word']))Затем значение параметра записывается в переменную $p:
$p0=$_POST[base64_decode('d29yZA==')];Далее выполняется функция zerofunc001(), и результат записывается в переменную $e1:
$e1=zerofunc001();После этого переменная $e1 передается в функцию zerofunc002() где происходит проверка условия. Если число четное, результат равен 2. В противном случае результат равен 3:
$x2=(zerofunc002($e1))?2:3;Затем запускается цикл, который продолжается до тех пор, пока переменная $d3 не станет равной числу $x2. Внутри цикла происходит замена всех вхождений строки “hacker” в переменной $p0 на пустую строку, что фактически удаляет эту подстроку из переменной.
for($d3=0;$d3<$x2;$d3++) {
$p0=str_replace(base64_decode('aGFja2Vy'),'',$p0);
} Результат цикла записывают в переменную $word
$word = $p0;Вот так выглядит код полностью:

Теперь должно быть понятно, почему вместо флага получаем “Something went wrong”. Когда пишем hacker.
Обход и получение флага
Когда пришел момент обхода защиты и получения флага, у меня не было четкого представления, как приступить к этой задаче. К счастью, я обнаружила похожую ситуацию в рамках HackyHolidays CTF, что стало полезным источником в процессе решения.
Итак, приступим. Из кода мы уже знаем, что если ввести просто hacker, то он удаляется. Теперь хочу немного наглядно показать это:

Я доработала код, и теперь он показывает, что происходит в цикле:

Для тех, кто не понял. Код удалил “hacker” и остальные итерации остались пустыми. Нам нужно, чтобы к концу итерации остался один “hacker”.
Теперь попробуем “hackehackerr”.

Как видим “hacker” дошел до 0 итерации. Попробуем теперь “hackehackehackerrr”.

Теперь всё прошло так, как нужно. Все итерации были завершены, и в конце остался именно “hacker”, как мы и ожидали.
Теперь сделаем тоже самое на реальном сайте:

Tags: