• Курсы Академии Кодебай, стартующие в мае - июне, от команды The Codeby

    1. Цифровая криминалистика и реагирование на инциденты
    2. ОС Linux (DFIR) Старт: 16 мая
    3. Анализ фишинговых атак Старт: 16 мая Устройства для тестирования на проникновение Старт: 16 мая

    Скидки до 10%

    Полный список ближайших курсов ...

Гостевая статья ImpressCMS 1.3.11 - почему не стоит доверять PHP_SELF

ImpressCMS - это бесплатная, управляемая сообществом система управления контентом, написанная на PHP, которая считает себя безопасной, быстрой и модульной. Этот пост показывает нам, что незаметные переменные могут находиться под влиянием пользователя и, следовательно, могут привести к критическим уязвимостям безопасности.

Мы просканировали текущую версию ImpressCMS версии 1.3.11 и обнаружили несанкционированную уязвимость SQL-инъекции. Эксплойт влияет на установки, которые используют PDO в качестве драйвера базы данных. Проблема была исправлена в версии 1.4.0, хотя патч не соответствует передовым методам и может быть недостаточным. Вектор атаки не требует взаимодействия с пользователем, поэтому его можно использовать для автоматического управления многими сайтами ImpressCMS в больших масштабах. При наличии этой чрезвычайно опасной уязвимости пользователям настоятельно рекомендуется обновить свои установки ImpressCMS.

Усеченные результаты анализа доступны в нашем демонстрационном приложении RIPS. Обратите внимание, что мы ограничили результаты проблемами, описанными в этом посте, чтобы обеспечить исправление.



Обнаружение SQL-запроса
Модули ImpressCMS являются расширениями, которые предоставляют определенную функциональность. Например, модуль контента позволяет пользователям размещать статьи. Базовая структура требует каталог для каждого модуля. Если пользователь хочет редактировать контент, вызывается файл PHP в соответствующем подкаталоге. Следовательно, имя каталога является частью URL. Для загрузки данных модуля из базы данных в качестве идентификатора используется имя каталога. В случае модуля содержимого URL выглядит следующим образом: .

Восприимчивый класс icms_module_Handlerнаходится в Handler.phpфайле и обрабатывает модули системы. Каждый запрос проходит через serviceметод этого класса, чтобы предоставить соответствующий модуль, который должен быть загружен. Подробно определяется имя каталога PHP_SELF, которое является частью $_SERVERинформационного массива суперглобальной среды. PHP_SELFсодержит короткую часть текущего URL. Если файл внутри каталога модуля вызывается, PHP_SELFсодержит такое имя каталога / модуля.

Например, при вызове необходимо загрузить профиль/modules/profile/admin/user.php модуля . Поэтому сначала извлекается подстрока от конца строки. Во-вторых, эта подстрока отделяется косыми чертами, как видно в строке 417. Массив теперь имеет строку в третьей позиции, индекс 2. Если установлен индекс 2 массива, метод вызывается со своим значением, как видно в строке 420./modules/$url_arrayprofilegetByDirname()

HTDOCS / библиотеки / ICMS / модуль / handler.php
Код:
if ($inAdmin || file_exists('./xoops_version.php') || file_exists('./icms_version.php')) {
  $url_arr = explode('/', strstr($_SERVER['PHP_SELF'], '/modules/'));
  if (isset($url_arr[2])) {
    /* @var $module icms_module_Object */
    $module = icms::handler("icms_module")->getByDirname($url_arr[2], TRUE);
    ⋮

В getByDirname()параметре, полученном как $dirnameне очищенный, объединенный в запрос SQL и выполненный сразу после этого в следующем коде:

HTDOCS / библиотеки / ICMS / модуль / handler.php
Код:
$sql = "SELECT * FROM " . $this->db->prefix('modules') . " WHERE dirname = '" . trim($dirname) . "'";
if (!$result = $this->db->query($sql)) return $module;

Эксплуатация через PHP_SELF
Чтобы использовать уязвимость, $_SERVER['PHP_SELF']необходимо настроить $url_arr[2]значение, чтобы оно содержало произвольную команду SQL. Это может быть достигнуто путем изменения соответствующего имени каталога модуля на оператор SQL внутри URL. Хотя каталог не существует и, следовательно, запрос приводит к ошибке 404 file not found . Однако уязвимый метод in Handler.phpвыполняется на любой странице, включая страницы вне каталога модулей.

Таким образом, чтобы использовать его, мы /admin.phpвместо этого вызываем, потому что этот URL не пытается загрузить модуль уже. Мы можем добавить косую черту к этому URL-адресу, и он все еще разрешается в admin.phpфайле, например /admin.php/foo, что крайне важно для этого эксплойта. Это приводит к тому, PHP_SELFчто пользователь контролирует имя файла, о чем многие разработчики не знают. Как видно из этого эксплойта, PHP_SELFзначение было полезно для определения имени каталога, но разработчики не думали, что оно контролируется пользователем и, следовательно, опасно в контексте метода.

Вызов приводит к тому, что скрипт admin.phpв корне сети выполняется и $_SERVER['PHP_SELF']имеет значение /admin.php/modules/bar. Код из строки 417 и далее продолжается, пытаясь загрузить модуль «bar». Так как это приводит нас к SQL-запросу, мы можем манипулировать «баром» для вставки SQL-оператора. Вызов /admin.php/modules/' OR SLEEP(1000) -- -- это пример экранирования одинарной кавычки и выполнения произвольной команды SQL.

Кроме того, хотя мы не вошли в систему, переменная $isAdminустановлена в true. Это позволяет нам пройти Handler.phpпроверку в строке 416.

Заплата
Наилучшей практикой для предотвращения введения вредоносных утверждений является использование подготовленных утверждений. Поскольку поставщик никогда не использовал подготовленные операторы в своем коде, это исправление не может быть применено. Мы не хотим переписывать большую базу кода и, следовательно, предоставлять только исправления. Одиночная кавычка, которая позволила нам вырваться из строки, должна быть экранирована с помощью quote()метода. Замените строку 133 Handler.phpфайла следующим текстом:

$sql = "SELECT * FROM " . $this->db->prefix('modules') . " WHERE dirname = " . $this->db->quote(trim($dirname));

Резюме
В этом посте мы увидели, что невинное появляющееся $_SERVER['PHP_SELF']значение контролируется пользователем и может привести к уязвимостям, как и любой другой пользовательский ввод. Часто неясно, какие переменные могут содержать пользовательский ввод, поэтому необходимо всегда использовать подготовленные операторы и дезинфицировать входные данные для обеспечения безопасности приложения.

Мы связались с поставщиком по поводу уязвимости, но не получили ответа на наш запрос. Проблема была решена в версии 1.4.0, однако исправление не соответствует передовым методам, и поэтому его безопасность не может быть гарантирована.

Источник:
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!