Исследование

Тестирование на проникновение: оптимизируем работу с помощью агента Mythic

Введение

Мы часто рассказываем, как злоумышленники используют постэксплуатационные фреймворки в своих атаках. Но мы не только анализируем артефакты — богатая экспертиза нашей компании позволяет нам изучать подобные инструменты и реализовывать лучшие практики в проведении тестирования на проникновение, чтобы помогать организациям всегда быть на шаг впереди.

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

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

Отметим, что эксперты «Лаборатории Касперского» уделяют большое внимание обнаружению подобных инструментов и техник, включая как описанные в статье, так и многие другие, используемые злоумышленниками в реальных атаках.

Для противодействия злоумышленникам в описываемом контексте применяются такие решения, как Kaspersky Endpoint Security, использующие следующие технологии.

  • Анализ поведения отслеживает поведение процессов в операционной системе, обнаруживает вредоносное поведение и обеспечивает дополнительную защиту критически важных компонентов ОС, таких как процесс службы Local Security Authority Subsystem Service.
  • Защита от эксплойтов предотвращает эксплуатацию уязвимостей в установленном ПО и ОС.
  • Защита от бесфайловых угроз обнаруживает и блокирует угрозы, которые не хранятся в файловой системе в виде традиционных файлов, но хранятся, например, в задачах планировщика, подписках WMI и т. п.
  • А также целый ряд других технологий.

Однако стоит заметить, что, поскольку в исследовании речь идет о сложной атаке, управляемой непосредственно злоумышленником (или пентестером), для более надежного противодействия следует применять эшелонированный подход к защите. Он должен включать внедрение решений безопасности, которые позволяют экспертам SOC обнаруживать действия злоумышленников и реагировать на них в режиме реального времени. К таким инструментам относятся решения класса Endpoint Detection and Response, Network Detection and Response и Extended Detection and Response, а также сервисы класса Managed Detection and Response. Эти решения обеспечивают непрерывный мониторинг и реагирование на возможные инциденты. Другим краеугольным камнем комплексного подхода к защите от сложных угроз и целевых атак является активное использование инструментов киберразведки, чтобы иметь актуальную и релевантную информацию о тактиках и техниках злоумышленников.

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

Инструменты пентестера: как выбрать

Анализ готовых решений

Выбор инструментов для проведения тестирования на проникновение может оказаться сложной задачей. В процессе работы почти каждый пентестер сталкивается с проблемой детектирования со стороны защитных решений (EPP и EDR). Как только инструмент для тестирования на проникновение становится популярным среди злоумышленников, защитные технологии начинают детектировать не только его поведение, но и отдельные компоненты. Более того, способность обнаруживать такой инструмент становится ключевым показателем в оценке результативности таких технологий. Это приводит к тому, что пентестерам необходимо тратить больше времени на подготовку к проекту.

При этом у многих существующих решений есть недостатки, затрудняющие тестирование на проникновение. Например, этичные хакеры активно используют инструмент Cobalt Strike. Для версии платформы 4.9.1 задана определенная последовательность опкодов в агенте Beacon. Чтобы избежать детектирования защитными решениями, опкоды необходимо менять, однако в таком случае агент перестанет работать.

Неизменяемая последовательность опкодов для агента Cobalt Strike

Неизменяемая последовательность опкодов для агента Cobalt Strike

Еще один пример — полезная нагрузка Meterpreter от Metasploit, сигнатуры которой встречаются более 230 раз в базе данных антивирусов компании Microsoft, что значительно затрудняет использование этого инструмента в проекте.

Фреймворк Sliver — это проект с открытым исходным кодом. Он находится в активной разработке и может решить задачи пентестера. Однако у этого проекта также есть ряд недостатков.

  1. Размер генерируемой фреймворком нагрузки — 8–9 мегабайт, что снижает гибкость использования, так как оптимальный размер агента для тестирования на проникновение, обеспечивающий вариативность его применения, составляет около 100 КБ.
  2. Проблемы со стабильностью. Мы столкнулись с перебоями в работе активной сессии. Кроме того, ранее этот фреймворк не поддерживал автоматическое использование прокси-сервера из конфигурации Windows, что тоже усложняло работу с ним (на текущий момент эта функциональность реализована).

Сейчас набирают популярность фреймворк Havoc и его полезная нагрузка Demon, поскольку они активно развиваются и поддерживают техники, которые позволяют избежать обнаружения. Однако на текущий момент в этом фреймворке наблюдаются несоответствие принципам операционной безопасности (OPSEC) и проблемы со стабильностью. Кроме того, настройка полезной нагрузки в Havoc ограничена негибкими параметрами.

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

Структура нагрузки

