• [ Регистрация ]Открытая и бесплатная
  • Tg admin@ALPHV_Admin (обязательно подтверждение в ЛС форума)

Статья Пентест провайдера. Как цепочка классических багов привела к полной компрометации

stihl

Moderator
Регистрация
09.02.2012
Сообщения
1,178
Розыгрыши
0
Реакции
510
Deposit
0.228 BTC
stihl не предоставил(а) никакой дополнительной информации.
В этой статье я поделюсь историей одного из выполненных мной проектов, который показал, что даже в наше время встречаются простые и базовые уязвимости, грамотное сочетание которых может привести к RCE.
Я занимаюсь анализом защищенности веб‑приложений и внешних инфраструктур в Singleton Security. Нашим заказчиком выступил довольно крупный интернет‑провайдер, предоставляющий свои услуги в нескольких регионах России.

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

В область тестирования входила корпоративная ERP-система, причем это был даже не вендорский продукт, а внутренняя разработка. Самописные решения (еще и для внутреннего использования) особенно интересны тем, что к ним могут предъявляться гораздо менее строгие требования по безопасности. Вероятность того, что такие системы проходят регулярный пентест, тем более мала. Собственно, о захвате этой системы я сегодня и расскажу.

warning​

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

Разведка, первая зацепка​

Первый этап при проведении пентеста — это, конечно же, разведка — поиск максимального числа поддоменов, веб‑сайтов, служб и сервисов, доступных в обозначенном скоупе.

Поэтому в первую очередь я просканировал порты на полученных девяти IP-адресах, чтобы определить доступные службы.

Я начал с поиска веб‑приложений на стандартных портах — 80 и 443. Это помогло быстро очертить базовую поверхность атаки и провести сканирование без лишнего шума. На тот момент было непонятно, использует ли заказчик средства защиты и насколько строго они настроены, поэтому я старался действовать осторожно.

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

Команда выглядела так:

nmap -v -Pn -iL scope.txt -p 80,443 --max-rate 20 -oG web-scan.nmap
В результате сканирования я обнаружил три узла с доступными веб‑серверами. Кроме того, Nmap по умолчанию выполняет обратное разрешение DNS-имен, поэтому в процессе я также получил используемое доменное имя (в тексте я буду использовать вместо него example.ru).

Теперь можно использовать его для поиска поддоменов. Для этого я обычно пользуюсь инструментарием Для просмотра ссылки Войди или Зарегистрируйся, в частности утилитами subfinder и dnsx. Первая предназначена для поиска поддоменов в открытых источниках, а вторая — для выполнения DNS-запросов, аналог nslookup или dig. Инструментарий PD примечателен тем, что вывод одной утилиты можно сразу пайпить на ввод другой. Благодаря этому можно собирать интересные комбайны, позволяющие одним однострочником провести разведку, обнаружить действующие HTTP-сервисы и сразу же просканировать их на наличие уязвимостей.

Но конкретно в этом случае задача проще — найти все поддомены, относящиеся к скоупу, поэтому я использовал лишь две упомянутые утилиты:

subfinder -all -silent -d example.ru | dnsx -a -resp -silent -nc
После фильтрации вывода по IP-адресам из скоупа мое внимание привлек один адрес, в который разрешались около десяти поддоменов. Это был как раз один из ранее найденных хостов с доступным веб‑интерфейсом.

Я изучил доступные веб‑приложения и выяснил, что на этом узле размещена ERP-система (erp.example.ru). Большинство поддоменов оказались ее копиями для офисов компании в разных городах. Также были доступны поддомены с говорящими названиями files и api, судя по всему, предназначенные для работы с файлами и API-запросами.

Следующий этап, разумеется, — это фаззинг доступных файлов и директорий на обнаруженных веб‑приложениях. Здесь и ждала первая находка: на поддомене files.example.ru оказался доступен конфиг Nginx.


Первая уязвимость — читаем файлы​

Мое внимание сразу же привлекла одна из первых строчек конфига:

Код:
location /avatar {
    rewrite ^/avatar/(.*)$ /api.php?type=getAvatar&file=$1 break;
    ...
    fastcgi_pass localhost:9000
}

Здесь можно увидеть, что все маршруты, начинающиеся с /avatar, обрабатываются rewrite-правилом, его можно прочитать так: «возьми все, что идет после /avatar/, и подставь в аргумент параметра file». То есть если мы обратимся по пути /avatar/test/example.png, то Nginx превратит это в /api.php?type=getAvatar&file=test/example.png.

GET-параметр file вызывает очень большие подозрения на возможный LFR / Path Traversal, но, если мы подставим нагрузку в изначальный URL, ничего не произойдет: Nginx обрубает подобные запросы и возвращает ошибку 400. Но стоит проверить, можно ли обратиться к скрипту api.php напрямую и подставить нагрузку туда.

