
Meus experimentos em armar o Nim (https://nim-lang.org/)
Meus experimentos em armar Nim para desenvolvimento de implants e operações ofensivas em geral.
DllMain exportado
mingw e passar uma única flag para o compilador Nim.| Arquivo | Descrição |
|---|---|
| amsi_patch_2_bin.nim | Corrige (patch) o AMSI do processo atual usando um método diferente (WIP, ajuda é bem-vinda) |
| excel_4_com_bin.nim |
Este repositório não fornece binários, você terá que compilá-los por conta própria. Este repositório foi configurado para cross-compilar os arquivos fonte Nim de exemplo para Windows a partir de Linux ou MacOS.
Use VSCode Devcontainers para configurar automaticamente um ambiente de desenvolvimento para você (veja a seção Configurando um Ambiente de Desenvolvimento). Feito isso, basta executar make.
Instale Nim usando o gerenciador de pacotes do seu sistema (para Windows use o instalador no site oficial)
brew install nimapt install nimchoco install nim(Nim também fornece uma imagem docker no Dockerhub)
Agora você deve ter os comandos nim e nimble disponíveis, o primeiro é o compilador Nim e o segundo é o gerenciador de pacotes do Nim.
Instale o toolchain Mingw necessário para cross-compilação para Windows (Não necessário se estiver compilando no Windows):
apt-get install mingw-w64brew install mingw-w64Finalmente, instale a magnífica biblioteca Winim, juntamente com zippy e nimcrypto
nimble install winim zippy nimcryptoDepois, entre na raiz deste repositório e execute make.
Você encontrará os binários e dlls no diretório bin/
Veja a seção de cross-compilation no guia de uso do compilador Nim, para muito mais detalhes.
Cross compilar para Windows a partir de MacOS/*nix requer o toolchain mingw, geralmente basta brew install mingw-w64 ou apt install mingw-w64.
Depois, você só precisa passar a flag -d=mingw para o compilador Nim.
Ex.: nim c -d=mingw --app=console --cpu=amd64 source.nim
Veja a seção FFI insana no manual do Nim.
Se você está familiarizado com P/Invoke do C#, é essencialmente o mesmo conceito, embora pareça um pouco mais feio:
Exemplo de chamada a `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)
Para chamadas complexas da API Windows, use a [biblioteca Winim](https://github.com/khchen/winim), economiza uma quantidade enorme de tempo e não adiciona muito ao tamanho do executável (veja abaixo) dependendo de como você a importa.
Tem até suporte a COM!!!
## Criando DLLs Windows com um `DllMain` exportado
Muito obrigado à pessoa que postou [isto](https://forum.nim-lang.org/t/1973) no fórum Nim.
O compilador Nim tenta criar uma função `DllMain` automaticamente para você no momento da compilação sempre que você diz a ele para criar uma DLL do Windows, no entanto, por algum motivo ele não a exporta. Para ter um `DllMain` exportado, você precisa passar `--nomain` e definir você mesmo uma função `DllMain` com os pragmas apropriados (`stdcall, exportc, dynlib`).
Você também precisa chamar `NimMain` a partir do seu `DllMain` para inicializar o coletor de lixo do Nim. (Muito importante, caso contrário seu computador vai literalmente explodir).
Exemplo:```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
Para compilar:``` nim c -d=mingw --app=lib --nomain --cpu=amd64 mynim.dll
### Criando XLLs
Você pode criar um XLL (uma DLL do Excel, imagine só) com uma função de abertura automática que pode ser usada para entrega de payload. O código a seguir cria um simples XLL que possui uma função de abertura automática e todo o código boilerplate necessário para compilar como uma biblioteca de link. O POC compila como uma DLL, você pode então alterar a extensão para .xll e ele abrirá no Excel e executará o payload quando clicado duas vezes:```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
Existem muitas outras coisas sorrateiras que podem ser feitas com XLLs. Veja mais exemplos de técnicas de XLL aqui.
Extraído da página de FAQ do Nim
Para a maior redução de tamanho, use as seguintes flags -d:danger -d:strip --opt:size
Além disso, descobri que você pode economizar mais alguns bytes passando --passc=-flto --passl=-flto para o compilador. Dê uma olhada também no Makefile deste repositório.
Essas flags diminuem os tamanhos drasticamente: o exemplo de injeção de shellcode vai de 484,3 KB para 46,5 KB quando compilado de forma cruzada a partir do MacOSX!
Muito obrigado a @Shitsecure por descobrir isso!
Por padrão, o Nim não gera PEs com uma tabela de realocação, que é necessária para a maioria das ferramentas que carregam EXEs de forma reflexiva.
Para gerar um executável Nim com uma seção de realocação, você precisa passar algumas flags adicionais para o linker.
Especificamente: --passL:-Wl,--dynamicbase
Exemplo de comando completo:``` nim c --passL:-Wl,--dynamicbase my_awesome_malwarez.nim
## Diferença de tamanho do executável ao usar a biblioteca Winim vs sem ela
Incrivelmente, a diferença de tamanho é bastante insignificante. Especialmente quando se aplicam as otimizações de tamanho descritas acima.
Os dois exemplos `pop_bin.nim` e `pop_winim_bin.nim` foram criados para este propósito.
O primeiro define a chamada `MessageBox` da WinAPI manualmente e o segundo usa a biblioteca Winim (especificamente `winim/lean` que é apenas o SDK principal, veja [aqui](https://github.com/khchen/winim#usage)), resultados:```
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
Se você importar toda a biblioteca Winim com import winim/com, ela adiciona apenas cerca de ~20 KB, o que, considerando a quantidade de funcionalidades que ela abstrai, vale 100% a pena esse tamanho extra:```
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
## Considerações de Opsec
Devido à forma como o Nim resolve DLLs dinamicamente usando `LoadLibrary` através da sua FFI, nenhuma das suas funções importadas externamente aparecerá nas importações estáticas do executável (veja [este post do blog](https://web.archive.org/web/20210117002945/https://secbytes.net/implant-roulette-part-1:-nimplant/) para mais detalhes):

Se você compilar código-fonte Nim para uma DLL, parece que você sempre terá um `NimMain` exportado, independentemente de especificar seu próprio `DllMain` ou não (??). Isso poderia potencialmente ser usado como uma assinatura, não sei quantas empresas estão realmente usando Nim em sua stack de desenvolvimento. Definitivamente se destaca.

## Escrevendo Nim sem o Runtime do Nim
Como o Nim é fortemente sinalizado por soluções antivírus, uma maneira de contornar isso é escrever programas Nim sem o runtime do Nim. [Writing Nim-less Nim](https://www.youtube.com/watch?v=EXX3HmCG3pw) é uma palestra que descreve as etapas de como escrever código Nim sem os runtimes Nim e C, o código fonte desta palestra está disponível [aqui](https://github.com/m4ul3r/writing_nimless). A palestra segue e expande o trabalho de [zimawhit3](https://github.com/zimawhit3) com [Bitmancer](https://github.com/zimawhit3/Bitmancer/tree/main).
A premissa é confiar nas definições de tipo do `winim` e aproveitar a escrita de código que não resulte no uso do runtime do Nim.
## Convertendo código C para Nim
https://github.com/nim-lang/c2nim
Usei para traduzir alguns pequenos trechos de C, ainda não tentei nada grande.
## Pontes de Linguagem
- Integração com Python https://github.com/yglukhov/nimpy
* Isso é realmente super interessante, [especialmente esta parte](https://github.com/yglukhov/nimpy/blob/master/nimpy/py_lib.nim#L330). Com alguma modificação, será que isso poderia carregar a PythonxXX.dll da memória?
- Integração com Jave VM: https://github.com/yglukhov/jnim
## Depuração
Use a função `repr()` em combinação com `echo`, suporta quase todos (??) os tipos de dados, até structs!
Veja [este post do blog para mais informações](https://nim-lang.org/blog/2017/10/02/documenting-profiling-and-debugging-nim-code.html)
## Configurando um ambiente de desenvolvimento
Este repositório suporta [Devcontainers do VSCode](https://code.visualstudio.com/docs/remote/create-dev-container) que permite desenvolver em um contêiner Docker. Isso automatiza a configuração de um ambiente de desenvolvimento para você.
1. Instale o VSCode e o Docker desktop
2. Clone este repositório e abra-o no VSCode
3. Instale a extensão `Visual Studio Code Remote - Containers`
4. Abra a paleta de comandos e selecione o comando `Remote-Containers: Reopen in Container`
O VSCode agora criará a imagem Docker (vai demorar um pouco) e colocará você diretamente no seu ambiente de desenvolvimento Nim pré-construído!
## Armadilhas que me vi caindo
- Ao chamar winapis com Winim e tentar passar um valor nulo, certifique-se de passar o valor `NULL` (definido dentro da biblioteca Winim) em vez do valor `nil` embutido do Nim. (Ugh)
- Para obter o handle do SO para o arquivo criado após chamar `open()` no Windows, você precisa chamar `f.getOsFileHandle()` **não** `f.getFileHandle()` por razões.
- O compilador Nim aceita argumentos na forma `-a=value` ou `--arg=value` mesmo que, se você olhar o uso, ele só mostre argumentos passados como `-a:value` ou `--arg:value`. (Importante para Makefiles)
- Ao definir um array de bytes, você também precisa indicar pelo menos no primeiro valor que é um array de bytes, um pouco estranho, mas ok (https://forum.nim-lang.org/t/4322)
Array de bytes em C#:```csharp
byte[] buf = new byte[5] {0xfc,0x48,0x81,0xe4,0xf0,0xff}
Array de bytes em Nim:```nim var buf: array[5, byte] = [byte 0xfc,0x48,0x81,0xe4,0xf0,0xff]
## Bibliotecas Nim interessantes
- 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
## Links do Nim para desenvolvimento de implants
- 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
## Contribuidores
Abraço virtual para todos que contribuíram ❤️
<a href="https://github.com/byt3bl33d3r/OffensiveNim/graphs/contributors">
<img src="https://contrib.rocks/image?repo=byt3bl33d3r/OffensiveNim" />
</a>
| Arquivo | Descrição |
|---|
| pop_bin.nim | Chamar MessageBox WinApi sem usar a biblioteca Winim |
| pop_winim_bin.nim | Chamar MessageBox com a biblioteca Winim |
| pop_winim_lib.nim | Exemplo de criação de uma DLL Windows com um DllMain exportado |
| execute_assembly_bin.nim | Hospeda o CLR, executa reflexivamente assemblies .NET a partir da memória |
| clr_host_cpp_embed_bin.nim | Hospeda o CLR incorporando diretamente código C++, executa um assembly .NET do disco |
| scshell_c_embed_bin.nim | Mostra como armar rapidamente código C existente incorporando SCShell (C) diretamente dentro do Nim |
| fltmc_bin.nim | Enumera todos os drivers Minifilter |
| blockdlls_acg_ppid_spoof_bin.nim | Cria um processo suspenso que falsifica seu PPID para explorer.exe, também ativa BlockDLLs e ACG |
| named_pipe_client_bin.nim | Cliente de Pipe Nomeado |
| named_pipe_server_bin.nim | Servidor de Pipe Nomeado |
| embed_rsrc_bin.nim | Incorpora um recurso (arquivo zip) em tempo de compilação e extrai o conteúdo em tempo de execução |
| self_delete_bin.nim | Uma forma de deletar um executável bloqueado ou em execução no disco. Método descoberto por @jonasLyk |
| encrypt_decrypt_bin.nim | Criptografia/Descriptografia usando AES256 (Modo CTR) com a biblioteca Nimcrypto |
| amsi_patch_bin.nim | Corrige (patch) o AMSI do processo atual |
| amsi_providerpatch_bin.nim | Corrige a DLL do Provedor AMSI (neste caso MpOav.dll) para contornar o AMSI. Publicado aqui |
| etw_patch_bin.nim | Corrige (patch) o ETW do processo atual (Contribuição de ) |
| wmiquery_bin.nim | Consulta processos em execução e AVs instalados usando WMI |
| out_compressed_dll_bin.nim | Comprime, codifica em Base-64 e gera código PowerShell para carregar uma dll gerenciada na memória. Port do script original PowerSploit para Nim. |
| dynamic_shellcode_local_inject_bin.nim | POC para injetar shellcode localmente recuperado dinamicamente em vez de codificá-lo em um array. |
| shellcode_callback_bin.nim | Executa shellcode usando funções de Callback |
| shellcode_bin.nim | Cria um processo suspenso e injeta shellcode com VirtualAllocEx/CreateRemoteThread. Também demonstra o uso de definições de tempo de compilação para detectar arch, os etc. |
| shellcode_fiber.nim | Execução de shellcode via fibras |
| shellcode_inline_asm_bin.nim | Executa shellcode usando assembly inline |
| ssdt_dump.nim | Recuperação simples de SSDT usando tabela de funções em tempo de execução do diretório de exceção. Técnica inspirada no artigo MDSEC |
| syscalls_bin.nim | Mostra como fazer chamadas diretas ao sistema |
| execute_powershell_bin.nim | Hospeda o CLR e executa PowerShell através de um runspace não gerenciado |
| passfilter_lib.nim | Registrar alterações de senha em um arquivo (ab)usando um filtro de complexidade de senha |
| minidump_bin.nim | Cria um dump de memória do lsass usando MiniDumpWriteDump |
| http_request_bin.nim | Demonstra algumas formas de fazer requisições HTTP |
| execute_sct_bin.nim | Execução de arquivo .sct via GetObject() |
| scriptcontrol_bin.nim | Executa dinamicamente VBScript e JScript usando o objeto COM MSScriptControl |
| excel_com_bin.nim | Injeta shellcode usando o objeto COM do Excel e Macros |
| keylogger_bin.nim | Keylogger usando SetWindowsHookEx |
| memfd_python_interpreter_bin.nim | Usa a chamada de sistema memfd_create para carregar um binário em um arquivo anônimo e executá-lo com a chamada de sistema execve. |
| uuid_exec_bin.nim | Planta shellcode de um array UUID no espaço heap e usa o Callback EnumSystemLocalesA para executar o shellcode. |
| unhookc.nim | Desfaz o hook de ntdll.dll para evitar hooks de EDR/AV (incorpora o template de código C do ired.team) |
| unhook.nim | Desfaz o hook de ntdll.dll para evitar hooks de EDR/AV (implementação pura em nim) |
| taskbar_ewmi_bin.nim | Usa Injeção de Memória de Janela Extra via propriedade Running Application da Barra de Tarefas para executar o shellcode. |
| fork_dump_bin.nim | (ab)usa a implementação do fork() do Windows e adquire um handle para um processo remoto usando o direito de acesso PROCESS_CREATE_PROCESS. Em seguida, tenta despejar a memória do processo bifurcado usando MiniDumpWriteDump() |
| ldap_query_bin.nim | Realizar consultas LDAP via COM usando o provedor ADSI do ADO |
| sandbox_process_bin.nim | Isola um processo (sandbox) definindo seu nível de integridade como Não Confiável e removendo tokens importantes. Isso pode ser usado para "desabilitar silenciosamente" um processo PPL (ex.: AV/EDR) |
| list_remote_shares.nim | Usar NetShareEnum para listar os compartilhamentos acessíveis pelo usuário atual |
| chrome_dump_bin.nim | Ler e descriptografar cookies do banco de dados sqlite do Chrome |
| suspended_thread_injection.nim | Execução de shellcode via injeção de thread suspensa |
| dns_exfiltrate.nim | Exfiltração DNS simples via consultas de registro TXT |
| rsrc_section_shellcode.nim | Executar shellcode incorporado na seção .rsrc do binário |
| token_steal_cmd.nim | Roubar um token/personificar e então executar um comando |
| anti_analysis_isdebuggerpresent.nim | Anti-análise simples que verifica a presença de um depurador |
| sandbox_domain_check.nim | Técnica simples de evasão de sandbox, que verifica se o computador está conectado a um domínio ou não |
| Hook.nim | Exemplo de Hooking ofensivo para MessageBoxA |
| anti_debug.nim | Demonstração de duas técnicas anti-debugging |
| anti_debug_via_tls.nim | Anti-debugging via TLS |
| local_pe_execution.nim | Executar arquivos exe e dll na memória |
| stack_string_allocation.nim | Alocar strings c e wide na pilha usando arrays |
| hardware_breakpoints.nim | Hook de funções usando breakpoints de hardware |
| Injeta shellcode usando o objeto COM do Excel e Macros Excel 4 (WIP) |