You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1380 lines
106 KiB
1380 lines
106 KiB
БЫСТРЫЙ СТАРТ ПО ТЕХНИКАМ СКРЫТИЯ, ВНЕДРЕНИЯ И ЗАЩИТЫ В ОС WINDOWS
|
|
|
|
ВВЕДЕНИЕ
|
|
|
|
|
|
Следует помнить, что ни одна из рассматриваемых техник защиты или атаки не является абсолютной.
|
|
Для каждой есть меры противодействия.
|
|
Некоторые техники используются несмотря на устаревание, т.к.:
|
|
- гарантируют запуск на старых ОС, коих всегда будет много;
|
|
- ничего не изобрели вместо.
|
|
|
|
Параллельно с этой методичкой рекомендуется к прочтению цикл статей "Malware development" в блоге https://0xpat.github.io
|
|
|
|
I. ТЕХНИКИ СКРЫТИЯ И ВНЕДРЕНИЯ
|
|
|
|
Windows позволяет манипулировать процессами в очень широких пределах,
|
|
вследствие наличия набора системных вызовов CreateRemoteThread(), ReadProcessMemory(), WriteProcessMemory().
|
|
Назначение этих вызовов - обеспечение работы отладчиков (из этого логически следует, что подобные
|
|
механики доступны во всех ОС, позволяющих отлаживать сторонний процесс.
|
|
В Linux они тоже есть: см.ptrace,
|
|
https://habr.com/post/430302/
|
|
https://github.com/gaffe23/linux-inject
|
|
https://www.evilsocket.net/2015/05/01/dynamically-inject-a-shared-library-into-a-running-process-on-androidarm/ ).
|
|
Интересная техника инъекции без ptrace: https://github.com/DavidBuchanan314/dlinject
|
|
Простенький инжектор под Линукс: https://stackoverflow.com/questions/24355344/inject-shared-library-into-a-process
|
|
|
|
|
|
Поэтому внедрение в другие процессы и манипуляция ими (в пределах прав доступа) - дело техники.
|
|
|
|
1. ИНЪЕКЦИЯ В ПРОЦЕСС
|
|
|
|
Инъекция в процесс нужна для выполнения своего кода в чужом процессе того же пользователя, в ситуации, когда уже есть доступ в систему.
|
|
Классическая цель - броузеры (перехват и замена трафика для реализации атаки MITM), мессенджеры, почтовые клиенты итд.
|
|
Последовательность вызовов примерно такая:
|
|
|
|
OpenProcess - открываем чужой процесс
|
|
VirtualAlloc - аллоцируем в нем память
|
|
VirtualProtect - разрешаем выполнение этой памяти
|
|
WriteProcessMemory - пишем свой шелл-код в эту память
|
|
CreateRemoteThread - запускаем шелл-код в виде нового потока
|
|
|
|
Если шелл-код короткий и написан с относительной адресацией, этого как правило и достаточно.
|
|
Но это редкий случай, такой код пишется как правило на ассемблере.
|
|
Более часто нужно выполнить большие куски логики, оформленные в виде dll.
|
|
Для запуска dll в чужом процессе эту dll нужно скопировать в чужую память,
|
|
и настроить ее - прописать весь импорт, настроить адреса ф-й итд.
|
|
В обычной жизни этим занимается функция LoadLibrary.
|
|
Но это слишком приметная функция, которая кроме того обращается к диску.
|
|
Полностью бездисковую инъекцию из памяти реализуют две библиотеки:
|
|
|
|
https://github.com/stephenfewer/ReflectiveDLLInjection
|
|
https://github.com/dismantl/ImprovedReflectiveDLLInjection
|
|
|
|
Вторая библиотека - просто улучшение первой:
|
|
- работает кросс-разрядная инъекция (32->64, 64->32, 32->32, 64->64)
|
|
|
|
Принципиально, что в реализации есть инъектируемый загрузчик, использующий только относительную адресацию.
|
|
Инъекция проходит так:
|
|
- в один кусок памяти записывается загрузчик
|
|
- в другой кусок памяти записывается dll
|
|
- управление передается загрузчику
|
|
- загрузчик ищет в таблице импорта функции LoadLibrary и GetProcAddress по хешам их имен
|
|
- загрузчик ищет в памяти dll и настраивает её
|
|
- после настройки загрузчик передает управление на DllMain
|
|
|
|
Эту технику можно улучшить, если переделать инъектируемый загрузчик во внешний:
|
|
- он будет выполняться из атакующего процесса, а не изнутри атакуемого
|
|
- в нем нужно заменить все функции работы с памятью на WriteProcessMemory/ReadProcessMemory.
|
|
Исходников готовой реализации пока в сети не встречалось, но в природе такая реализация есть.
|
|
|
|
Рефлективная загрузка dll в собственный процесс: https://github.com/fancycode/MemoryModule
|
|
|
|
Рефлективная загрузка 80-го левела: https://github.com/bats3c/DarkLoadLibrary/blob/master/DarkLoadLibrary/src/ldrutils.c
|
|
https://www.mdsec.co.uk/2021/06/bypassing-image-load-kernel-callbacks/
|
|
Заявлен обход ядерных триггеров на загрузку образа в память, хотя чем это отличается от рефлективной загрузки не очень ясно
|
|
(UPD: сообщают что запись о модуле не попадает в PEB)
|
|
|
|
Дополнительно, выполнение произвольного шелл-кода в контексте текущего процесса:
|
|
https://github.com/DimopoulosElias/SimpleShellcodeInjector/blob/master/SimpleShellcodeInjector.c
|
|
|
|
|
|
2. ПЕРЕХВАТ ФУНКЦИЙ (ХУКИ)
|
|
|
|
Известная не один десяток лет техника:
|
|
- в прологе большинства системных функций есть несколько nop (до 5-и), предусмотренных
|
|
специально для этой цели
|
|
- пролог функции заменяется jmp на наш обработчик
|
|
- обработчик вызывает оригинальную функцию по смещению пролога после nop (или не вызывает - зависит от логики)
|
|
|
|
Чтобы все отработало без ошибок, сигнатура нашей функции-обработчика должна полностью совпадать по типам данных,
|
|
возврата и соглашению о вызовах.
|
|
|
|
Если специального пролога нет, хук все равно можно поставить - не всегда. Нужно смотреть на содержимое пролога.
|
|
Просто затираемые jmp инструкции нужно скопировать и перенести в тело нового обработчика - но там творческий подход,
|
|
и универсальных рецептов нет.
|
|
|
|
Компилятор Microsoft имеет переключатель: свойства проекта -> C/C++ -> Создание кода -> Создать образ с обновлением
|
|
(patchable image) специально для цели генерации пустых прологов функций.
|
|
|
|
Такой хук еще называют трамплином, detour или inline-хуком.
|
|
|
|
В статье "Trampolines In x64" https://www.ragestorm.net/blogs/?p=107 можно посмотреть вариации трамплинов.
|
|
|
|
В данной статье https://www.malwaretech.com/2013/10/ring3-ring0-rootkit-hook-detection-22.html
|
|
расписано больше видов хуков (в т.ч. в ring0) - IAT hooks, inline hooks, SSDT hooks, SYSENTER_EIP Hooks, IRP Major Function Hook
|
|
|
|
|
|
3. PROCESS HOLLOWING
|
|
|
|
Process Hollowing (aka RunPE) - это Windows-реализация аналога пары сисвызовов fork()/exec() из Unix. То есть, запуск процесса,
|
|
и замещение его текста другим исполняемым модулем, c настройкой его в памяти процесса, и дальнейший запуск с точки входа.
|
|
В Windows вместо fork()/exec() используется CreateProcess(), делающий сразу и fork() и exec().
|
|
Т.е. происходит замещение текста процесса, которым управлять мы не можем.
|
|
Потому реализацию замены текста, настройки импорта и релокаций нужно делать самому, что достаточно сложно
|
|
и по сути дублирует системный загрузчик процессов ОС Windows.
|
|
|
|
Преимущества такого трюка в том, что:
|
|
- наш код выглядит как другой процесс
|
|
- другой процесс может быть доверенным (trusted) процессом ОС (explorer, svchost),
|
|
добавленный в исключения UAC, файрволла и антивирусов.
|
|
|
|
Реализация с подробным описанием доступна по адресу
|
|
https://github.com/m0n0ph1/Process-Hollowing
|
|
|
|
Антивирусы распознают process hollowing сравнением текста процесса в памяти и на диске.
|
|
|
|
Реализация на VBScript, для использования в макросах-дропперах:
|
|
https://github.com/itm4n/VBA-RunPE
|
|
|
|
4. PROCESS DOPPELGäNGING
|
|
|
|
Назначение техники то же самое - скрыть название настоящего запускаемого процесса.
|
|
Суть исполнения иная.
|
|
|
|
- открывается NTFS-транзакция на запись в какой-нибудь исполняемый файл. Как обычно, это будет
|
|
кто-нибудь из доверенных процессов - svchost, explorer итд.
|
|
- тело .exe заменяется нашим текстом
|
|
- процесс запускается
|
|
- транзакция откатывается. Физическая запись в тело файла не происходит.
|
|
|
|
Для всех остальных процессов выглядит так, как будто бы запускается оригинальный файл.
|
|
Но открывший транзакцию поток видит новый текст в запускаемом файле.
|
|
|
|
Техника успела устареть, т.к. начиная с какой-то версии Windows 10 транзакции NTFS вроде бы отменили совсем.
|
|
|
|
Реализация доступна по адресу
|
|
https://github.com/hasherezade/process_doppelganging/blob/master/main.cpp
|
|
|
|
Описание на английском:
|
|
https://hshrzd.wordpress.com/2017/12/18/process-doppelganging-a-new-way-to-impersonate-a-process/
|
|
|
|
Есть комбо из двух техник:
|
|
Process Doppelgänging combo Process Hollowing
|
|
https://blog.malwarebytes.com/threat-analysis/2018/08/process-doppelganging-meets-process-hollowing_osiris/
|
|
Transacted hollowing
|
|
https://github.com/hasherezade/transacted_hollowing
|
|
|
|
4.1. PROCESS HERPADERPING
|
|
|
|
https://jxy-s.github.io/herpaderping/
|
|
https://github.com/jxy-s/herpaderping.git
|
|
|
|
Техника похожа на Process doppelganging:
|
|
- настоящий текст программы пишется в файл и запускается CreateProcess
|
|
- до запуска реального потока текст затирается шумом (например, текстом программы-хоста)
|
|
- используется race condition в Windows Defender, чтобы подсунуть ему левый текст программы
|
|
|
|
|
|
5. ЗАМЕНА PEB
|
|
|
|
Легковесная техника для скрытия процесса постфактум.
|
|
PEB - это Process Environment Block, структура с основной информацией о процессе, присутствует в каждом процессе.
|
|
В ней в частности есть имя процесса и его командная строка. Их можно заменить как изнутри процесса, так и извне
|
|
(приостановив потоки процесса с помощью SuspendThread(), заменив данные WriteProcessMemory() и возобновив потоки
|
|
с помощью ResumeThread()). После этого в списке процессов видны измененные имя процесса и командная строка.
|
|
|
|
Еще один интересный прием - затирание таблицы экспорта .dll после загрузки в память.
|
|
После того, как получены адреса всех необходимых адресов функций, можно затереть весь экспорт и таким образом
|
|
осложнить идентификацию процесса по известным/уникальным именам функций.
|
|
|
|
Дополнительно, можно затереть секцию с ресурсами, если они не используются (либо после того как они были подгружены).
|
|
Словом, вариации с подменой и затиранием служебных таблиц/областей ограничена лишь фантазией.
|
|
|
|
6. SHELL CODE
|
|
|
|
Название идет с былинных времен, когда инъектируемый код был призван получить remote shell на атакуемой машине.
|
|
Потому код должен был удовлетворять требованиям:
|
|
- быть кратким насколько возможно (чтобы затереть чем поменьше в атакуемом процессе)
|
|
- быть позиционно-независимым (только относительная адресация)
|
|
|
|
Ныне, shell code обозначает любую вставку машинного кода вне зависимости от контекста применения.
|
|
Однако типичный контекст по-прежнему - инъекция в процесс, например грубо в кусок исполняемого потока (чтобы обойти DEP).
|
|
Так что указанные выше требования в силе.
|
|
|
|
Типичный shell code для процессов Windows делает bootstrapping (в том числе для обхода ASLR):
|
|
- определяет важные вехи в памяти - указатели на TEB и PEB
|
|
- из PEB получает адрес таблицы импорта
|
|
- из таблицы импорта получает адрес kernel32.dll
|
|
- из kernel32.dll получает адреса LoadLibrary, GetProcAddress (обычно по хешу имени, а не по самому имени)
|
|
- когда есть LoadLibrary и GetProcAddress, можно делать все что угодно.
|
|
https://habr.com/ru/post/522966/
|
|
http://www.hick.org/code/skape/papers/win32-shellcode.pdf
|
|
(У этого чувака http://www.hick.org/~mmiller/ кстати есть куча интересного, хотя и устаревшего)
|
|
https://www.corelan.be/index.php/2010/02/25/exploit-writing-tutorial-part-9-introduction-to-win32-shellcoding/
|
|
|
|
Этот же код можно написать на Си, не используя ассемблер.
|
|
Пример - функция ReflectiveLoader() https://github.com/dismantl/ImprovedReflectiveDLLInjection/blob/master/dll/src/ReflectiveLoader.c
|
|
|
|
Hell's Gate: разбор поиска системных вызовов в позиционно-независимом коде на Си
|
|
https://vxug.fakedoma.in/papers/VXUG/Exclusive/HellsGate.pdf
|
|
|
|
Конвертер PE->shell
|
|
https://github.com/hasherezade/pe_to_shellcode
|
|
|
|
7. INJECT PE / INFECT PE
|
|
|
|
Внедрение нагрузки в существующий PE-файл:
|
|
https://github.com/secrary/InfectPE/
|
|
https://github.com/JonDoNym/peinjector
|
|
|
|
В файл добавляется код распаковки (загрузчик) и нагрузка, переправляется оригинальная точка входа на загрузчик.
|
|
Так можно к легальному софту цеплять свои нагрузки.
|
|
Цифровые подписи разумеется слетают.
|
|
|
|
|
|
II. ЗАЩИТНЫЕ ТЕХНИКИ
|
|
|
|
|
|
КАК РАБОТАЮТ АНТИВИРУСЫ
|
|
|
|
АВ получают инфу о том что происходит в системе одним из двух путей:
|
|
- подписываясь на события ядра с помощью Event Trace for Windows (ETW) https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/event-tracing-for-windows--etw-
|
|
- подключая свой драйвер-минифильтр в режиме ядра (ring0), и подписываясь таким образом на активность файловой системы и подобные события (Windows Defender, Eset, WebRoot, McAfee)
|
|
- проставляя свои хуки в режиме пользователя (ring3) непосредственно в исполняемые процессы (Avast, BitDefender, Symantec, TrendMicro) на функции из ntdll.dll, user32.dll, kernel32.dll итд.
|
|
В первом случае ничего поделать нельзя, во втором случае хуки можно снять.
|
|
|
|
УСТРОЙСТВО WINDOWS DEFENDER
|
|
|
|
Windows Defender использует драйвер типа minifilter под названием WdFilter для подписки на события в системе.
|
|
Перехватываются:
|
|
- создание и запуск процесса
|
|
- загрузка образа процесса
|
|
- запуск потоков
|
|
- манипуляции с неродным процессом - запись в память и запуск удаленного потока
|
|
- верифицируются загружаемые драйвера
|
|
- перехватываются операции с реестром.
|
|
|
|
Из всего полезного что удалось найти в разборе - список условий, при которых можно избежать такого внимания:
|
|
- белый список процессов (в него входят в т.ч. svchost, werfault и процессы самого WinDefender)
|
|
- список hardened ключей реестра
|
|
|
|
https://n4r1b.com/posts/2020/01/dissecting-the-windows-defender-driver-wdfilter-part-1/
|
|
https://n4r1b.com/posts/2020/02/dissecting-the-windows-defender-driver-wdfilter-part-2/
|
|
https://n4r1b.com/posts/2020/03/dissecting-the-windows-defender-driver-wdfilter-part-3/
|
|
https://n4r1b.com/posts/2020/04/dissecting-the-windows-defender-driver-wdfilter-part-4/
|
|
|
|
УСТРОЙСТВО ЭМУЛЯТОРА
|
|
|
|
Эмулятор АВ предназначен для дополнительного анализа возможного поведения программы при статическом анализе бинарника:
|
|
https://findpatent.ru/patent/251/2514141.html
|
|
1) эмулятор не выполняет все системные вызовы, делая вызов "заглушек". Особо нужные для функционирования программы может выполнять (типа аллокации памяти),
|
|
но в общем случае - нет;
|
|
2) эмулятор больше интересуют последовательности системных вызовов, чем их результат;
|
|
3) в некоторых АВ эмулятор выполняет все ветвления в коде вне зависимости от выполнения условий (по некоторым свидетельствам VBA32).
|
|
Для того чтобы заглянуть во все ветки кода.
|
|
4) эмулятор ограничен по времени работы (порядка десятков секунд, либо по количеству выполненных системных вызовов).
|
|
|
|
В некоторых АВ эмулятор начинается с внедренных в ваш код хуков.
|
|
Детект эмулятора Avast:
|
|
// Противодействие Avast CyberCapture.
|
|
BYTE* A = (BYTE*)GET_API(SendMessageA); // Любая функция, на которую Avast ставит ловушку
|
|
if (A[0] == 0xe9) // Если первая команда - JMP
|
|
{
|
|
// В песочнице Avast ставит ловушки с переходом на адрес, по которому записана последовательность байтов FF25 00000000 (еще один JMP)
|
|
// т.е. характерным признаком эмулятора Аваст является два последовательных JMP, E9 и FF 25 в прологе вашей функции
|
|
// В нормальном режиме Аваст также ставит хуки, но их меньше, и они ведут на адреса насильно внедренной в процесс aswhook.dll
|
|
SIZE_T W = (SIZE_T)(A + 5) + (SIZE_T)(*(INT32*)(A + 1));
|
|
if (*(WORD*)W == 0x25FF && *(DWORD*)(W + 2) == 0)
|
|
{
|
|
debug_printfA(ORANGE, "Avast CyberCapture (sandbox) detected\n");
|
|
GET_API(ExitProcess)(-1);
|
|
}
|
|
}
|
|
|
|
Устройство ЧАСТИ обнаруживающего shell-код эмулятора BitDefender описано тут https://habr.com/ru/company/skillfactory/blog/527512/
|
|
Исходники эмулятора доступны https://github.com/bitdefender/bddisasm
|
|
Триггеры эмулятора:
|
|
- определение shell-кода в памяти:
|
|
- доступ к регистру указателя инструкций EIP/RIP
|
|
- доступ к структурам TEB/PEB
|
|
- поиск системных функций типа GetProcAddress
|
|
- самомодификация (расшифровка на месте)
|
|
- расшифровка строк на стеке
|
|
- выполнение стека
|
|
- использование SYSCALL вместо точек входа в библиотечных .dll
|
|
- в режиме ядра
|
|
- специфические инструкции типа SWAPGS
|
|
- доступ к регистру MSR
|
|
- доступ к KPCR (Область управления процессором ядра)
|
|
|
|
ПРОТИВОДЕЙСТВИЕ АНТИВИРУСАМ
|
|
|
|
Есть два вида детектов антивирусов (далее АВ):
|
|
- статический (по сигнатуре)
|
|
- динамический (по поведению).
|
|
|
|
С первым бороться легко, со вторым трудно.
|
|
|
|
Вдобавок, АВ используют нечеткое хеширование (fuzzy hashing (ssdeep, imphash)), нейросети и байесовские фильтры, чтобы обнаруживать неизвестную ранее малварь
|
|
по степени подобия текста или поведения уже известным образцам:
|
|
https://xakep.ru/2020/09/28/clear-hash/
|
|
|
|
АВ в обязательном порядке ставят детекты на известные строки и импорт функций.
|
|
|
|
Необходимые (но недостаточные) меры по защите от АВ:
|
|
- обфускация строк
|
|
- обфускация импорта (т.е. импортируемых из сторонних .dll функций)
|
|
- внесение шума в код
|
|
- шифрование кода с расшифровкой перед выполнением.
|
|
|
|
Дополнительные меры по противодействию АВ:
|
|
- отключение АВ (при достаточных правах)
|
|
- снятие хуков (только для АВ, работающих в userland)
|
|
|
|
Известна техника KHOBE (Kernel HOoks Bypassing Engine). В паблике отсутствует код, известны лишь общие сведения.
|
|
Нужно использовать race condition (чей?), предъявляя для анализа благополучный код в момент и быстро переключить контекст сразу после анализа АВ.
|
|
|
|
Подробнее см.раздел "Чистка от антивирусных детектов".
|
|
|
|
|
|
ПОИСК СИГНАТУР В ИЗВЕСТНЫХ БД
|
|
|
|
Декодер правил Windows Defender:
|
|
https://github.com/hfiref0x/WDExtract
|
|
|
|
Самый простой способ - поищите уже известные сигнатуры в базе сигнатур YARA.
|
|
Yara - это свободное средство для сигнатурного анализа малвари
|
|
https://virustotal.github.io/yara/
|
|
Но сами правила от него не выложены централизованно.
|
|
Есть коммерческие сборники правил, например
|
|
https://www.nextron-systems.com/2018/12/21/yara-rule-sets-and-rule-feed/
|
|
Есть бесплатные низкого качества https://github.com/Neo23x0/signature-base/
|
|
Большой сборник баз, среди которых есть и шлак, и актуальные: https://github.com/InQuest/awesome-yara
|
|
Синтаксис и возможности правил: https://habr.com/ru/company/varonis/blog/584618/
|
|
|
|
|
|
Можно конвертировать БД ClamAV в человеко-понятный формат Yara и далее искать нужные детекты:
|
|
https://resources.infosecinstitute.com/topic/yara-simple-effective-way-dissecting-malware/
|
|
> YARA with ClamAV Rules
|
|
>
|
|
> YARA can be integrated with ClamAv rule database. Perform the below steps to integrate ClamAv rules with YARA:
|
|
>
|
|
> Download the ClamAV to YARA Python script here: https://code.google.com/p/malwarecookbook/source/browse/trunk/3/3/clamav_to_yara.py
|
|
> Download and unpack the ClamAV db: http://database.clamav.net/main.cvd
|
|
> Run the ClamAV to YARA Python script:
|
|
> python clamav_to_yara.py –f main.cvd –o testing_clamav.yara
|
|
> Now test the converted rules with YARA like below:
|
|
> yara –r testing_clamav.yara /directory/to/check"
|
|
|
|
|
|
ОТКЛЮЧЕНИЕ WINDOWS DEFENDER
|
|
|
|
Иногда АВ можно просто отключить, в частности можно добавить себя в исключения Windows Defender (не всегда) здесь
|
|
HKLM|HKCU\MACHINE\SOFTWARE\Microsoft\Windows Defender\Exclusions\Paths
|
|
HKLM|HKCU\MACHINE\SOFTWARE\Policies\Microsoft\Windows Defender\Exclusions\Paths
|
|
И примерно в том же месте вовсе отключить АВ.
|
|
Заметьте, что это делается через политики!
|
|
|
|
|
|
ОБФУСКАЦИЯ СИСТЕМНЫХ ВЫЗОВОВ
|
|
|
|
Простейшая техника - получение адреса функции с помощью GetProcAddress(LoadLibrary(decode("lib.dll"), decode("funcname"))
|
|
Однако здесь светятся вызовы GetProcAddress и LoadLibrary.
|
|
|
|
Старая, но до сих пор действенная техника GetApi была применена в троянце Carberp:
|
|
https://github.com/hzeroo/Carberp/blob/master/source%20-%20absource/pro/all%20source/RemoteCtl/DrClient/GetApi.h
|
|
|
|
Суть ее в поиске функций в таблице импорта по хешу их имени. Это сбивает сигнатурные детекты, хотя и доступно автоматизированному анализу
|
|
в дизассемблерах. Метод хеширования можно периодически менять.
|
|
|
|
Другой подход - cистемные вызовы inline - суем весь boilerplate-код подготовки сисвызова в ассемблер
|
|
https://github.com/JustasMasiulis/inline_syscall
|
|
|
|
Библиотека заменителей некоторым вызовам WinAPI:
|
|
https://github.com/vxunderground/WinAPI-Tricks
|
|
|
|
В конечном итоге, системные вызовы все равно ловятся АВ, работающих в режиме ядра через подписки на перехват вызовов.
|
|
|
|
ОБФУСКАЦИЯ КОДА
|
|
|
|
Обычно код в виде .dll сжимают, шифруют и пакуют в массив (см.ниже Скрытие данных в сегменте кода),
|
|
во время выполнения аллоцируют память, извлекают и распаковывают код, далее настраивают .dll в памяти
|
|
(релокации, импорт и все такое). См.ниже про крипторы и упаковщики - это оно и есть.
|
|
Этот трюк известен АВ и от проактивной защиты такое не спасает.
|
|
|
|
Потому мысль продвинулась дальше:
|
|
|
|
1. Распаковка каждой функции непосредственно перед выполнением.
|
|
В каждой функции определяется пролог и эпилог, который расшифровывает и шифрует тело функции соответственно.
|
|
Для поиска границы функции используются сигнатуры.
|
|
Для изначального шифрования функций в файле требуется внешний кодировщик.
|
|
Возможны и другие варианты декодирования на лету, но все они сложны в реализации.
|
|
|
|
2. собственные JIT-интерпретаторы.
|
|
Например, https://github.com/jacob-baines/jit_obfuscation_poc
|
|
Идея ясна из названия - транслируем один код в другой код, который неизвестен антивирусам и недоступен
|
|
автоматическому реверсу и анализу.
|
|
|
|
VMProtect-2 - обфусцирующая виртуальная машина
|
|
https://back.engineering/tags/vmprotect-2/
|
|
|
|
Есть интересный проект обфусцирующего компилятора на основе LLVM:
|
|
https://github.com/obfuscator-llvm/obfuscator
|
|
и пояснения по его алгоритмам
|
|
https://0xpat.github.io/Malware_development_part_6/
|
|
Еще один коммерческий:
|
|
http://www.star-force.ru/products/starforce-obfuscator/
|
|
|
|
Интересный подход к расшифровке кода - получение ключа расшифровки с сервера.
|
|
Это дает определенный эффект против эмуляторов АВ.
|
|
|
|
ОБФУСКАЦИЯ СТРОК
|
|
|
|
До появления constexpr обфускацию строк делали сторонней утилитой и двухпроходной сборкой:
|
|
- строки в коде помечались специальными маркерами, как правило в глобальной таблице строк
|
|
- обращение к строкам происходило через функцию дешифровки, по ее индексу в таблице
|
|
- утилита проходила по готовому .exe и замещала их шифротекстом.
|
|
|
|
Такой подход очень усложнял отладку и требовал дополнительных этапов сборки,
|
|
делая код нечитаемым.
|
|
|
|
constexpr позволяет сделать шифрование строки на этапе сборки, решая все перечисленные проблемы.
|
|
Однако это работает в Visual Studio не ниже версии 2015, требуя C++ стандарта 14.
|
|
Готовая библиотека шифрования Andrivet ADVObfuscator:
|
|
https://github.com/andrivet/ADVobfuscator
|
|
Также есть
|
|
https://github.com/Snowapril/String-Obfuscator-In-Compile-Time (основан на Andrivet)
|
|
https://github.com/adamyaxley/Obfuscate
|
|
https://github.com/fritzone/obfy
|
|
https://github.com/revsic/cpp-obfuscator
|
|
|
|
Обфускация работает на максимальных настройках оптимизации в Visual Studio:
|
|
- C/C++/ Оптимизация: Полная оптимизация
|
|
- C/C++/ Оптимизация / Оптимизация всей программы: Вкл
|
|
- C/C++/ Оптимизация / Разворачивать inline-функции: отключить
|
|
- C/C++/ Создание кода / Включить объединение строк: Да
|
|
Однако этот параметр надо пробовать, влияет когда как, по-разному на x64/x86
|
|
- другие настройки оптимизации тоже нужно пробовать, могут влиять.
|
|
|
|
Комментарий разработчика насчет того, что обфускатор не работает на полной оптимизации для компиляции х86:
|
|
"...почему обфускатор строк не всегда работает.
|
|
Дело в методе decrypt, получается когда включена оптимизация разворачивать подставляемые функции,
|
|
компилятор по месту вызова этого метода вставляет его тело, а так как в этом теле используются выражения, которые он может просчитать во время компиляции,
|
|
то и расшифровывает строку он получается во время компиляции.
|
|
Получается он зашифровал и расшифровал строку во время компиляции.
|
|
Исправляется отключением оптимизации разворачивать подставляемые функции."
|
|
|
|
Из известных недостатков инлайн-обфускаторов - ограничение на длину строк.
|
|
Каждый дополнительный символ в строке - это дополнительная рекурсия компилятора при вычислениях на этапе компиляции.
|
|
Стек у MSVC2015 кончается на длинах примерно в 100 символов.
|
|
|
|
Есть также простой трюк, используемый при отсутствии С++ (в чистом Си)
|
|
char str[] = { 'H', 'E', 'L', 'L', 'O' };
|
|
В такой инициализации строка заносится в массив на стеке mov'ами в во время выполнения, и как строка не попадет в сегмент .data
|
|
(т.е. превратится в набор ассемблерных инструкций в .text такого вида:
|
|
|
|
mov edx, 8EB5h
|
|
push edx
|
|
mov edx, 6C6CD488h
|
|
push edx
|
|
итд
|
|
|
|
кстати, расшифровка строки по месту выглядит примерно так:
|
|
|
|
mov edx, 8EB5h
|
|
xor edx, 8EDAh
|
|
push edx
|
|
mov edx, 6C6CD488h
|
|
xor edx, 0B1C0h
|
|
push edx
|
|
mov esi, esp
|
|
sub esp, 20h
|
|
mov edx, 0F478h
|
|
xor edx, 0F459h
|
|
push edx
|
|
mov edx, 74690CD7h
|
|
xor edx, 2CB2h
|
|
push edx
|
|
|
|
Чистая же строка выглядит в дизассемблере так:
|
|
|
|
.code:004010A5 aTest001 db 'Test001',0
|
|
.code:004010AD aLoremIpsumDolo db 'Lorem ipsum dolor sit amet',0
|
|
|
|
)
|
|
|
|
char str[] = "HELLO"; заполнится во время компиляции как строка и попадет в .data.
|
|
|
|
ОБФУСКАЦИЯ ТОЧКИ ВХОДА
|
|
|
|
Эта мера используется для противодействия АВ-эмуляторам и ручному анализу.
|
|
Реальная точка входа отличается от декларируемой в PE/ELF-заголовках.
|
|
К примеру, в .dll есть фальшивый безобидный экспорт (какой-нибудь DllMain, DoTheWork итд), выполняющий какие-то действия для отвода глаз.
|
|
Для запуска же реальной нагрузки нужно дернуть не проэкспортированную функцию по известному лишь запускающему контексту адресу.
|
|
Другой вариант - использование DOS-заглушки. Смена сигнатуры MZ на любую другую в двоичном файле PE приведет к запуску бинарника в режиме DOS.
|
|
Как следствие, АВ проигнорирует истинную точку входа.
|
|
В 16-битном же режиме эмуляторы не работают; через функцию 4B прерывания DOS можно запустить сторонний бинарь.
|
|
Это можно использовать в технике "разрыв цепочки".
|
|
|
|
СКРЫТИЕ ДАННЫХ В СЕГМЕНТЕ КОДА
|
|
|
|
АВ чутко реагируют на необычно большую секцию данных (.data, .rdata) - это признак сокрытия в ней зашифрованного кода-нагрузки.
|
|
Данные можно скрывать в секции текста. Компилятор Microsoft C++ позволяет сделать это с помощью такого трюка:
|
|
|
|
#pragma code_seg(push, ".text")
|
|
#pragma code_seg(pop)
|
|
unsigned char __declspec(allocate(".text")) hiddencode[]={ ... };
|
|
|
|
По подобному принципу можно складывать нагрузку в другие секции, прагмами/declspec data_seg, const_seg.
|
|
Правда, линкер может плодить секции с одинаковыми именами и разными правами доступа, потому есть еще такой вариант:
|
|
|
|
#pragma comment(linker,"/SECTION:.data,EW")
|
|
unsigned char PayloadName0[]={}
|
|
#pragma comment(linker,"/SECTION:.rdata,R")
|
|
unsigned char PayloadName2[]={}
|
|
|
|
Противодействие этой мере со стороны АВ - частотный анализ секции кода. У секции кода низкая энтропия,
|
|
т.к. число опкодов ограничено, и статистическое распределение символов в коде имеет четко выраженную структуру.
|
|
Потому скрытие шифрованных и/или упакованных массивов достаточно четко отслеживается.
|
|
Этому в свою очередь можно противопоставить слабо меняющие энтропию методики шифрования - к примеру,
|
|
xor 1 байт (разумеется, если в таком массиве скрыт код в виде .dll. Если там другие данные, это не поможет).
|
|
|
|
Про энтропию и вообще как выглядит ваш PE-файл для АВ:
|
|
https://0xpat.github.io/Malware_development_part_4/
|
|
Померять энтропию можно DIE (Detect It Easy).
|
|
|
|
КРИПТОРЫ И УПАКОВЩИКИ
|
|
|
|
Надежные реализации упаковщиков известны как минимум с середины 90-х годов.
|
|
Идея проста - один .exe упаковывается внутрь другого .exe, и при выполнении выполняет трюк барона Мюнгхаузена
|
|
по вытаскиванию и запуску нагрузки из себя.
|
|
Разумеется, это отличное средство для скрытия кода.
|
|
К упаковке добавляется также и шифрование.
|
|
Упаковка может быть многослойной, для затруднения анализа.
|
|
Пик популярности упаковщиков пришелся на 0-е годы.
|
|
|
|
Для определения типа упаковщика применялась программа PEId (прекращена в 2011-м году).
|
|
|
|
Сейчас применяются намного более умные крипторы.
|
|
Криптор вдобавок берет на себя функции обхода эмуляции АВ, детекта песочниц,
|
|
иногда даже обхода UAC и повышения привилегий (вследствие особенностей запуска нагрузки эти функции
|
|
бывает уместно возложить именно на криптор).
|
|
Также, кроме банального вытаскивания нагрузки из шифрованного массива внутри себя,
|
|
хороший криптор генерирует правдоподобные таблицы импорта, правдоподобный код, сбивающий с толку АВ,
|
|
разбавляет энтропию нагрузки, рассовывает нагрузку случайным образом по разным секциям,
|
|
генерирует настоящие ресурсы (строки в локализации), словом делает вид что он настоящая программа.
|
|
Подобный подход описан в https://xss.is/threads/39006/
|
|
|
|
Словом, это защитная оболочка, прячущая ваш код.
|
|
|
|
Конечно крипторы не всесильны, и детекты по поведению они не снимут.
|
|
|
|
Интересный подход к криптостроению: ключ расшифровки нагрузки находится отдельно от крипта и передается через командную строку (или еще как-то):
|
|
https://habr.com/ru/company/solarsecurity/blog/519994/
|
|
|
|
Используем комбо из публичного кода в пакере с нуля
|
|
https://iwantmore.pizza/posts/PEzor.html
|
|
в том числе используя
|
|
упаковщик Donut https://github.com/TheWover/donut
|
|
морфер Shikata Ga Nai https://github.com/EgeBalci/sgn
|
|
|
|
Криптор с открытым кодом:
|
|
https://github.com/oddcod3/Phantom-Evasion
|
|
Еще один:
|
|
https://github.com/ximerus/Kryptonite
|
|
|
|
Протектор с "наномитами":
|
|
https://www.apriorit.com/white-papers/293-nanomite-technology
|
|
Применена блокировка отладки процесса своим собственным отладчиком;
|
|
замена в дочернем потоке ВСЕХ инструкций переходов опкодами INT 3 (отладочное прерывание);
|
|
и формирование адреса перехода в процессе-отладчике.
|
|
|
|
СНЯТИЕ ХУКОВ
|
|
|
|
Для снятия чужих хуков можно использовать сравнение пролога функции в памяти процесса
|
|
с прологом в файле соответствующей .dll. Если они различаются, это признак того, что на функцию проставлен чужой хук.
|
|
Борьба соответствующая: прочесть тело функции из файла и заменить тело функции в памяти.
|
|
Достаточно первых 10 байт.
|
|
Обзор и сравнение разных техник:
|
|
https://www.first.org/resources/papers/telaviv2019/Ensilo-Omri-Misgav-Udi-Yavo-Analyzing-Malware-Evasion-Trend-Bypassing-User-Mode-Hooks.pdf
|
|
Демо: https://github.com/apriorit/antirootkit-anti-splicer
|
|
Еще: https://github.com/CylanceVulnResearch/ReflectiveDLLRefresher
|
|
Детект хуков: https://github.com/asaurusrex/Probatorum-EDR-Userland-Hook-Checker
|
|
Сравнение userland-хуков разных EDR; прямая работа с сисвызовами: https://github.com/Mr-Un1k0d3r/EDRs
|
|
|
|
Имейте в виду, что хуки на ваш процесс могут быть восстановлены после того, как вы их сняли.
|
|
|
|
|
|
ПЕРЕХВАТ ЧУЖИХ ПОТОКОВ (ЗАЩИТА ОТ ИНЪЕКЦИИ)
|
|
|
|
Перехватить чужую инъекцию в процесс можно, поставив свой обработчик на функцию BaseThreadInitThunk().
|
|
Создание нового потока начинается с нее (в том числе, инициированного извне процесса).
|
|
В этом обработчике можно принимать решение, разрешить или заблокировать запуск потока, по определенным признакам.
|
|
Самый простой подход - запустить сразу все свои потоки и далее блокировать все остальное.
|
|
Если это неприемлемо, можно смотреть на адрес и свойства страницы памяти, откуда запускается код.
|
|
У инъектируемого потока это как правило куча (heap). У потока здорового человека это секция текста (.text).
|
|
|
|
В частности, таким образом реализована защита от инъекций у броузера Mozilla Firefox.
|
|
|
|
Этой технике можно успешно противодействовать - извне процесса можно убрать хук на BaseThreadInitThunk
|
|
по описанной выше методике снятия хуков, после чего инъекция возможна.
|
|
|
|
Еще один способ - сразу после старта процесса выкрутить на максимум все митигации (см.ниже) в частности по DEP
|
|
и подписи кода.
|
|
|
|
https://ethicalchaos.dev/2020/06/14/lets-create-an-edr-and-bypass-it-part-2/
|
|
Здесь описана защита процесса с помощью:
|
|
- "невинной" разработки кода
|
|
- снятия хуков
|
|
- работы сисвызовами напрямую
|
|
- митигаций
|
|
- SharpBlock - еще одна техника, использующая перехват старта дочернего потока с помощью событий отладки, и патчинг его точки входа для запутывания EDR.
|
|
|
|
|
|
ЗАЩИТА ПРОЦЕССА ОТ ЗАВЕРШЕНИЯ
|
|
|
|
1. Запрет доступа через дискреционный список контроля доступа (DACL). DACL пустой => процесс сможет убить только админ:
|
|
https://stackoverflow.com/questions/6185975/prevent-user-process-from-being-killed-with-end-process-from-process-explorer
|
|
|
|
2. Пометка процесса как критически важного (RtlSetProcessIsCritical, NtSetInformationProcess).
|
|
Любая попытка остановить такой процесс будет приводить к BSOD;
|
|
при попытке убить такой процесс через Диспетчер Задач будет выведено предупреждение о том, что процесс критически важный
|
|
и его снятие может привести к краху системы.
|
|
Требует права администратора и наличие привилегии SeDebugPrivelege:
|
|
|
|
RtlSetProcessIsCritical:
|
|
https://www.codeproject.com/Articles/43405/Protecting-Your-Process-with-RtlSetProcessIsCriti
|
|
|
|
NtSetInformationProcess со значением параметра ProcessInformationClass = BreakOnTermination:
|
|
http://www.rohitab.com/discuss/topic/40275-set-a-process-as-critical-process-using-ntsetinformationprocess-function/
|
|
|
|
Использование этих вызовов может приводить к падениям.
|
|
Эмпирически установлено, что NtSetInformationProcess с параметром BreakOnTermination стабильно работает на 32-битных ОС,
|
|
а RtlSetProcessIsCritical - на 64-битных.
|
|
|
|
3. Если есть приватный ключ от цифровой подписи кода Microsoft (лол))), то начиная с Windows Vista
|
|
можно сделать любой процесс защищенным от любых изменений извне.
|
|
Также, защищенный родительский процесс может порождать защищенный дочерний процесс,
|
|
используя вызов функции CreateProcess с флагом CREATE_PROTECTED_PROCESS.
|
|
Этот механизм был улучшен в Windows 8.1, но он не идеален и не исключает возможности сделать любой процесс защищенным
|
|
или же снять защиту с системных процессов, имеющих цифровую подпись.
|
|
|
|
Пример создания защищенного дочернего процесса есть в описании функции UpdateProcThreadAttribute на MSDN:
|
|
https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute
|
|
|
|
Статья о защищенных процессах от Alex Ionescu:
|
|
https://www.crowdstrike.com/blog/evolution-protected-processes-part-1-pass-hash-mitigations-windows-81
|
|
https://www.crowdstrike.com/blog/evolution-protected-processes-part-2-exploitjailbreak-mitigations-unkillable-processes-and
|
|
|
|
Презентация от Alex Ionescu:
|
|
http://www.nosuchcon.org/talks/2014/D3_05_Alex_ionescu_Breaking_protected_processes.pdf
|
|
|
|
Пример эксплойта для уязвимости в драйвере Capcom, позволяющий сделать любой процесс защищенным:
|
|
https://www.unknowncheats.me/forum/anti-cheat-bypass/271789-pplib-ppl-processes.html
|
|
https://github.com/notscimmy/pplib
|
|
|
|
Статья с примерами как сделать процесс защищенным и поднять его привилегии, пропатчив память процесса:
|
|
https://www.blackhat.com/docs/asia-17/materials/asia-17-Braeken-Hack-Microsoft-Using-Microsoft-Signed-Binaries-wp.pdf
|
|
|
|
Исходники драйверов, снимающих защиту цифровой подписи:
|
|
https://github.com/Mattiwatti/PPLKiller
|
|
https://github.com/katlogic/WindowsD
|
|
|
|
4. Прочие не самые эффективные способы защиты процессов описаны здесь:
|
|
https://security.stackexchange.com/questions/30985/create-a-unterminable-process-in-windows
|
|
|
|
ЗАЩИТА ПРОЦЕССА ОТ СНЯТИЯ ПРИ ОСТАНОВЕ СИСТЕМЫ (SHUTDOWN)
|
|
|
|
1. Можно установить обработчик событий консоли через вызов SetConsoleCtrlHandler,
|
|
в котором возвращать 0 на события CTRL_LOGOFF_EVENT и CTRL_SHUTDOWN_EVENT.
|
|
- Работает для консольных программ, для которых не выполняются другие обработчики событий консоли.
|
|
- Начиная с Windows 7 обработка событий CTRL_LOGOFF_EVENT и CTRL_SHUTDOWN_EVENT не работает
|
|
для программ, использующих функции библиотек user32.dll и gdi32.dll.
|
|
|
|
Пример на MSDN:
|
|
https://docs.microsoft.com/en-us/windows/console/registering-a-control-handler-function
|
|
|
|
2. Можно вызывать функцию AbortSystemShutdown в бесконечном цикле.
|
|
- требует права администратора и привилегии SeShutdownPrivilege
|
|
- не успевает отработать если выполнить в консоли команду shutdown c ключом /t со значением 0 (таймаут 0 секунд)
|
|
- не спасает от выполнения в консоли команды shutdown с ключом /f
|
|
- на Windows 10 похоже не работает.
|
|
|
|
3. Можно создать невидимое окно и возвращать 0 в обработчике событий окна на события WM_QUERYENDSESSION и WM_ENDSESSION.
|
|
- Начиная с Windows Vista требуется вызывать функцию ShutdownBlockReasonCreate на событии WM_QUERYENDSESSION,
|
|
либо делать скрытие окна вызовом функции ShowWindow со значением второго параметра FALSE (хотя окно и так создается невидимым).
|
|
- от нажатия кнопки принудительного shutdown это никак не спасает.
|
|
- не спасает от выполнения в консоли команды shutdown с ключом /f
|
|
- не работает для консольных программ, в частности бесполезно использовать эту технику внутри dll, запущенной через rundll32
|
|
|
|
Подробнее описано на MSDN:
|
|
https://docs.microsoft.com/en-us/windows/win32/shutdown/shutdown-changes-for-windows-vista
|
|
https://docs.microsoft.com/en-us/previous-versions/windows/desktop/ms700677(v=vs.85)
|
|
|
|
МИТИГАЦИИ
|
|
|
|
см. SetProcessMitigationPolicy()/UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY)
|
|
Позволяет включить у процесса DEP, ASLR, запретить динамическую генерацию кода,
|
|
доп.проверки на проверки подписи, валидности дескрипторов, SEHOP исключений, и много чего еще.
|
|
Этим пользуются броузеры и АВ, выкручивая митигации на максималки с целью затруднить инъекции в них или сковырнуть процесс.
|
|
На Windows 10 это действительно эффективно.
|
|
|
|
Хорошая статья http://www.sekoia.fr/blog/microsoft-edge-binary-injection-mitigation-overview/
|
|
и код к ней
|
|
https://github.com/SekoiaLab/BinaryInjectionMitigation/
|
|
демонстрируют защиту кода митигацией по проверке подписи кода.
|
|
|
|
В этой статье https://habr.com/ru/post/494000/ дан обзор политик митигаций, включая теневой стек, цитата:
|
|
|
|
"Code Integrity Guard (CIG) предъявляет обязательное требование к подписи загружаемых двоичных файлов.
|
|
|
|
Arbitrary Code Guard (ACG) гарантирует, что подписанные страницы неизменны,
|
|
а динамический код не может быть сгенерирован, что гарантирует целостность загружаемых двоичных файлов.
|
|
|
|
С введением CIG и ACG злоумышленники все чаще прибегают к перехвату управления с помощью косвенных вызовов и возвратов,
|
|
известных как Call/Jump Oriented Programming (COP/JOP) и Return Oriented Programming (ROP)."
|
|
|
|
|
|
СЕТЕВАЯ АСИММЕТРИЯ
|
|
|
|
Результаты работы антивируса зависят от страны.
|
|
Большинство производителей АВ решений - страны коллективного Запада.
|
|
Эффективность АВ зависит в основном от проверки нейросетками в "облаке".
|
|
С началом кибер-противостояния РФ-США, последние поставили приоритет всему трафику из своей страны, в ущерб другим странам (в том числе Западной Европы),
|
|
с целью усилить собственную безопасность. По-видимому проверочные мощности не безразмерны.
|
|
Поэтому стала нормальной ситуация, когда одна и та же нагрузка не работает в US и работает в других странах.
|
|
|
|
|
|
ЧИСТКА ОТ АНТИВИРУСНЫХ ДЕТЕКТОВ
|
|
|
|
Перед чисткой нужно первым делом убедиться, что антивирус не сливает образцы:
|
|
- virustotal ВСЕГДА сливает образцы в прямом эфире
|
|
- dyncheck сливает образцы при динамических проверках по поведению. При статических проверках - вроде бы нет
|
|
- у Windows Defender нужно отключить опцию "Отправка образцов"
|
|
- у остальных АВ нужно найти опцию отправки образцов и облачной защиты и отключить их.
|
|
|
|
Общая методика чистки такая:
|
|
1. Находим конкретные строки кода, на которые взводится детект;
|
|
2. Заменяем его.
|
|
|
|
Пункт 1 долгий и нудный, делается так:
|
|
- отключаем комментом или ifdef'ом ВЕСЬ код программы, собираем
|
|
- АВ затыкается
|
|
- раскомментируем половину кода
|
|
- АВ молчит
|
|
- еще половину половины
|
|
- АВ молчит
|
|
- половину половины половины
|
|
- АВ орет -> нашли участок!
|
|
Далее такой же дихотомией доходим до конкретных строчек:
|
|
- строчку раскомментируем - орет, закомментируем - молчит.
|
|
|
|
Учитываем оптимизирующий компилятор: оптимизатор может выкинуть огромный блок кода,
|
|
если не видит влияния этого кода на общее поведение.
|
|
К примеру, если в рамках поиска детекта поставить return посреди тестируемой функции,
|
|
оптимизатор может выкинуть из конечного бинарника и хвост ф-ии, и ее начало,
|
|
т.к. посчитает, что в оставшейся части ф-ии ничего полезного и влияющего на общее выполнение не происходит.
|
|
По такому же принципу оптимизатор выкидывает неожиданные участки кода, что здорово путает карты.
|
|
|
|
Как правило, антивирусные детекты выставляются на:
|
|
- имя бинарного файла (раз засвеченное имя будет давать детекты)
|
|
- Microsoft Visual C++ добавляет строку с именем проекта в бинарник: Свойства проекта -> Общие -> Целевое имя объекта (там по умолчанию стоит $(ProjectName))
|
|
нужно его рандомизировать, или просто затирать нулями/пробелами в пост-событии сборки прямо в бинарнике
|
|
- отдельные системные вызовы (CreateRemoteThread, VirtualProtect, CreateFile, CreateProcess, OpenProcess, работа с реестром, и прочее)
|
|
- последовательности системных вызовов (на отдельные сисвызовы молчит, на последовательность - орёт)
|
|
- открытые строки
|
|
- характерные алгоритмы (генераторы случайных чисел, (де)шифрование, (де)компрессия)
|
|
- высокая энтропия бинарного файла (шифрованые/архивированные массивы, в т.ч. в секции кода)
|
|
|
|
Дополнительно, детект на чистый файл может быть выставлен:
|
|
- При скачивании его с сайта с низкой репутацией (на который уже были комплейны о наличии подозрительных файлов)
|
|
- Как вариант, при скачивании файла из другой страны (влияет как адрес клиента, так и адрес сайта)
|
|
- При отсутствии хэша файла в базе данных АВ (запускаемых файлов в мире ограниченное количество)
|
|
|
|
Под Linux, не забываем убрать символы и лишние строки утилитой strip (а еще лучше sstrip).
|
|
|
|
Системные вызовы либо обфусцируются GetApi.h (можно брать напрямую из carberp/GetApi.h
|
|
https://github.com/hzeroo/Carberp/blob/master/source%20-%20absource/pro/all%20source/RemoteCtl/DrClient/GetApi.h)
|
|
либо, если в GetApi нужный вызов отсутствует, следующей последовательностью:
|
|
|
|
HANDLE h = LoadLibrary(_OBFUSCATED("dll.dll"));
|
|
void* f = GetProcAddress(h, _OBFUSCATED("funcname"));
|
|
|
|
здесь обе строки обфусцированы.
|
|
|
|
Последовательности сисвызовов обфусцируются таким же образом, либо сисвызовы творчески заменяются на аналоги.
|
|
|
|
Как обфусцировать строки см.выше.
|
|
|
|
Характерные алгоритмы мы разбавляем шумовым кодом:
|
|
- добавляем/убираем volatile к локальным переменным
|
|
- меняем место определения локальной переменной в коде (было в прологе ф-ии - ставим ближе к месту использования, и наоборот)
|
|
- добавляем шумовой код между строк (инкремент мусорной volatile переменной, сложения, вычитания, другие операции)
|
|
- такой шумовой код можно оформить в inline-ф-ю или макрос: в отладочной сборке тело ф-ии отключено, в боевой - constexpr'ами
|
|
создаются случайные паттерны кода.
|
|
- энтропию убираем, распихивая куски массива по разным секциям и дополняя массивы неиспользуемыми константными байтами,
|
|
собирая массив перед использованием из кусков.
|
|
|
|
Еще одна тактика снятия детектов - рандомизация адресов функций в итоговом .exe-файле.
|
|
Этого можно добиться простым перемешиванием списка объектных файлов в командной строке компоновщика:
|
|
|
|
link.exe /out:file.exe foo.obj bar.obj --> детект
|
|
link.exe /out:file.exe bar.obj foo.obj --> нет детекта
|
|
|
|
Есть утилита для поиска сигнатур в PE-файлах:
|
|
https://github.com/vxlabinfo/SignFinder
|
|
основана на статьях
|
|
https://vxlab.info/%d1%87%d0%b8%d1%81%d1%82%d0%ba%d0%b0-pe32-%d1%87%d0%b0%d1%81%d1%82%d1%8c-1/
|
|
https://vxlab.info/%d1%87%d0%b8%d1%81%d1%82%d0%ba%d0%b0-pe32-%d1%87%d0%b0%d1%81%d1%82%d1%8c-2/
|
|
сайт уже протух, но остались копии, например здесь
|
|
https://ru-sfera.org/threads/chistka-ot-signaturnogo-detekta-antivirusov.2870/
|
|
а также гуглить чистка-pe32-часть-1 чистка-pe32-часть-2
|
|
|
|
|
|
РЕПУТАЦИЯ ФАЙЛА
|
|
|
|
Файл с новым никому не известным хэшем будет блокироваться АВ просто на всякий случай.
|
|
Это называется "отсутствие репутации".
|
|
Потому обычно файлу накручивают репутацию на подконтрольных машинах: запускают, и при блокировке АВ,
|
|
разблокируют его вручную, добавляют в исключение и заставляют работать.
|
|
Таким же образом работает штатный SmartScreen, и АВ-экран Chrome.
|
|
Описание механизма репутации в Mozilla Firefox:
|
|
https://wiki.mozilla.org/Security/Features/Application_Reputation_Design_Doc
|
|
|
|
РАЗРЫВ ЦЕПОЧКИ
|
|
|
|
При обходе АВ в случае многоступенчатого запуска нагрузки, почти единственный способ избежать обнаружения - это разрыв цепочки запуска.
|
|
Так что родительским процессом у последующих ступеней является не предыдущая ступень, а легитимный файл ОС.
|
|
К примеру, мы хотим из лоадера скачать и запустить вторую ступень нагрузки.
|
|
Если мы сделаем это напрямую, АВ обнаружит связь между лоадером и нагрузкой.
|
|
Если мы добавим в цепочку промежуточное звено (например запуск нагрузки командой AT), то цепочка будет разорвана.
|
|
|
|
Одна добрая душа сделала каталог таких системных утилит и критериев для их использования https://lolbas-project.github.io/
|
|
https://github.com/api0cradle/LOLBAS
|
|
|
|
ПОДМЕНА РОДИТЕЛЬСКОГО ПРОЦЕССА
|
|
|
|
Разновидность разрыва цепочки, разрывающая связь с порождаемым процессом.
|
|
В CreateProcessA передается lpStartupInfo, в lpAttributesList которого указыватся дескриптор желаемого родительского процесса.
|
|
Кстати, таким образом можно повышать привилегии, наследуя контекст безопасности процесса.
|
|
Детали в https://blog.f-secure.com/detecting-parent-pid-spoofing/
|
|
|
|
ZERG RUSH
|
|
|
|
Запускаем 100500 разных хэшей крипта одной и той же нагрузки, перегружая тем самым АВ.
|
|
Если повезет, АВ выпилит только 10499:
|
|
https://habr.com/ru/company/solarsecurity/blog/519994/
|
|
|
|
ОБХОД AMSI
|
|
|
|
AMSI - это Antimalware Scan Interface, антивирусный модуль для анализа кода скриптовых языков Windows.
|
|
Он обрабатывает код на PowerShell, C#, VBScript, JavaScript, Windows Script Host (wscript.exe and cscript.exe),
|
|
макросов Office VBA, и UAC.
|
|
|
|
Краткая суть: анализируем исходники (если надо декомпилируем), только в статике, ставим детекты на строки - имена переменных, строки,
|
|
похожие паттерны, использование мостов для WinAPI.
|
|
Чистим соответственно.
|
|
|
|
Чувак по имени S3cur3Th1sSh1t проделал отличную работу, чтобы систематизировать все методы обхода AMSI.
|
|
|
|
Две статьи описывают принципы работы AMSI и принципы его обхода:
|
|
https://s3cur3th1ssh1t.github.io/Bypass_AMSI_by_manual_modification/
|
|
https://s3cur3th1ssh1t.github.io/Bypass-AMSI-by-manual-modification-part-II/
|
|
TL;DR: AMSI ставит детекты на строки, поэтому активно переименовываем идентификаторы в скриптах,
|
|
клеим строки на лету, используем левые кодировки для хранения скриптов.
|
|
|
|
Сканер детектов (находит строки, на которые выставлен детект):
|
|
https://github.com/RythmStick/AMSITrigger
|
|
|
|
Анти-AMSI обфускатор:
|
|
https://amsi.fail/
|
|
|
|
Техники обхода собраны здесь:
|
|
https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell
|
|
|
|
Обфускатор PowerShell-скриптов:
|
|
https://reconshell.com/chimera-powershell-obfuscation-script-for-bypass-amsi-and-antivirus/
|
|
|
|
Документы чистятся так:
|
|
- первым делом меняем разводку (хэш картинок, расположение элементов, текстовки итд)
|
|
- обфусцируем VBA код
|
|
- ставим таймауты перед распаковкой дроппера и перед запуском самого файла
|
|
|
|
|
|
FAT BINARY
|
|
|
|
Непроработанная, но давно известная и перспективная техника, связанная с необходимостью доставки универсальной 32/64-разрядной нагрузки:
|
|
https://en.wikipedia.org/wiki/Fat_binary
|
|
https://habr.com/ru/company/macloud/blog/545278/
|
|
За счет махинаций с заголовками исполняемых файлов, стартовый пролог является общим,
|
|
который далее выбирает нужную нагрузку с нужной точкой входа.
|
|
|
|
|
|
III. ОБНАРУЖЕНИЕ ПЕСОЧНИЦ И ОТЛАДЧИКОВ
|
|
|
|
ОБНАРУЖЕНИЕ ПЕСОЧНИЦ
|
|
|
|
Обнаружение песочниц нужно для того, чтобы не выполниться в ней. Не загружать и не светить основную нагрузку.
|
|
Песочницы в основном делают из виртуальных машин, но сам по себе этот критерий недостаточный, т.к. на ВМ вполне может крутиться легитимный терминальный сервер.
|
|
|
|
Много методов систематизировано здесь:
|
|
Al-Khaser: https://github.com/LordNoteworthy/al-khaser
|
|
PaFish: https://github.com/a0rtega/pafish
|
|
|
|
Хорошая статья по обнаружению эмуляторов и песочниц: https://0xpat.github.io/Malware_development_part_2/
|
|
|
|
Ниже очень краткая и неполная выжимка стратегий:
|
|
|
|
1. По имени машины (https://www.blackhat.com/docs/us-17/thursday/us-17-Kotler-The-Adventures-Of-Av-And-The-Leaky-Sandbox.pdf):
|
|
*ESET: REYNAPC, MALVAPC, ELEANOREPC, WRIGHTPC, BRIAPC, JORIPC, GABBIPC, HELSAPC, MAMEPC, SHARAIPC, ARACHONPC, FLORIANPC, EDITHPC
|
|
*Various: WIN7-PC, ROGER-PC, DAVID-PC, ADMIN-PC, APIARY7-PC, ANTONY-PC, LUSER-PC, PERRY-PC, KLONE_X64-PC, 0M9P60J5W-PC, MIKI-PC
|
|
*Avira: C02TT22, C02TT26, C02TT36, C02TT18, C06TT43
|
|
*Comodo: spurtive, circumstellar
|
|
*Others: ZGXTIQTG8837952 (Comodo), ABC-WIN7, PC, WIN-U9ELNVPPAD0, PC-4A095E27CB, WIN-LRG949QLD21
|
|
|
|
2. По серийным номерам и названию оборудования - MAC-адреса сетевой карты, имя тома жесткого диска
|
|
(vbox, qemu, vmware, virtual hd)
|
|
|
|
3. По выполнению в виртуальной машине.
|
|
|
|
4. По времени выполнения инструкции CPUID
|
|
4.1. По разнице GetTickCount() перед и после Sleep();
|
|
|
|
5. По отстутствию активности в интерактивной сессии (мышь, клавиатура)
|
|
|
|
6. Резолв заведомо несуществующего домена (NotPetya killswitch)
|
|
|
|
Несколько примеров реализации детекта песочниц:
|
|
- https://habr.com/ru/company/solarsecurity/blog/473086/
|
|
- Обзор дешманских методов от Positive Technologies: https://habr.com/ru/company/pt/blog/507912/
|
|
- Комбайн с многоступенчатым обнаружением песочниц:
|
|
https://blog.talosintelligence.com/2020/05/astaroth-analysis.html
|
|
читать с раздела "Anti-analysis/Anti-sandbox mechanisms"
|
|
|
|
ОБХОД ЭМУЛЯТОРОВ
|
|
|
|
Эмулятор как правило является частью антивируса, и ему нужно очень быстро определить, разрешить ли работу данного кода или нет.
|
|
Из-за этого, проверка в эмуляторе как правило не занимает много времени.
|
|
На этом строится основная стратегия обхода эмуляторов - задержка выполнения.
|
|
Простой Sleep() уже давно не работает, т.к. перехватывается эмулятором, реальной задержки не происходит.
|
|
Поэтому как правило вместо задержки используется цикл вычислений (например расчет числа Пи с большой точностью).
|
|
|
|
Много интересных и простых техник по обходу эмуляторов:
|
|
https://wikileaks.org/ciav7p1/cms/files/BypassAVDynamics.pdf
|
|
|
|
Подход, основанный на несовершенстве эмуляции WinAPI - анализ регистров ECX EDX после возврата из вызова:
|
|
https://winternl.com/fuzzing-the-windows-api-for-av-evasion/
|
|
https://github.com/jackullrich/Windows-API-Fuzzer
|
|
Более ранняя работа
|
|
https://github.com/SPTHvx/SPTH/blob/master/articles/files/dynamic_anti_emulation.txt
|
|
|
|
Маскировка истинной последовательности системных вызовов в большом количестве шумовых вызовов:
|
|
https://habr.com/ru/company/pt/blog/551954/
|
|
|
|
ОБНАРУЖЕНИЕ ОТЛАДЧИКОВ, ЗАЩИТА ОТ ОТЛАДКИ
|
|
|
|
1. IsDebuggerPresent() - ненадежно, функцию патчат и она возвращает "нас не дебажат"
|
|
|
|
2. Поиск процессов по имени (windbg, idapro итд)
|
|
|
|
3. Засечки времени прохождения характерных кусков кода
|
|
|
|
Интересные методы защиты от отладки у криптера OnionCrypter: https://decoded.avast.io/jakubkaloc/onion-crypter/
|
|
- применяют сигнатуры от известных пакеров (UPX), чтобы зациклить автоанализ и сбить с толку реверсеров попроще.
|
|
Разумеется нагрузка накрыта не тем пакером, следы которого оставлены.
|
|
- после обнаружения отладчика выбрасывается исключение
|
|
- три разных ф-ии для аллокации памяти - HeapAlloc GlobalAlloc VirtualAlloc. Много ложных аллокаций затрудняют ручной анализ,
|
|
делает бесполезным точку останова и хук на эти ф-ии.
|
|
- запуск нагрузки через callback системной ф-ии. Т.е. не "передаем управление на такой-то адрес",
|
|
а "вызываем EnumWhateverA и в качестве callback передаем этой ф-ии точку входа нагрузки".
|
|
|
|
IV. ТЕХНИКИ ЗАКРЕПЛЕНИЯ
|
|
|
|
На Windows, классические способы закрепления следующие:
|
|
- автозагрузка [HKLM|HKCU]\Software\Microsoft\Windows\CurrentVersion\Run
|
|
- задача по расписанию CoCreateInstance(CLSID_TaskScheduler, ...)
|
|
Из достоинств - не требуются права админа, из недостатков - настолько очевидны, что дают немедленный детект по поведению.
|
|
- установка себя как службы (без прав не обойтись)
|
|
- BITS - не столь часто используется, но не напрягает АВ
|
|
- ... (техник много)
|
|
Тут https://habr.com/ru/post/425177/ хороший обзор техник.
|
|
Тут http://www.hexacorn.com/blog/2017/01/28/beyond-good-ol-run-key-all-parts/ огромное количество стандартных
|
|
и нестандартных точек расширения в Windows. В частности обыгрываются идеи запуска по нестандартным триггерам - на аппаратные события,
|
|
точки расширения популярных программ итд итп.
|
|
|
|
Также смотри выше "Разрыв цепочки".
|
|
|
|
|
|
V. ОБРАТНЫЙ КАНАЛ И СВЯЗЬ
|
|
|
|
C&C-сервера всегда скрыты: либо за прокладками (обратными прокси), либо за тор-доменом.
|
|
Прокладки выстраиваются в каскады, их делается много, так что вывод из строя одной не приводит к краху всей сети.
|
|
|
|
При реализации канала связи с C&C следует помнить, что в ОС может быть настроен свой системный прокси.
|
|
|
|
Для начального поиска C&C можно использовать алгоритм генерации домена (DGA - Domain Generation Algorithm)
|
|
http://www.marc-blanchard.com/BotInvaders/index.php
|
|
Смысл его в том, чтобы сгенерировать псевдослучайные доменные имена
|
|
- которых не слишком много (до 10к), чтобы перебрать за разумное время;
|
|
- их достаточно много, чтобы их нельзя было засквоттить или еще как-то забанить/заспуфить;
|
|
- список доменов для одного месяца отличается от списка доменов для другого месяца;
|
|
- трудно сделать регулярку, чтобы вырезать их на dns-серверах.
|
|
|
|
Обычно для связи с C&C используется протокол HTTPS, но не всегда нужный порт или протокол открыт.
|
|
Если DPI-фильтр режет HTTP(s)-трафик, используются другие протоколы:
|
|
- можно делать специфические DNS-запросы на _нужный_ (свой) DNS-сервер, и прятать информацию в доменных именах
|
|
- можно делать специфические ICMP-посылки ***
|
|
- используются почтовые протоколы SMTP/IMAP/POP3
|
|
https://habr.com/ru/company/kaspersky/blog/522128/
|
|
Словом, можно использовать разные варианты модуляции полезного сигнала поверх несущей,
|
|
которая гарантировано проходит через файрволл.
|
|
|
|
Трафик перехватывается и анализируется системами наподобие Suricata https://suricata-ids.org/
|
|
распознающими аномалии и отыскивающими паттерны в трафике.
|
|
Библиотека PyWhat для автоматического парсинга трафика
|
|
https://habr.com/ru/company/dcmiran/news/t/563206/
|
|
https://github.com/bee-san/pyWhat
|
|
|
|
Существуют черные списки доменов, адресов, SSL-сертификатов, профилей трафика, например:
|
|
https://sslbl.abuse.ch
|
|
https://urlhaus.abuse.ch
|
|
https://feodotracker.abuse.ch
|
|
|
|
Используются такие техники как JA3 client fingerprinting/JA3S server fingerprinting/JARM (нечеткое хеширование):
|
|
https://engineering.salesforce.com/tls-fingerprinting-with-ja3-and-ja3s-247362855967
|
|
https://habr.com/ru/company/acribia/blog/560168/
|
|
Суть их в том, что TLS-рукопожатие прогнозируемо для связки клиент+сервер, т.к. в рукопожатии фигурирует большое количество комбинаций шифров,
|
|
с учетом их взаимного расположения. Рукопожатие одного и того же клиента с одним и тем же сервером всегда одинаково.
|
|
С этого рукопожатия снимают отпечаток, клея версию TLS, принимаемые шифры, список расширений, эллиптические кривые и форматы эллиптических кривых, и накрывая MD5.
|
|
Средство для снятия отпечатка:
|
|
https://github.com/salesforce/ja3
|
|
https://ja3er.com/form
|
|
Средство борьбы с этим - рандомизация TLS-стека (Cipher-Stunting) и на клиенте, и на сервере (рандомизация настройки SSLCipherSuite и подобных):
|
|
https://www.bc-security.org/post/ja3-s-signatures-and-how-to-avoid-them
|
|
https://www.vectra.ai/blogpost/c2-evasion-techniques
|
|
TL;DR: командлет Enable-TlsCipherSuite позволяет сменить комбинацию шифров клиента - но - это общесистемная настройка.
|
|
BCryptAddContextFunction
|
|
https://docs.microsoft.com/en-us/windows/win32/secauthn/prioritizing-schannel-cipher-suites
|
|
|
|
|
|
Нужно предусмотреть постоянную актуальность адреса C&C-сервера в теле программы.
|
|
Поэтому вместо использования обычных доменных имен и DNS-инфраструктуры,
|
|
можно использовать публичную инфраструктуру, которую нельзя отозвать:
|
|
- emercoin-домены и DNS (можно делать как специфические запросы по протоколу Emercoin,
|
|
так и обычные DNS-запросы к серверам OpenNIC)
|
|
- записи в блокчейнах криптовалют (модуляция инфы в суммах, адресах или служебных записях)
|
|
- TOR-домены (не везде TOR открыт, и требуется специфичный клиентский код для работы поверх TOR)
|
|
- твиттеры и прочие публичные соцсети (реже, т.к. учетка может быть отозвана)
|
|
например https://safe.cnews.ru/news/top/2020-09-08_hakerynaemniki_shest_let
|
|
|
|
Обзор техник связи любезно предоставлен Positive Technologies: https://habr.com/ru/company/pt/blog/497608/
|
|
DNS-туннелирование: https://habr.com/ru/company/varonis/blog/513160/
|
|
|
|
Для борьбы с детектами на сетевой обмен используются подходы с маскировкой трафика.
|
|
Для работы в промышленных масштабах используются конструкторы вроде C2 Malleable Profile для Cobalt Strike
|
|
https://www.cobaltstrike.com/help-malleable-c2
|
|
https://github.com/threatexpress/random_c2_profile
|
|
или конструктора шлюзов C3 https://github.com/FSecureLABS/C3
|
|
Принцип в том, чтобы вынести транспортный уровень софта из него самого, сделать его гибко настраиваемым и маскируемым,
|
|
сделать возможность быстрого расширения и гибкой реакции на детекты за счет модульности (основной функционал софта - главный модуль,
|
|
сетевой функционал - выносной модуль-плагин).
|
|
|
|
|
|
Если полностью закрыты все каналы изнутри сети, то инфу все равно можно отправить.
|
|
|
|
Один из вариантов - почта (SMTP):
|
|
- Ищем почтового клиента на локальной машине и кладем письмо в Outbox, не забывая подчистить за собой
|
|
- ищем SMTP-сервер в локалке (хотя они теперь всегда требуют аутентификацию)
|
|
- также на локальной машине может быть доступна веб-почта (например OWA = Outlook Web Access) и закрыт при этом инет.
|
|
|
|
Другой вариант - так называемая "ракета":
|
|
https://www.blackhat.com/docs/us-17/thursday/us-17-Kotler-The-Adventures-Of-Av-And-The-Leaky-Sandbox.pdf
|
|
состоящая, как следует из названия, из двух ступеней.
|
|
Первая ступень должна быть Fully Undetectable.
|
|
Она собирает информацию с системы, формирует сообщение, и прошивает ее во вторую ступень.
|
|
Вторая ступень представляет из себя бинарник со следующими свойствами:
|
|
- он раздражает АВ (есть детекты по сигнатуре)
|
|
- он умеет связаться с C&C-сервером и отправить ему прошитую носителем посылку.
|
|
|
|
Дальше события развиваются так:
|
|
- корпоративный АВ отправляет вторую ступень в "облако" на выполнение в песочнице
|
|
- вторая ступень попадает в песочницу и запускается
|
|
- песочница находится в "облаке", снаружи обороняемого периметра, и оттуда есть связь с интернетом
|
|
- задача песочницы - исследовать поведение образца, потому его активность не глушится, хотя и регистрируется
|
|
- вторая ступень отправляет данные на C&C, и дальше ей уже все равно
|
|
- PROFIT
|
|
|
|
|
|
VI. ПОВЫШЕНИЕ ПРИВИЛЕГИЙ
|
|
|
|
ОБХОД UAC
|
|
|
|
Это первое что приходится делать: https://github.com/hfiref0x/UACME
|
|
Методы примерно до 20-го устарели и не работают; до 40-го через один.
|
|
|
|
В двух словах, идея обхода следующая:
|
|
1. маскируем текущий процесс под легитимный, для которого Windows никогда не спрашивает о необходимости elevation (путем подмены имени процесса в PEB)
|
|
2. дергаем другой процесс, у которого выставлена авто-элевация, чтобы он запустил нужный нам .exe (аналог suid root в Unix)
|
|
Для второго пункта есть туева хуча способов.
|
|
|
|
Ни в коем случае не запускать на личной машине! МОЖНО ПРИВЕСТИ ОС В НЕГОДНОСТЬ!
|
|
|
|
|
|
ПОДЪЕМ ПРИВИЛЕГИЙ (LPE)
|
|
|
|
По повышению привилегий, обзор общих стратегий тут: https://habr.com/ru/post/428602/
|
|
Конкретные эксплойты быстро устаревают, потому здесь не приводим.
|
|
Общая идея LPE в Windows - получение и использование чужого токена безопасности https://habr.com/ru/company/pt/blog/563436/
|
|
Теория и практика LPE: https://habr.com/ru/company/otus/blog/530596/
|
|
Общие приемы эксплуатации уязвимостей в ядре: https://habr.com/ru/company/pt/blog/566698/
|
|
(патчинг HalDispatchTable, кража токена)
|
|
|
|
|
|
VII. ИССЛЕДОВАНИЯ
|
|
|
|
Как понять, что происходит внутри черного ящика, будь то накрытого упаковщиком .exe, или неведомой системы вообще?
|
|
|
|
ПЕРЕХВАТ СИСТЕМНЫХ ВЫЗОВОВ
|
|
|
|
В Windows есть API Monitor (из комплекта rohitab), а в Linux - strace.
|
|
Подслушиваем системные вызовы интересующего нас исполняемого файла, отфильтровываем по нужным критериям, понимаем картину происходящего.
|
|
|
|
ПЕРЕХВАТ ТРАФИКА
|
|
|
|
Wireshark, можно узнать адреса, порты, протоколы. Если повезет, можно даже посмотреть подробности.
|
|
Из-за повсеместного SSL стало непросто, но можно подсунуть свой корневой сертификат в систему, поднять прокси с его использованием,
|
|
и ловить трафик уже на прокси.
|
|
https://mitmproxy.org/ прокси для HTTPS, также полезен для ловли проблем на стыках подсистем
|
|
|
|
PATCH DIFFING / BINARY DIFFING
|
|
|
|
Способ поиска уязвимости по её исправлению.
|
|
Берем старый исполняемый файл, берем новый исполняемый файл (с патчем уязвимости), смотрим разницу,
|
|
по разнице вычисляем подробности эксплуатации.
|
|
https://habr.com/ru/company/dsec/blog/479972/
|
|
https://wumb0.in/extracting-and-diffing-ms-patches-in-2020.html
|
|
|
|
FUZZING
|
|
|
|
Кормим системе на вход лютый бред, генерируемый случайно (но по правилам), и смотрим, когда она сломается (ловим крэши).
|
|
Далее, соотнося данные на входе и крэши, находим устойчивую картину.
|
|
Далее по ней уже можно верстать шелл-код для эксплуатации.
|
|
|
|
Для этого есть масса инструментов, вручную так никто не делает, все автоматизированно.
|
|
|
|
Описание фаззинга белого ящика (с известными исходниками).
|
|
https://habr.com/ru/company/dsec/blog/517596/
|
|
Это скорее для автотестировщиков, контроля качества, и генерации тестов на лету, а не для исследований/реверса.
|
|
И все же общие понятия о методиках и инструментах статья дает.
|
|
|
|
Популярный фаззер AFL (American Fuzzy Lop), основанный на генетических алгоритмах (морфирование корректного входного сэмпла)
|
|
https://github.com/google/AFL
|
|
он же под винду
|
|
https://github.com/googleprojectzero/winafl
|
|
|
|
Обоснование подходов к фаззингу с разбором теории:
|
|
https://habr.com/ru/company/bizone/blog/570312/
|
|
https://habr.com/ru/company/bizone/blog/570534/
|
|
https://wcventure.github.io/FuzzingPaper/
|
|
Фаззить просто черный ящик бесперспективно. Нужно
|
|
- реверсить/анализировать код
|
|
- искать входные проверки
|
|
- начинять фаззер ими, чтобы тот мог корректно мутировать ввод и прорываться за проверки
|
|
|
|
|
|
|
|
VIII. ВСПОМОГАТЕЛЬНЫЕ СЛУЖЕБНЫЕ ТЕХНИКИ
|
|
|
|
ИСКЛЮЧЕНИЯ И ПОСМЕРТНЫЙ СТЕК
|
|
|
|
Ловля багов и отладка в промышленных масштабах - задача в общем-то достаточно банальная, но решения для неё известны не всем и не всегда тривиальны.
|
|
Основной способ узнать, что пошло не так - это снять посмертный стек вызовов и отправить его телеметрией на сервер.
|
|
Теория и практика по обработке исключений в Windows: https://habr.com/ru/post/536990/
|
|
Для этого надо этот посмертный стек снять.
|
|
Для этого надо словить аварийный вылет программы (a.k.a. крэш) и снять нужную инфу, перед тем как дать ей погибнуть.
|
|
Для этого есть два основных способа:
|
|
* VEH - Vectored Exception Handling
|
|
* SEH - Structured Exception Handling
|
|
На Linux/*nix есть сигналы (SIGBUS, SIGSTOP, SIGILL итд), man signal
|
|
|
|
И еще раз:
|
|
- VEH - это AddVectoredExceptionHandler() и статья https://docs.microsoft.com/ru-ru/windows/win32/debug/using-a-vectored-exception-handler
|
|
- SEH - это __try ... __except и статья https://docs.microsoft.com/en-us/cpp/cpp/try-except-statement?view=vs-2019
|
|
Если используется SEH, то обернуть в try/except нужно все основные потоки.
|
|
Если используется VEH, то достаточно установки одного общего обработчика в прологе программы.
|
|
|
|
Из минусов SEH - Ошибка C2712 Cannot use __try in functions that require object unwinding, и решение описано тут
|
|
https://stackoverflow.com/questions/51701426/cannot-use-try-in-functions-that-require-object-unwinding-fix
|
|
Свойства / C/C++ / Создание кода / Включить С++ исключения: Нет
|
|
|
|
Главный недостаток любого подхода - с process hollowed процессами ни один метод не даст номеров строк и имен функций,
|
|
т.к. не сработает загрузка символов. Будут только голые адреса.
|
|
|
|
В обработчике исключения мы должны снять стек (код ниже).
|
|
Если мы хотим при этом номера строк кода, нам нужны символы (.pdb), а проект должен быть собран с опциями
|
|
- C/C++ / Общие / Формат отладочной информации: База данных программы (/Zi)
|
|
- Компоновщик / Отладка / Создавать отладочную информацию: Оптимизировать для отладки (/DEBUG)
|
|
- Компоновщик / Отладка / Создать полный файл базы данных программы: Да
|
|
и .pdb должен лежать РЯДОМ с умирающим .exe или .dll.
|
|
|
|
Для боевых сборок это не подойдет, но для отладки на внутренних ресурсах можно так. Для боевых сборок в стеке будут просто адреса, что тоже немало.
|
|
|
|
Код снятия стека достаточно мал, приведем его здесь:
|
|
|
|
#include <windows.h>
|
|
#include <Psapi.h>
|
|
|
|
// Some versions of imagehlp.dll lack the proper packing directives themselves
|
|
// so we need to do it.
|
|
#pragma pack( push, before_imagehlp, 8 )
|
|
#include <imagehlp.h>
|
|
#pragma pack( pop, before_imagehlp )
|
|
|
|
#pragma comment(lib, "psapi.lib")
|
|
#pragma comment(lib, "dbghelp.lib")
|
|
|
|
|
|
__declspec(noinline) DWORD DumpStackTrace() {
|
|
unsigned int i;
|
|
void * stack[100];
|
|
unsigned short frames;
|
|
SYMBOL_INFO * symbol;
|
|
HANDLE process;
|
|
|
|
debug_printf("PROGRAM CRASHED, STACK TRACE FOLLOWS:\r\n");
|
|
|
|
process = GetCurrentProcess();
|
|
|
|
if (!SymInitialize(process, NULL, TRUE))
|
|
return 0;
|
|
|
|
DWORD symOptions = SymGetOptions();
|
|
symOptions |= SYMOPT_LOAD_LINES | SYMOPT_UNDNAME | SYMOPT_LOAD_ANYTHING | SYMOPT_CASE_INSENSITIVE;
|
|
SymSetOptions(symOptions);
|
|
|
|
frames = CaptureStackBackTrace(0, 100, stack, NULL);
|
|
symbol = (SYMBOL_INFO *)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
|
|
symbol->MaxNameLen = 255;
|
|
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
|
|
|
DWORD offset_from_symbol = 0;
|
|
#ifdef _WIN64
|
|
IMAGEHLP_LINE64* line = (IMAGEHLP_LINE64*)calloc(sizeof(IMAGEHLP_LINE64), 1);
|
|
line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
|
#else
|
|
IMAGEHLP_LINE* line = (IMAGEHLP_LINE*)calloc(sizeof(IMAGEHLP_LINE), 1);
|
|
line->SizeOfStruct = sizeof(IMAGEHLP_LINE);
|
|
#endif
|
|
|
|
|
|
for (i = 0; i < frames; i++)
|
|
{
|
|
SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
|
|
|
|
SymGetLineFromAddr(process, (DWORD64)(stack[i]), &offset_from_symbol, line);
|
|
|
|
debug_printf( "%i: %s (%s:%i) - 0x%0X\n", frames - i - 1, symbol->Name,
|
|
line->FileName, line->LineNumber, symbol->Address);
|
|
symbol->Name[0] = 0;
|
|
symbol->Address = 0;
|
|
if(line->FileName)
|
|
line->FileName[0] = 0;
|
|
line->LineNumber = 0;
|
|
}
|
|
|
|
free(symbol);
|
|
free(line);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
ФАЙЛЫ КАРТЫ (.MAP)
|
|
|
|
Включаются в компоновщике:
|
|
Visual Studio / Свойства проекта / Компоновщик / Отладка / Создавать файл сопоставления: ДА
|
|
|
|
Если у упавшей программы отсутствуют символы в .pdb, но известен адрес падения, то по карте можно найти адрес функции, как описано здесь:
|
|
https://www.codeproject.com/articles/3472/finding-crash-information-using-the-map-file
|
|
|
|
|
|
УМЕНЬШЕНИЕ РАЗМЕРА КОДА
|
|
|
|
ОТКАЗ ОТ CRT (C RUNTIME LIBRARY)
|
|
|
|
Пример программы, компилирующейся в .exe размером 3к:
|
|
|
|
hello.cpp:
|
|
#include <windows.h>
|
|
|
|
const char *str="Message";
|
|
|
|
int MyMain()
|
|
{
|
|
MessageBoxA(NULL,str,str,MB_OK);
|
|
ExitProcess(0);
|
|
return 0;
|
|
}
|
|
|
|
build.bat:
|
|
set PATH=c:\LLVM9\bin
|
|
|
|
clang++.exe -DUNICODE -c -D_UNICODE -m32 -std=c++14 -Wall -Os -mno-sse -fms-extensions -fms-compatibility -fno-exceptions -fno-rtti -fomit-frame-pointer -ffunction-sections -fdata-sections -Wno-c++11-narrowing -Wc++11-compat-deprecated-writable-strings *.cpp -I"c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include"
|
|
|
|
lld-link.exe /subsystem:windows /nodefaultlib /entry:MyMain /libpath:"c:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\lib" /libpath:"c:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Lib" *.o kernel32.lib user32.lib
|
|
|
|
По умолчанию точка входа - WinMainCRTStartup в CRT. Когда своя точка входа, CRT не нужен.
|
|
Вдобавок здесь указан отключающий CRT ключ /nodefaultlib.
|
|
Но функции strcpy придется писать самому, и исключения не получится использовать.
|
|
Но strcpy уже есть в shlwapi.lib, потому делаем в коде
|
|
|
|
#include <Shlwapi.h>
|
|
#pragma comment(lib,"Shlwapi.lib")
|
|
|
|
ОТКЛЮЧЕНИЕ ПРОВЕРОК БЕЗОПАСНОСТИ
|
|
|
|
Компилятор Microsoft сует много дополнительного защитного кода в итоговый код - канарейки стека, проверки выхода за массивы,
|
|
зануление переменных на входе в функцию. Все это дает лишние килобайты и в боевом коде не нужно.
|
|
- Свойства / С/С++ / Создание кода / Основные проверки времени выполнения (/RTC) - по умолчанию (тут не очень понятно что ставить на самом деле)
|
|
- Свойства / С/С++ / Создание кода / Защита потока управления - Нет
|
|
- Свойства / С/С++ / Создание кода / Создать образ с обновлением - Нет (только если вы не будете ставить хуки на свои же функции)
|
|
- Свойства / С/С++ / Язык / Удалить код и данные, на которые не указывает ссылка - Да /Zc:inline)
|
|
- Свойства / С/С++ / Язык / Включить информацию о типах времени выполнения - Нет
|
|
|
|
|
|
ОПТИМИЗАЦИИ
|
|
|
|
- Отключить кадры стека (Omit frame pointers) - по умолчанию при входе в функцию текущая вершина стека в регистре BSP.
|
|
Таким образом можно отграничить личный стек текущей функции от стека вышестоящих функций.
|
|
Если отключить сохранение кадров стека, то высвободится еще один регистр, и уменьшится число ассемблерных инструкций,
|
|
как за счет отказа от записи в него, так и за счет того, что больше переменных можно хранить и передавать через регистры.
|
|
|
|
MICROSOFT RICH HEADER
|
|
|
|
http://ntcore.com/files/richsign.htm
|
|
http://bytepointer.com/articles/the_microsoft_rich_header.htm
|
|
Нештатная секция в PE-заголовке, которая вставляется компоновщиками Microsoft с 1998 года и версии Microsoft Visual Studio 6.0.
|
|
В нее записывается статистика о тулчейне, собравшем данный бинарник, как-то - кол-во объектных файлов C,
|
|
кол-во объектных файлов C++, кол-во объектных файлов ASM, версия компоновщика, версия компилятора ресурсов,
|
|
кол-во функций в импорте, и всякое такое.
|
|
Сделано это было скорее всего для отладочных целей (чтобы отладить тулчейн сборки).
|
|
Однако нужно понимать, что этот заголовок может быть использован для криминалистики как отпечаток.
|
|
|
|
КРОСС-БИТНЫЙ КОД
|
|
|
|
Возможно выполнять как 32-битный код в 64-разрядном режиме, так и наоборот.
|
|
В ядре Windows для выполнения системных вызовов из 32-разрядного режима предусмотрены шлюзы, такие как Heaven's Gate:
|
|
https://medium.com/@fsx30/hooking-heavens-gate-a-wow64-hooking-technique-5235e1aeed73
|
|
Еще пример:
|
|
http://blog.rewolf.pl/blog/?p=102
|
|
https://github.com/rwfpl/rewolf-wow64ext
|
|
|
|
|
|
ГЕНЕРАЦИЯ ПСЕВДОСЛУЧАЙНЫХ ЧИСЕЛ
|
|
|
|
Код и разбор простых алгоритмов ГПСЧ здесь https://habr.com/ru/post/499490/
|
|
Теоретический обзор некриптостойких и криптостойких ГПСЧ: https://habr.com/ru/post/531750/
|
|
Следует помнить, что качество ГСЧ (именно случайных, без буквы П в аббревиатуре) - это важнейшее звено криптографии.
|
|
Хороший криптоалгоритм сводится на нет использованием в нем плохого ГСЧ (например для генерации гаммы, вектора IV итд).
|
|
|
|
|
|
ЛИТЕРАТУРА
|
|
|
|
1. М. Руссинович, Д. Соломон - Внутреннее устройство Microsoft Windows, 6-е издание (Часть 1) [2013, PDF, RUS] - https://rutracker.org/forum/viewtopic.php?t=4469765
|
|
2. М. Руссинович, Д. Соломон, А. Ионеску - Внутреннее устройство Microsoft Windows. Основные подсистемы ОС. 6-е издание (Часть 2) [2014, PDF, RUS] - https://rutracker.org/forum/viewtopic.php?t=4727796
|
|
3. Библиотека разработчика - Лав Р. - Ядро Linux: описание процесса разработки, 3-е изд. [2013, PDF, RUS] - https://rutracker.org/forum/viewtopic.php?t=5169029
|
|
4. Библиотека программиста - Элджер Дж. - C++ [2008, PDF, RUS] - https://rutracker.org/forum/viewtopic.php?t=694260
|
|
5. Крис Касперски. Сборник из 507 статей - 2017.03.01 [PDF, DOC] - https://rutracker.org/forum/viewtopic.php?t=5375505
|
|
6. Understanding Windows Shellcode - [email protected] - http://www.hick.org/code/skape/papers/win32-shellcode.pdf
|
|
7. https://0xpat.github.io/ 0xPat blog Red/purple teamer - цикл статей "Malware development"
|