Для просмотра ссылки Войди или Зарегистрируйся
Бинго! Теперь есть возможность читать содержимое файлов в системе, доступных текущему пользователю, — вероятно, www-data. А еще в конфиге Nginx был виден эндпоинт, предназначенный для загрузки файлов, но он уже требовал авторизации (однако он все еще будет полезен в дальнейшем).


Новый поддомен​

Используя обнаруженную уязвимость, я принялся изучать содержимое файлов сервера, включая многочисленные конфиги в директории /etc. И тут всплыла следующая находка: настройка зоны (назовем ее example.ru) для DNS-сервера BIND. В ней — несколько новых поддоменов, которые я не встречал на этапе разведки, причем они резолвились все в тот же IP-адрес, с которым я работал. Одним из них был xyz.example.ru, на котором нашлось новое приложение.

Главная страница представляла собой форму аутентификации, и никаких других возможностей доступно не было. Тогда я снова пофаззил файлы и каталоги. Мое внимание привлек файл config.php. Но это скрипт на PHP, он выполняется сервером, а не возвращается как файл.

И тут мне помогла найденная ранее LFR-уязвимость (Local File Read — возможность читать файлы на удаленном хосте). Так как действие происходит на одном и том же сервере, оказалось достаточно извлечь файл /var/www/xyz.example.ru/config.php и ознакомиться с его содержимым.

Для просмотра ссылки Войди или Зарегистрируйся
И снова косяк! Креды от сервиса лежат плейнтекстом в этом файле. Ими‑то я и воспользовался, чтобы получить доступ к приложению.

Интерфейс оказался простеньким: это табличка с множеством фильтров. Как я понял, программа предназначена для просмотра информации об абонентах провайдера: номера договоров, персональные данные абонентов, статус подключения. Уже достаточно чувствительные данные, доступ к которым не должен попасть в руки посторонних.

В этом сервисе для нас главное — это PHP-скрипт, непосредственно собирающий информацию из БД. Интересен он ровно тем, о чем ты, наверное, сейчас подумал.

Для просмотра ссылки Войди или Зарегистрируйся
Милая наша золотая кавычка! Сколько скриптов ты поломала и сколько еще поломаешь.

Чтобы не гадать и не тратить время на то, как эксплуатировать SQL-инъекцию, я снова воспользовался LFR и извлек исходный код скрипта.

Сложно описать боль, которую мне причинило увиденное. 800 строк отборных if — else, конкатенация параметров в каждый первый SQL-запрос и точно такое же формирование HTML-разметки...

Помимо SQLi, тут еще и риск эксплуатации XSS, если соответствующую нагрузку можно загрузить со стороны клиента. Впрочем, личный кабинет не входил в скоуп тестирования, поэтому проверить эту гипотезу не удалось.

Но вернемся к нашим кавычкам. При таком широком просторе для экспериментов я выбрал один из самых простых вариантов — запрос к базе с выполнением классической UNION-инъекции.

Для просмотра ссылки Войди или Зарегистрируйся
Далее тем же способом я извлек схему базы данных — оказалось, это та же БД, что используется в основной ERP-системе. Поэтому следующим шагом я изучил таблицы с пользовательскими данными, чтобы понять, удастся ли получить доступ к какой‑нибудь учетной записи в ERP.


Получаем доступ в приложение​

И тут меня ждала занятная находка: в таблице пользователей оказалось два столбца для хранения паролей. Один использовал bcrypt и применялся для большинства записей — их было около 1500. А вот второй содержал MD5-хеши без соли и все еще встречался примерно у 200 учеток. Похоже, разработчики перешли на более надежный алгоритм, но зачем‑то оставили (или еще не удалили) старый MD5.

Так или иначе, это значительно облегчило мне задачу: из примерно 200 извлеченных MD5-хешей удалось успешно пробрутить 96. С парольной политикой, видимо, все совсем грустно. К тому же многие пароли повторялись у разных пользователей, так что общее число скомпрометированных учеток выросло до 160.

Я проверил базу и убедился, что среди скомпрометированных учетных записей оказались пользователи с высокими привилегиями: администраторы, сотрудники техподдержки и несколько ключевых лиц, принимающих решения в организации.

Злоумышленник, имеющий подобный уровень доступа, способен нанести серьезный ущерб организации: извлечь данные сотрудников и клиентов, нарушить бизнес‑процессы вплоть до полной остановки работы организации. Возможно, получить доступ к корпоративной инфраструктуре, если и дальше продолжат встречаться подобные подарки.

Останавливаться на достигнутом, конечно же, не хотелось — вдруг получится дожать до настоящего пробива, то есть удаленного исполнения кода?


Finish him!​

Виртуальный хост files.example.ru, как ты помнишь, поддерживал загрузку файлов на сервер, но эта возможность была недоступна без активной сессии в ERP. Однако теперь у нас есть подходящая учетка благодаря вскрытой на прошлом шаге базе.