Для начала определим, какая полезная нагрузка необходима для тестирования на проникновение. Мы решили разбить ее на три модуля: Stage 0, Stage 1 и Stage 2. Первый модуль, Stage 0, отвечает за создание и запуск полезной нагрузки. Он должен генерировать артефакт, например шелл-код, DLL, EXE-файл, скрипт VBA и т. д., а также обеспечивать максимальную гибкость, предоставляя настраиваемые параметры для запуска полезной нагрузки. Также этот модуль отвечает за обход средств защиты информации и контролирует среду запуска.

Второй модуль (Stage 1) должен предоставлять оператору возможность осмотреться на хосте и выполнить первоначальную разведку, после чего на основе этой информации произвести закрепление с помощью нагрузки, которая поддерживает скрытые каналы связи. После закрепления этот модуль должен запустить третий модуль (Stage 2) для проведения таких работ, как горизонтальное перемещение, повышение привилегий, эксфильтрация данных и сбор учетных данных.

Три модуля полезной нагрузки

Три модуля полезной нагрузки

Модуль Stage 0 необходимо написать с нуля, поскольку доступные инструменты быстро детектируются защитными решениями и становятся бесполезными для тестирования на проникновение. Для реализации модуля Stage 1 мы частично решили модифицировать существующие проекты с открытым исходным кодом, а часть задач решить самостоятельно. Для третьего модуля (Stage 2) мы также использовали открытые проекты с небольшими изменениями.

В этой статье мы подробно расскажем о реализации второго модуля (Stage 1).

Формирование требований

Исходя из вышеперечисленных задач, сформулируем требования к модулю Stage 1.

  1. Динамическая функциональность, то есть модульность, для повышения устойчивости. К тому же, динамическая конфигурация позволяет добавлять техники с помощью новых модулей, не изменяя функциональное ядро.
  2. Обеспечение запуска третьего модуля полезной нагрузки (Stage 2).
  3. Минимальный размер (100–200 КБ) и оставление минимальных следов в системе.
  4. Функциональность модуля должна соответствовать принципам операционной безопасности (OPSEC) и обеспечивать выполнение операций без срабатывания средств защиты информации — поэтому нам необходимо предусмотреть возможность избегания сигнатурного детектирования в памяти.
  5. Использование нестандартных (скрытых) каналов передачи данных помимо HTTP и TCP для скрытного закрепления и избегания сетевого детектирования.

Выбираем оптимальное решение

В процессе формирования требований мы определили потребность в модульности. Для начала нам необходимо определить оптимальный способ добавления новых функций во время выполнения задач. Одним из широко используемых методов динамического добавления функциональности является рефлективная DLL-инъекция (Reflective DLL Injection), представленная в 2008 году. Этот вид инъекций имеет как свои преимущества, так и недостатки. Функция ReflectiveLoader достаточно легко детектируется, а значит, для создания динамической конфигурации понадобится ее кастомная реализация. Это эффективный, однако затратный способ реализации модульности, поэтому мы решили продолжить поиски.

В середине 2010-х годов стал популярен фреймворк PowerShell Empire, загрузчик которого основан на рефлективном выполнении PowerShell. С внедрением строгого мониторинга и жестких политик в отношении PowerShell эпоха этого фреймворка завершилась, и популярность набрали сборки .NET, которые также выполнялись рефлективно c помощью метода Assembly.Load. В это время появились такие наборы утилит, как SharpSploit и GhostPack. А в 2018 году в Cobalt Strike появилась функция execute-assembly, которая создавала новый процесс и внедряла в него сборки .NET. Создание процесса и инъекция в него — заметные индикаторы компрометации, которые отслеживаются очень тщательно.

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

Следующий этап развития фреймворков — выполнение объектных файлов в памяти. Объектный файл (COFF, Common Object File Format) — это файл, который представляет собой скомпилированную версию исходного кода. Обычно объектные файлы не являются полноценными программами: они нужны для компоновки и сборки проекта. Объектный файл включает в себя несколько важных элементов, которые обеспечивают правильное функционирование исполняемого кода.

  • Заголовок — содержит информацию об архитектуре, о временной метке, количестве секций и символов, а также другие метаданные.
  • Секции — это блоки, которые могут включать код на ассемблере, отладочную информацию, директивы компоновщика, информацию об исключениях и статические данные.
  • Таблица символов — содержит функции и переменные, а также информацию об их расположении в памяти.

