
Мои эксперименты по вооружению Nim (https://nim-lang.org/)
Мои эксперименты по использованию Nim для разработки имплантов и общих наступательных операций.
DllMain
mingw и передать один флаг компилятору Nim.| Файл | Описание |
|---|---|
| amsi_patch_2_bin.nim | Патчит AMSI в текущем процессе другим методом (WIP, помощь приветствуется) |
| excel_4_com_bin.nim | Внедряет шеллкод с помощью COM-объекта Excel и макросов Excel 4 () |
Этот репозиторий не предоставляет бинарные файлы, вам придётся компилировать их самостоятельно. Репозиторий настроен на кросс-компиляцию примеров исходного кода Nim в Windows из Linux или MacOS.
Используйте Devcontainers VSCode для автоматической настройки среды разработки (см. раздел Настройка среды разработки). После этого просто выполните make.
Установите Nim с помощью менеджера пакетов вашей системы (для Windows используйте установщик с официального сайта)
brew install nimapt install nimchoco install nim(Nim также предоставляет docker-образ на Dockerhub)
Теперь у вас должны быть доступны команды nim и nimble: первая — компилятор Nim, вторая — менеджер пакетов Nim.
Установите тулчейн Mingw, необходимый для кросс-компиляции в Windows (не требуется, если вы компилируете на Windows):
apt-get install mingw-w64brew install mingw-w64Наконец, установите великолепную библиотеку Winim, а также zippy и nimcrypto
nimble install winim zippy nimcryptoЗатем перейдите в корень этого репозитория и выполните make.
Бинарные файлы и DLL вы найдёте в каталоге bin/
Смотрите раздел о кросс-компиляции в руководстве по использованию компилятора Nim для более подробной информации.
Кросс-компиляция в Windows из MacOS/*nix требует тулчейн mingw, обычно достаточно выполнить brew install mingw-w64 или apt install mingw-w64.
Затем нужно просто передать флаг -d=mingw компилятору Nim.
Например: nim c -d=mingw --app=console --cpu=amd64 source.nim
Смотрите невероятный раздел FFI в руководстве Nim.
Если вы знакомы с P/Invoke в C#, это, по сути, та же концепция, хотя выглядит немного уродливее:
Пример вызова `MessageBox````nim type HANDLE* = int HWND* = HANDLE UINT* = int32 LPCSTR* = cstring
proc MessageBox*(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT): int32 {.discardable, stdcall, dynlib: "user32", importc: "MessageBoxA".}
MessageBox(0, "Hello, world !", "Nim is Powerful", 0)
Для любых сложных вызовов Windows API используйте библиотеку [Winim](https://github.com/khchen/winim), это экономит огромное количество времени и не сильно увеличивает размер исполняемого файла (см. ниже) в зависимости от способа импорта.
Даже поддерживает COM!!!
## Создание Windows DLL с экспортируемой `DllMain`
Огромное спасибо человеку, опубликовавшему [это](https://forum.nim-lang.org/t/1973) на форуме Nim.
Компилятор Nim пытается автоматически создать функцию `DllMain` для вас во время компиляции, когда вы указываете ему создать DLL для Windows, однако по какой-то причине он её не экспортирует. Чтобы иметь экспортируемую `DllMain`, нужно передать `--nomain` и определить функцию `DllMain` самостоятельно с соответствующими прагмами (`stdcall, exportc, dynlib`).
Также необходимо вызвать `NimMain` из вашего `DllMain`, чтобы инициализировать сборщик мусора Nim. (Очень важно, иначе ваш компьютер буквально взорвётся).
Пример:```nim
import winim/lean
proc NimMain() {.cdecl, importc.}
proc DllMain(hinstDLL: HINSTANCE, fdwReason: DWORD, lpvReserved: LPVOID) : BOOL {.stdcall, exportc, dynlib.} =
NimMain()
if fdwReason == DLL_PROCESS_ATTACH:
MessageBox(0, "Hello, world !", "Nim is Powerful", 0)
return true
Для компиляции:``` nim c -d=mingw --app=lib --nomain --cpu=amd64 mynim.dll
### Создание XLL
Вы можете создать XLL (DLL для Excel, представьте себе) с функцией автозапуска, которая может использоваться для доставки полезной нагрузки. Следующий код создает простой XLL с функцией автозапуска и всем остальным шаблонным кодом, необходимым для компиляции в виде библиотеки ссылок. Данный POC компилируется как DLL, после чего вы можете изменить расширение на .xll, и при двойном щелчке он откроется в Excel и запустит полезную нагрузку:```nim
#[
Compile:
nim c -d=mingw --app=lib --nomain --cpu=amd64 nim_xll.nim
Will compile as a DLL, you can then just change the extension to .xll
]#
import winim/lean
proc xlAutoOpen() {.stdcall, exportc, dynlib.} =
MessageBox(0, "Hello, world !", "Nim is Powerful", 0)
proc NimMain() {.cdecl, importc.}
proc DllMain(hinstDLL: HINSTANCE, fdwReason: DWORD, lpvReserved: LPVOID) : BOOL {.stdcall, exportc, dynlib.} =
NimMain()
return true
Существует множество других скрытых трюков, которые можно выполнить с помощью XLL. Смотрите больше примеров методов XLL здесь.
Взято со страницы FAQ Nim
Для максимального уменьшения размера используйте следующие флаги -d:danger -d:strip --opt:size
Кроме того, я обнаружил, что можно выжать еще несколько байтов, передав компилятору --passc=-flto --passl=-flto. Также взгляните на Makefile в этом репозитории.
Эти флаги радикально уменьшают размеры: пример внедрения шелл-кода уменьшается с 484.3 КБ до 46.5 КБ при кросс-компиляции из MacOSX!
Огромное спасибо @Shitsecure за то, что разобрался с этим!
По умолчанию Nim не генерирует PE с таблицей перемещений, которая требуется большинству инструментов для рефлексивной загрузки EXE-файлов.
Чтобы создать исполняемый файл Nim с разделом перемещений, необходимо передать компоновщику несколько дополнительных флагов.
А именно: --passL:-Wl,--dynamicbase
Полный пример команды:``` nim c --passL:-Wl,--dynamicbase my_awesome_malwarez.nim
## Разница в размере исполняемого файла при использовании библиотеки Winim и без нее
Удивительно, но разница в размере довольно незначительна. Особенно если применить описанные выше оптимизации размера.
Для этой цели были созданы два примера: `pop_bin.nim` и `pop_winim_bin.nim`.
Первый определяет вызов WinAPI `MessageBox` вручную, а второй использует библиотеку Winim (конкретно `winim/lean`, которая представляет собой только базовый SDK, см. [здесь](https://github.com/khchen/winim#usage)), результаты:```
byt3bl33d3r@ecl1ps3 OffensiveNim % ls -lah bin
-rwxr-xr-x 1 byt3bl33d3r 25K Nov 20 18:32 pop_bin_32.exe
-rwxr-xr-x 1 byt3bl33d3r 32K Nov 20 18:32 pop_bin_64.exe
-rwxr-xr-x 1 byt3bl33d3r 26K Nov 20 18:33 pop_winim_bin_32.exe
-rwxr-xr-x 1 byt3bl33d3r 34K Nov 20 18:32 pop_winim_bin_64.exe
Если вы импортируете всю библиотеку Winim с помощью import winim/com, это добавляет всего около ~20 КБ, что, учитывая объём функциональности, которую она абстрагирует, на 100% оправдывает этот дополнительный размер:```
byt3bl33d3r@ecl1ps3 OffensiveNim % ls -lah bin
-rwxr-xr-x 1 byt3bl33d3r 42K Nov 20 19:20 pop_winim_bin_32.exe
-rwxr-xr-x 1 byt3bl33d3r 53K Nov 20 19:20 pop_winim_bin_64.exe
## Соображения по Opsec
Из-за того, как Nim динамически разрешает DLL с помощью `LoadLibrary` через свой FFI, ни одна из ваших внешних импортированных функций фактически не появится в статических импортах исполняемого файла (см. [эту запись в блоге](https://web.archive.org/web/20210117002945/https://secbytes.net/implant-roulette-part-1:-nimplant/) для получения дополнительной информации):

Если вы компилируете исходный код Nim в DLL, похоже, что у вас всегда будет экспортированный `NimMain`, независимо от того, указываете ли вы свой собственный `DllMain` или нет (??). Это потенциально может использоваться как сигнатура; не знаю, сколько организаций на самом деле используют Nim в своем стеке разработки. Определенно выделяется.

## Написание Nim без среды выполнения Nim
Поскольку Nim сильно помечается антивирусными решениями, один из способов обойти это — писать программы на Nim без среды выполнения Nim. [Writing Nim-less Nim](https://www.youtube.com/watch?v=EXX3HmCG3pw) — это доклад, в котором описываются шаги по написанию кода на Nim без среды выполнения Nim и C; исходный код из этого доклада доступен [здесь](https://github.com/m4ul3r/writing_nimless). Доклад продолжает и расширяет работу [zimawhit3](https://github.com/zimawhit3) с [Bitmancer](https://github.com/zimawhit3/Bitmancer/tree/main).
Предпосылка заключается в том, чтобы полагаться на определения типов `winim` и использовать написание кода, которое не приведет к использованию среды выполнения Nim.
## Преобразование кода C в Nim
https://github.com/nim-lang/c2nim
Использовал его для перевода множества небольших фрагментов C, ничего крупного не пробовал.
## Языковые мосты
- Интеграция с Python: https://github.com/yglukhov/nimpy
* Это на самом деле очень интересно, [особенно эта часть](https://github.com/yglukhov/nimpy/blob/master/nimpy/py_lib.nim#L330). С некоторыми модификациями можно ли загрузить PythonxXX.dll из памяти?
- Интеграция с Jave VM: https://github.com/yglukhov/jnim
## Отладка
Используйте функцию `repr()` в сочетании с `echo`; поддерживает почти все (??) типы данных, даже структуры!
См. [эту запись в блоге для получения дополнительной информации](https://nim-lang.org/blog/2017/10/02/documenting-profiling-and-debugging-nim-code.html)
## Настройка среды разработки
Этот репозиторий поддерживает [VSCode Devcontainers](https://code.visualstudio.com/docs/remote/create-dev-container), что позволяет вам разрабатывать в контейнере Docker. Это автоматизирует настройку среды разработки для вас.
1. Установите VSCode и Docker Desktop
2. Клонируйте этот репозиторий и откройте его в VSCode
3. Установите расширение `Visual Studio Code Remote - Containers`
4. Откройте палитру команд и выберите команду `Remote-Containers: Reopen in Container`
VSCode теперь соберет образ Docker (это займет некоторое время) и поместит вас прямо в вашу предварительно собранную среду разработки Nim!
## Ловушки, в которые я сам попадал
- При вызове winapi с Winim и попытке передать нулевое значение убедитесь, что вы передаете значение `NULL` (определенное в библиотеке Winim), а не встроенное значение `nil` из Nim. (Уф)
- Чтобы получить дескриптор ОС для созданного файла после вызова `open()` в Windows, нужно вызывать `f.getOsFileHandle()`, **а не** `f.getFileHandle()` по причинам.
- Компилятор Nim принимает аргументы в форме `-a=value` или `--arg=value`, хотя если посмотреть на справку, аргументы передаются только как `-a:value` или `--arg:value`. (Важно для Makefile'ов)
- При определении байтового массива также нужно указать хотя бы в первом значении, что это байтовый массив; немного странно, но ладно (https://forum.nim-lang.org/t/4322)
Байтовый массив в C#:```csharp
byte[] buf = new byte[5] {0xfc,0x48,0x81,0xe4,0xf0,0xff}
Массив байтов в Nim:```nim var buf: array[5, byte] = [byte 0xfc,0x48,0x81,0xe4,0xf0,0xff]
## Интересные библиотеки Nim
- https://github.com/dom96/jester
- https://github.com/pragmagic/karax
- https://github.com/Niminem/Neel
- https://github.com/status-im/nim-libp2p
- https://github.com/PMunch/libkeepass
- https://github.com/def-/nim-syscall
- https://github.com/tulayang/asyncdocker
- https://github.com/treeform/ws
- https://github.com/guzba/zippy
- https://github.com/rockcavera/nim-iputils
- https://github.com/FedericoCeratto/nim-socks5
- https://github.com/CORDEA/backoff
- https://github.com/treeform/steganography
- https://github.com/miere43/nim-registry
- https://github.com/status-im/nim-daemon
## Ссылки Nim для разработки имплантов
- https://web.archive.org/web/20210117002945/https://secbytes.net/implant-roulette-part-1:-nimplant/
- https://securelist.com/zebrocys-multilanguage-malware-salad/90680/
- https://github.com/MythicAgents/Nimplant
- https://github.com/elddy/Nim-SMBExec
- https://github.com/elddy/NimScan
## Участники
Виртуальные объятия всем, кто внес свой вклад ❤️
<a href="https://github.com/byt3bl33d3r/OffensiveNim/graphs/contributors">
<img src="https://contrib.rocks/image?repo=byt3bl33d3r/OffensiveNim" />
</a>
| Файл | Описание |
|---|
| pop_bin.nim | Вызов WinAPI MessageBox без использования библиотеки Winim |
| pop_winim_bin.nim | Вызов MessageBox с использованием библиотеки Winim |
| pop_winim_lib.nim | Пример создания Windows DLL с экспортируемой DllMain |
| execute_assembly_bin.nim | Размещает CLR, рефлексивно выполняет .NET сборки из памяти |
| clr_host_cpp_embed_bin.nim | Размещает CLR путём прямого встраивания кода C++, выполняет .NET сборку с диска |
| scshell_c_embed_bin.nim | Показывает, как быстро вооружить существующий код C, встраивая SCShell (C) напрямую в Nim |
| fltmc_bin.nim | Перечисляет все драйверы Minifilter |
| blockdlls_acg_ppid_spoof_bin.nim | Создаёт приостановленный процесс, который подделывает свой PPID на explorer.exe, также включает BlockDLLs и ACG |
| named_pipe_client_bin.nim | Клиент именованного канала |
| named_pipe_server_bin.nim | Сервер именованного канала |
| embed_rsrc_bin.nim | Встраивает ресурс (zip-файл) во время компиляции и извлекает содержимое во время выполнения |
| self_delete_bin.nim | Способ удаления заблокированного или текущего запущенного исполняемого файла на диске. Метод обнаружен @jonasLyk |
| encrypt_decrypt_bin.nim | Шифрование/дешифрование с использованием AES256 (режим CTR) с помощью библиотеки Nimcrypto |
| amsi_patch_bin.nim | Патчит AMSI в текущем процессе |
| amsi_providerpatch_bin.nim | Патчит DLL-провайдера AMSI (в данном случае MpOav.dll) для обхода AMSI. Опубликовано здесь |
| etw_patch_bin.nim | Патчит ETW в текущем процессе (вклад от ) |
| wmiquery_bin.nim | Запрашивает запущенные процессы и установленные антивирусы с помощью WMI |
| out_compressed_dll_bin.nim | Сжимает, кодирует в Base-64 и выводит код PowerShell для загрузки управляемой DLL в память. Порт оригинального скрипта PowerSploit на Nim. |
| dynamic_shellcode_local_inject_bin.nim | POC для локальной инъекции шеллкода, получаемого динамически, вместо жёсткого кодирования в массиве. |
| shellcode_callback_bin.nim | Выполняет шеллкод с помощью функций обратного вызова |
| shellcode_bin.nim | Создаёт приостановленный процесс и внедряет шеллкод с помощью VirtualAllocEx/CreateRemoteThread. Также демонстрирует использование определений времени компиляции для определения архитектуры, ОС и т.д. |
| shellcode_fiber.nim | Выполнение шеллкода через файберы |
| shellcode_inline_asm_bin.nim | Выполняет шеллкод с использованием встроенного ассемблера |
| ssdt_dump.nim | Простое получение SSDT с использованием таблицы функций времени выполнения из каталога исключений. Техника вдохновлена статьёй MDSEC |
| syscalls_bin.nim | Показывает, как делать прямые системные вызовы |
| execute_powershell_bin.nim | Размещает CLR и выполняет PowerShell через неуправляемое пространство выполнения |
| passfilter_lib.nim | Логирует смены пароля в файл путём (зло)употребления фильтром сложности пароля |
| minidump_bin.nim | Создаёт дамп памяти lsass с помощью MiniDumpWriteDump |
| http_request_bin.nim | Демонстрирует пару способов выполнения HTTP-запросов |
| execute_sct_bin.nim | Выполнение .sct файла через GetObject() |
| scriptcontrol_bin.nim | Динамическое выполнение VBScript и JScript с помощью COM-объекта MSScriptControl |
| excel_com_bin.nim | Внедряет шеллкод с помощью COM-объекта Excel и макросов |
| keylogger_bin.nim | Кейлоггер с помощью SetWindowsHookEx |
| memfd_python_interpreter_bin.nim | Использует системный вызов memfd_create для загрузки бинарного файла в анонимный файл и выполняет его с помощью системного вызова execve. |
| uuid_exec_bin.nim | Размещает шеллкод из массива UUID в куче и использует обратный вызов EnumSystemLocalesA для выполнения шеллкода. |
| unhookc.nim | Снимает хуки с ntdll.dll для обхода детектов EDR/AV (встраивает шаблон кода C из ired.team) |
| unhook.nim | Снимает хуки с ntdll.dll для обхода детектов EDR/AV (чистая реализация на Nim) |
| taskbar_ewmi_bin.nim | Использует инъекцию Extra Window Memory через свойство Running Application панели задач для выполнения шеллкода. |
| fork_dump_bin.nim | (Зло)употребляет реализацией fork() в Windows и получает дескриптор удалённого процесса с правом доступа PROCESS_CREATE_PROCESS. Затем пытается сделать дамп памяти разветвлённого процесса с помощью MiniDumpWriteDump() |
| ldap_query_bin.nim | Выполняет LDAP-запросы через COM с помощью провайдера ADSI из ADO |
| sandbox_process_bin.nim | Помещает процесс в песочницу, устанавливая его уровень целостности как Untrusted и удаляя важные токены. Это может использоваться для "тихого отключения" PPL-процесса (например, AV/EDR) |
| list_remote_shares.nim | Использует NetShareEnum для вывода списка общих ресурсов, доступных текущему пользователю |
| chrome_dump_bin.nim | Читает и расшифровывает куки из базы данных sqlite Chrome |
| suspended_thread_injection.nim | Выполнение шеллкода через инъекцию в приостановленный поток |
| dns_exfiltrate.nim | Простая эксфильтрация через DNS с помощью запросов TXT-записей |
| rsrc_section_shellcode.nim | Выполнение шеллкода, встроенного в секцию .rsrc бинарного файла |
| token_steal_cmd.nim | Кража/имперсонализация токена и выполнение команды |
| anti_analysis_isdebuggerpresent.nim | Простой анти-анализ, проверяющий наличие отладчика |
| sandbox_domain_check.nim | Простой метод обхода песочницы, проверяющий, подключён ли компьютер к домену |
| Hook.nim | Пример наступательного хука для MessageBoxA |
| anti_debug.nim | Демонстрация двух методов анти-отладки |
| anti_debug_via_tls.nim | Анти-отладка через TLS |
| local_pe_execution.nim | Выполнение exe и dll файлов в памяти |
| stack_string_allocation.nim | Выделение C и широких строк в стеке с помощью массивов |
| hardware_breakpoints.nim | Хук функций с помощью аппаратных точек останова |