С помощью ранее найденной «читалки» (то есть LFR) я скачал исходный код скрипта file.example.ru/api.php, чтобы разобраться в механизме загрузки и понять, какие параметры нужно передать в POST-запросе. Оказалось, все довольно просто:

  • POST-запрос на самом деле является PUT-запросом;
  • в параметрах запроса нужно указать src (путь для сохранения), file (содержимое файла) и etag (MD5-хеш от file).
Используя эту информацию, собираем запрос на загрузку простого PoC, выводящего информацию о пользователе и текущей директории.

Для просмотра ссылки Войди или Зарегистрируйся
И вот, кажется, мы успешно загрузили вредоносную нагрузку, осталось лишь ее вызвать...

Для просмотра ссылки Войди или Зарегистрируйся
Проигрыш. Вместо того чтобы исполнить загруженный PHP-скрипт, сервер просто вернул его как файл. Чем же это вызвано?

Объяснение достаточно простое. В конфиге Nginx, который я нашел еще в самом начале повествования, есть несколько прописанных location (путей), каждый из которых завершается передачей обработанных аргументов в FPM (это программный пакет, отвечающий за выполнение PHP-скриптов, так как сам веб‑сервер этого делать не умеет) при помощи директивы fastcgi_pass. А для всех остальных возможных путей нет обработчика по умолчанию (location /), который передавал бы скрипт на выполнение. Поэтому загруженный скрипт и выдается обратно как файл.

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

Но конечно, унывать долго не пришлось. Во‑первых, посмотри, как формируется путь для сохранения загруженного файла:

Код:
public function getSaveSrc($src)
{
    return $this->getBasePath().'/'.$src;
}

Снова пути складываются без предварительной обработки, снова можно использовать Path Traversal, только теперь для записи файла в произвольную директорию. А это очень полезно, так как ранее мы установили, что на исследуемом сервере крутится несколько приложений одновременно. А значит, потенциально существует возможность записать эксплоит в директорию другого сайта, из которой он точно выполнится.

Помимо поддоменов files. и erp., во время разведки нашелся поддомен api.example.ru. Используя все ту же читалку, я определил, что исходники сайта лежат в директории /var/www/api.example.ru и эта директория является git-репозиторием (в ней был доступен файл ./.git/index). Это значительно упрощает задачу, поскольку позволяет выкачать репозиторий целиком, а не фаззингом подбирать пути к существующим файлам.

Для скачивания исходников я воспользовался утилитой Для просмотра ссылки Войди или Зарегистрируйся. Несмотря на то что она не обновлялась около пяти лет, тулза отлично справилась с задачей и смогла вытянуть все необходимые исходники. Другие подобные тулзы у меня не отрабатывали, поскольку ожидали именно открытую директорию .git/ в корне сайта, а не извлечение через Path Traversal.

Получив исходники, я обнаружил, что в рабочей директории сайта также есть конфиг Nginx:

Код:
location / {
  include snippets/fastcgi-php.conf;
  fastcgi_pass 127.0.0.1:9000;
}

Тут уже все гораздо проще: конфиг представляет собой единственный location, который передает все запросы в FPM на исполнение. Это значит, что если положить эксплоит туда, то он должен успешно выполниться.

Я повторил загрузку эксплоита, только в этот раз по пути ../../../../api.example.ru/exploit.php. Открываю загруженный файл, и он выполняется.

Для просмотра ссылки Войди или Зарегистрируйся
Победа!

Подробнее о принципах использованных уязвимостей читай в статьях «Хакера»:

Результаты​

В итоге, используя цепочку уязвимостей, я добился выполнения команд ОС на сервере ERP-системы заказчика. Обнаруженные недостатки позволяют потенциальному злоумышленнику заполучить персональные данные сотрудников и клиентов организации, нарушить ее операционную деятельность или использовать полученные данные для еще более глубокого проникновения в корпоративную инфраструктуру.

Подобные действия уже были out of scope, поэтому на доказательстве возможного выполнения команд ОС мне пришлось остановиться. Не сомневаюсь, что с такими находками можно было добраться и до внутряка.


Как такого не допустить​

Во‑первых, не совсем ясно, почему такая система была во внешнем контуре: это внутренняя система для использования сотрудниками организации, поэтому по‑хорошему она должна быть помещена за корпоративным VPN. В таком случае злоумышленникам останется надеяться только на социальную инженерию и заражение машин сотрудников.

Во‑вторых, значительную роль в успешной компрометации сервера сыграло отсутствие изоляции разных сервисов. Грамотная контейнеризация позволила бы разделить файловые системы разных приложений, что не дало бы использовать чтение файлов через Path Traversal настолько эффективно.

Ну и само собой, всегда и везде, во все времена необходимо проверять и санитизировать пользовательский ввод. Даже если какая‑то возможность не предназначена для обычных пользователей и «ввода» в простом понимании там нет, все параметры обязательно должны проходить проверку.
 
Activity
So far there's no one here
Сверху Снизу