
Учебная демонстрация эксплуатации уязвимости CVE-2018-1263 (RCE/LFI в phpMyAdmin). Включает настройку уязвимого окружения через Docker и пошаговое описание атаки для изучения эксплуатации веб-приложений.
Это руководство поможет вам установить уязвимый компонент и выполнить атаку, связанную с ошибкой phpMyAdmin, упомянутой в CVE-2018-1263.
Эта проблема была обнаружена в phpMyAdmin версии 4.8.x до 4.8.2. Используя её, атакующий может выполнить удалённый код и осуществить локальное включение файлов на сервере. Уязвимость связана с частью кода, отвечающей за перенаправление и загрузку страниц в phpMyAdmin. В коде есть ошибочная проверка разрешённых страниц, которая делает атаку возможной. Атакующий должен быть аутентифицирован, за исключением случаев "$cfg['AllowArbitraryServer'] = true" (где атакующий может указать любой хост, которым уже управляет, и выполнить произвольный код на phpMyAdmin) и "$cfg['ServerDefault'] = 0" (что обходит требование входа и запускает уязвимый код без какой-либо аутентификации).
Уязвимость вызвана обходом валидации в уязвимой функции проверки пути. Она позволяет удалённому аутентифицированному атакующему выполнить произвольный PHP-код на сервере.
В index.php из phpMyAdmin есть включение файла, которое можно вызвать, передав параметр target в URL. Часть кода, проверяющая параметр target, выглядит следующим образом
$target_blacklist = array (
'import.php', 'export.php'
);
// If we have a valid target, let's load that script instead
if (! empty($_REQUEST['target'])
&& is_string($_REQUEST['target'])
&& ! preg_match('/^index/', $_REQUEST['target'])
&& ! in_array($_REQUEST['target'], $target_blacklist)
&& Core::checkPageValidity($_REQUEST['target'])
) {
include $_REQUEST['target'];
exit;
}
// ...
В этом коде, как только условие if выполнено, выполняется include $_REQUEST['target'];. Поэтому нам просто нужно обойти условие if, чтобы выполнить то, что мы хотим.
Рассмотрим условие if
target не может быть пустым и должен быть строкой.target начинаться с index.target находиться в $target_blacklist.
$target_blacklist определяется непосредственно перед условием if и содержит import.php и export.php, то есть разрешено всё, кроме этих двух страниц.Core::checkPageValidity($_REQUEST['target']).
checkPageValidity отбрасывает всё после ? в $page и проверяет, находится ли она в белом списке. Строка после ? не является частью пути URL. В фрагменте кода также показан пример белого списка.public static function checkPageValidity(&$page, array $whitelist = [])
{
// ...
$_page = mb_substr($page, 0, mb_strpos($page . '?', '?'));
// example $whitelist == array('db_sql.php', 'sql.php', ...)
if (in_array($_page, $whitelist)) {
return true;
}
// ...
return false;
}
$page, поскольку она берётся напрямую из $_REQUEST['target'].Как уже упоминалось, атакующий полностью контролирует $page в функции checkPageValidity через параметр $_REQUEST['target'] в URL. Представим, что атакующий передаёт в $page через параметр $_REQUEST['target'] примерно следующее:
$page = 'db_sql.php?/../../../../../../../../etc/passwd'
Затем функция checkPageValidity выполняет следующее:
? и присваивает первую часть переменной $page. Таким образом, в этом примере значение $page = db_sql.php.$_page, т.е. db_sql.php, в белом списке. Поскольку оно там есть, функция возвращает True и управление возвращается в index.php.Поскольку условие if в index.php теперь истинно, выполняется следующая строка, как показано в приведённом выше фрагменте index.php:
include $_REQUEST['target'];
Далее происходит следующее:
$_REQUEST['target'], то есть выполняется следующее:
GET /index.php?target=db_sql.php?/../../../../../../../../etc/passwd
db_sql.php, происходит включение /../../../../../../../../etc/passwd, и содержимое файла /etc/passwd отправляется в ответе атакующему.Теперь это можно использовать для локального включения файлов или даже для удалённого выполнения кода, чтобы получить обратную оболочку. При каждом выполнении запроса в phpMyAdmin создаётся файл сессии, который сохраняется в каталоге /tmp с содержимым запроса. Файл сессии называется sess_< SESSION ID >. Идентификатор сессии легко найти в cookie с помощью режима инспектирования в браузере.
Итак, если мы выполним следующий запрос в phpMyAdmin
SELECT '<?php phpinfo();exit;?>'
он будет сохранён в файле сессии. Представим, что наш идентификатор сессии phpMyAdmin — e15cffd3ab25a631136611fba9ca2042.
Тогда, если мы откроем в браузере следующий адрес
http://your-ip:8080/index.php?target=db_sql.php?/../../../../../../../../tmp/sess_e15cffd3ab25a631136611fba9ca2042
phpMyAdmin попытается загрузить страницу сессии, и, поскольку страница содержит PHP-код, переданный через запрос, этот PHP-код будет выполнен. В данном примере мы увидим phpinfo на загруженной в браузере странице. Используя этот метод, мы можем выполнить любой произвольный код на удалённом сервере.
Инфраструктура эксплойта требует уязвимую версию phpMyAdmin и mysql. Для установки необходимых компонентов мы будем использовать docker-контейнеры. Для уязвимой версии phpMyAdmin воспользуемся готовым docker-окружением из Vulhub, а для mysql возьмём последнюю официальную версию из dockerhub. Скрипт установки предоставляется в виде docker compose yml-скрипта, который можно найти в репозитории.
Предполагается, что на целевой машине установлены docker и docker-compose. Если это не так, обратитесь к документации docker для их установки. После установки docker выполните следующие действия для настройки уязвимого компонента:
Сначала склонируйте репозиторий на целевой машине и перейдите в склонированный каталог
git clone [email protected]:msnkhan/exploit-demo.git
cd exploit-demo
Затем запустите docker compose-скрипт следующей командой
sudo docker-compose up -d
После завершения установки docker откроет страницу phpMyAdmin на порту 8080 вашей машины. Проверить это можно, открыв страницу в браузере по адресу следующего формата
http://your-machine-ip:8080
Если установка прошла успешно, вы должны увидеть страницу, похожую на следующую

Следующее видео — руководство по выполнению атаки