Автор: @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: