Перейти к основному содержанию

CTF — PHP - register globals

CTF

По традиции 9 мая займёмся задачками на информационную безопасность web-серверов. Сегодня задачка с портала root-me.org, называется "PHP - register globals". За решение задачки дают 25 баллов, ближе к среднему уровню.

ctf

Нам дают две подсказки:

  • Уязвимость связана с register_globals.
  • А ещё разработчики часто забывают почистить за собой файлы бэкапа.

Задачки с файлами бэкапов мы уже решали:

CTF — backup file

Многие текстовые редакторы в процессе редактирования делают резервные копии файлов, сохраняя их с другим расширением.

А потом снаружи появляется возможность доступа к файлам бэкапа текстовых редакторов.

register_globals=On — настройка PHP, которая автоматически регистрирует переменные EGPCS (Environment, GET, POST, Cookie, Server) в качестве глобальных переменных.

Опасная штука, не рекомендуется включать. Начиная с версии PHP 4.2.0 значением по умолчанию для этой директивы является off. Удалена в PHP 5.4.0.

Ссылки

https://www.root-me.org

Решение

Переходим на страницу задания:

http://challenge01.root-me.org/web-serveur/ch17/

Мы видим форму авторизации. Есть поле пароля и кнопка "connect".

ctf

Посмотрим код страницы. Ничего интересного, форма отправляет POST запрос на текущую страницу и передаёт переменную password. Вероятно, если передать правильный пароль, то чудо произойдёт.

ctf

По умолчанию основная страница index.php. Проверим это, допишем в URL. Действительно, основной исполняемый файл index.php.

ctf

Давайте проверим, не забыл ли разработчик отключить бэкап файлов в своём любимом текстовом редакторе. Проверим, не забыл ли разработчик удалить за собой файл index.php.bak. Забыл-таки.

ctf

Скачивается файл index.php.bak.

ctf

Посмотрим что внутри.

<?php

function auth($password, $hidden_password){
    $res=0;
    if (isset($password) && $password!=""){
        if ( $password == $hidden_password ){
            $res=1;
        }
    }
    $_SESSION["logged"]=$res;
    return $res;
}

function display($res){
    $aff= '
	  <html>
	  <head>
	  </head>
	  <body>
	    <h1>Authentication v 0.05</h1>
	    <form action="" method="POST">
	      Password&nbsp;<br/>
	      <input type="password" name="password" /><br/><br/>
	      <br/><br/>
	      <input type="submit" value="connect" /><br/><br/>
	    </form>
	    <h3>'.htmlentities($res).'</h3>
	  </body>
	  </html>';
    return $aff;
}

session_start();
if ( ! isset($_SESSION["logged"]) )
    $_SESSION["logged"]=0;

$aff="";
include("config.inc.php");

if (isset($_POST["password"]))
    $password = $_POST["password"];

if (!ini_get('register_globals')) {
    $superglobals = array($_SERVER, $_ENV,$_FILES, $_COOKIE, $_POST, $_GET);
    if (isset($_SESSION)) {
        array_unshift($superglobals, $_SESSION);
    }
    foreach ($superglobals as $superglobal) {
        extract($superglobal, 0 );
    }
}

if (( isset ($password) && $password!="" && auth($password,$hidden_password)==1) || (is_array($_SESSION) && $_SESSION["logged"]==1 ) ){
    $aff=display("well done, you can validate with the password : $hidden_password");
} else {
    $aff=display("try again");
}

echo $aff;

?>

Обратим внимание на последний участок кода.

ctf

Если переменная $password (а мы её передаём из формы) равна переменной $hidden_password, то нам выведут на экран значение $hidden_password. Если переменная $_SESSION["logged"] равна единице, то мы тоже получим то что нужно.

Если в настройках PHP стоит register_globals=On, то мы смело можем передать в URL вместе с переменной password ещё и hidden_password. Можем передать любые значения, главное, чтобы они были равны.

  • password = lab
  • hidden_password = lab

ctf

Ну вот, мы выполнили условие функции и получили значение переменной hidden_password, вот только мы его переопределили и видим тот текст, который передали — "lab". Но ничего страшного, смотрим в эту часть кода:

ctf

Если пароли равны, то взводится сессия logged. Убираем все параметры из URL.

ctf

Поскольку у нас сессия logged=1, то видим значение скрытой переменной hidden_password. Вот и флаг. Валидируем:

ctf

И получаем 25 баллов. ? Это ПОБЕДА, друзья!

Безопасность

Если у вас старая версия PHP, отключайте, по возможности, настройку register_globals. Это можно сделать в php.ini:

register_globals=Off

Большинство хостинг провайдеров вам это не позволят, потому придется воспользоваться файлом .htaccess:

php_flag register_globals off

Бонус

Настройка register_globals=On автоматически регистрирует и переменные сессии. Мы просто могли передать в URL параметр logged=1 и получить тот же результат:

ctf

Теги

 

Похожие материалы