Использование объектных файлов позволяет избежать загрузки в процесс среды CLR, как, например, при использовании сборки .NET и метода Assembly.Load. Более того, выполнение COFF происходит в текущем контексте, без необходимости создания процесса и инъекции в него. Эту возможность представили и сделали популярной в 2020 году разработчики фреймворка Cobalt Strike. А в 2021 году для реализации этой задачи компания TrustedSec создала инструмент COFF Loader с открытым исходным кодом: он загружает COFF-файл с диска и выполняет его. Такая функциональность отлично подходит для наших целей, поскольку позволяет выполнить нужные задачи: осмотреться, закрепиться в системе и запустить следующий модуль с помощью объектного файла (если мы добавим в проект получение файла по сетевому протоколу и его выполнение из памяти). Кроме того, используя инструмент COFF Loader, пентестер длительное время может оставаться незамеченным в системе.

Для работы с агентом в этом исследовании мы решили использовать BOF (Beacon Object File), объектные файлы для Cobalt Strike Beacon. В сети есть большое количество инструментов с открытым кодом и функций, написанных для BOF. Используя разные объектные файлы BOF как отдельные модули, мы можем в любой момент добавить нужную технику, не изменяя основную часть агента.

Следующее требование к Stage 1 — минимальный размер полезной нагрузки. Здесь можно реализовать различные варианты: например, при использовании языка C# размер Stage 1 составит 20 КБ. Это достаточно хороший показатель, но в таком случае нагрузка будет зависеть от .NET-платформы. Если использовать нативный язык, например C, нагрузка в незашифрованном виде составит приблизительно 50 КБ — это удовлетворяет нашим запросам.

Поддержку нагрузки, которая удовлетворяет выдвинутым нами требованиям, обеспечивает фреймворк Mythic. Его микросервисная архитектура позволяет легко добавить произвольную функциональность в серверную часть. Например, процесс сборки модуля выполняется в контейнере и должен быть полностью описан нами, поэтому в случае детектирования определенных строк мы сможем заменить их на произвольные значения. Кроме того, Mythic поддерживает как стандартные протоколы коммуникации (HTTPS, TCP), так и скрытые каналы, например реализацию зашифрованных коммуникаций через Slack или Telegram. Наконец, использование языка C обеспечивает маленький размер нагрузки. Все перечисленное делает фреймворк Mythic и взаимодействующий с ним агент, который выполняет BOF-файлы, оптимальным вариантом для запуска второго модуля.

Модель связи

В процессе коммуникации агента и фреймворка нам нужно сфокусироваться на трех элементах: контейнеры с полезной нагрузкой (Payload Containers), контейнеры профилей C2 (C2 Profile Cоntainers) и контейнер расшифровки (Translation Container). Контейнеры с полезной нагрузкой содержат исходный код агента и отвечают за сборку нагрузки, а контейнеры профилей C2 отвечают за общение с агентом. Они должны принимать трафик от агента и отправлять его в Mythic для дальнейшей обработки. Контейнер расшифровки отвечает за шифрование и расшифровку трафика. Мы воспользуемся протоколом HTTP при работе с Mythic, в таком случае в роли профиля С2 выступает веб-сервер, который слушает порт 80\443.

Модель коммуникации агента и фреймворка Mythic

Модель коммуникации агента и фреймворка Mythic

Загрузка объектного файла

Для загрузки и выполнения объектного файла агенту необходимо прочитать секцию файла .text и заменить все нули на относительные адреса внешних функций и статических данных. Этот процесс называется релокацией символов, на которые ссылается конкретная секция объектного файла. Кроме того, агент размещает эти символы в памяти, например после секции с кодом.

Чтобы найти внешние функции, потребуется проанализировать библиотеки, указанные в директивах компоновщика объектного файла. Для этого мы воспользовались функциями LoadLibrary, GetModuleHandle и GetProcAddress.

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

Представление объектного файла на диске (слева) и в памяти (справа)

Представление объектного файла на диске (слева) и в памяти (справа)

Недостатки решения

У описанного метода есть ряд недостатков. Выполнение объектных файлов является блокирующим, поэтому одновременный запуск нескольких задач исключен. Для долгосрочных задач необходимо использовать другие методы (например, инъекцию в процесс), однако для работы второго модуля это не является критическим недостатком, поскольку для него не предполагаются длительные задачи.

Ряд недостатков сложно компенсировать. Так, поскольку выполнение объектного файла происходит в текущем потоке, то в случае критической ошибки процесс завершается. Кроме того, во время выполнения объектного файла в памяти разметка секций и релокация используют функцию VirtualAlloc. Вызов этого WinAPI может привлечь внимание защитного решения.

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

Заключение

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

Тестирование на проникновение: оптимизируем работу с помощью агента Mythic

Ваш e-mail не будет опубликован. Обязательные поля помечены *

 

Отчеты
Подпишитесь на еженедельную рассылку

Самая актуальная аналитика – в вашем почтовом ящике