
I miei esperimenti nell'armamento di Nim (https://nim-lang.org/)
I miei esperimenti nell'armare Nim per lo sviluppo di implant e operazioni offensive generali.
DllMain
mingw e il passaggio di un singolo flag al compilatore Nim.| File | Descrizione |
|---|---|
| amsi_patch_2_bin.nim | Applica patch ad AMSI dal processo corrente usando un metodo diverso (WIP, aiuto apprezzato) |
| excel_4_com_bin.nim | Inietta shellcode usando l'oggetto COM di Excel e le macro Excel 4 (WIP) |
Questo repository non fornisce binari, dovrai compilarli tu stesso. Questo repository è stato impostato per cross-compilare i file sorgente Nim di esempio verso Windows da Linux o MacOS.
Usa VSCode Devcontainers per impostare automaticamente un ambiente di sviluppo per te (vedi la sezione Setting Up a Dev Environment). Una volta fatto, esegui semplicemente make.
Installa Nim usando il gestore pacchetti del tuo sistema (per Windows usa l'installer sul sito ufficiale)
brew install nimapt install nimchoco install nim(Nim fornisce anche un'immagine docker su Dockerhub)
Ora dovresti avere i comandi nim e nimble disponibili, il primo è il compilatore Nim e il secondo è il gestore pacchetti di Nim.
Installa la toolchain Mingw necessaria per la cross-compilazione verso Windows (non necessaria se compili su Windows):
apt-get install mingw-w64brew install mingw-w64Infine, installa la magnifica libreria Winim, insieme a zippy e nimcrypto
nimble install winim zippy nimcryptoPoi entra nella root di questo repository ed esegui make.
Dovresti trovare i binari e le dll nella directory bin/
Vedi la sezione sulla cross-compilazione nella guida all'uso del compilatore Nim, per molti più dettagli.
La cross-compilazione verso Windows da MacOs/*nix richiede la toolchain mingw, di solito basta brew install mingw-w64 o apt install mingw-w64.
Devi poi passare il flag -d=mingw al compilatore Nim.
Ad es. nim c -d=mingw --app=console --cpu=amd64 source.nim
Vedi l'incredibile sezione FFI nel manuale di Nim.
Se hai familiarità con il P/Invoke di csharp, è essenzialmente lo stesso concetto, anche se ha un aspetto leggermente più brutto:
Esempio di chiamata 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)
Per qualsiasi chiamata complessa alle API di Windows, usa la [libreria Winim](https://github.com/khchen/winim), fa risparmiare un'enorme quantità di tempo e non aggiunge troppo alla dimensione dell'eseguibile (vedi sotto) a seconda di come la importi.
Ha anche il supporto COM!!!
## Creazione di DLL Windows con un `DllMain` esportato
Un grande ringraziamento alla persona che ha pubblicato [questo](https://forum.nim-lang.org/t/1973) sul forum di Nim.
Il compilatore Nim cerca di creare automaticamente una funzione `DllMain` per te in fase di compilazione ogni volta che gli dici di creare una DLL Windows, ma per qualche motivo non la esporta effettivamente. Per avere un `DllMain` esportato devi passare `--nomain` e definire tu stesso una funzione `DllMain` con le opportune pragmas (`stdcall, exportc, dynlib`).
Devi anche chiamare `NimMain` dal tuo `DllMain` per inizializzare il garbage collector di Nim. (Molto importante, altrimenti il tuo computer esploderà letteralmente).
Esempio:```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
Per compilare:``` nim c -d=mingw --app=lib --nomain --cpu=amd64 mynim.dll
### Creazione di XLL
Puoi creare un XLL (una DLL di Excel, immagina) con una funzione di auto-apertura che può essere utilizzata per la consegna del payload. Il seguente codice crea un semplice per un XLL che ha una funzione di auto-apertura e tutto il codice boilerplate necessario per compilare come libreria di collegamento. Il POC compila come DLL, puoi quindi cambiare l'estensione in .xll e si aprirà in Excel ed eseguirà il payload quando viene fatto doppio clic:```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
Ci sono molte altre cose subdole che si possono fare con le XLL. Vedi altri esempi di tecniche XLL qui.
Tratto dalla pagina FAQ di Nim
Per la maggiore riduzione delle dimensioni usa le seguenti flag -d:danger -d:strip --opt:size
Inoltre, ho scoperto che puoi risparmiare qualche byte in più passando --passc=-flto --passl=-flto al compilatore. Dai anche un'occhiata al Makefile in questo repository.
Queste flag riducono le dimensioni drasticamente: l'esempio di shellcode injection passa da 484.3 KB a 46.5 KB quando compilato in cross da MacOSX!
Un enorme grazie a @Shitsecure per averlo scoperto!
Di default, Nim non genera PE con una tabella di rilocazione, necessaria per la maggior parte degli strumenti che caricano riflessivamente gli EXE.
Per generare un eseguibile Nim con una sezione di rilocazione devi passare alcune flag aggiuntive al linker.
Nello specifico: --passL:-Wl,--dynamicbase
Esempio di comando completo:``` nim c --passL:-Wl,--dynamicbase my_awesome_malwarez.nim
## Differenza di dimensione dell'eseguibile quando si usa la libreria Winim rispetto a quando non si usa
Incredibilmente, la differenza di dimensione è piuttosto trascurabile. Soprattutto quando si applicano le ottimizzazioni di dimensione descritte sopra.
I due esempi `pop_bin.nim` e `pop_winim_bin.nim` sono stati creati per questo scopo.
Il primo definisce manualmente la chiamata WinAPI `MessageBox` e il secondo usa la libreria Winim (nello specifico `winim/lean` che è solo il core SDK, vedi [qui](https://github.com/khchen/winim#usage)), risultati:```
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 importi l'intera libreria Winim con import winim/com, aggiunge solo circa ~20 KB che, considerando la quantità di funzionalità che astrae, vale al 100% quella dimensione 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
## Considerazioni Opsec
A causa del modo in cui Nim risolve dinamicamente le DLL usando `LoadLibrary` tramite la sua FFI, nessuna delle tue funzioni importate esternamente apparirà effettivamente negli import statici dell'eseguibile (vedi [questo post sul blog](https://web.archive.org/web/20210117002945/https://secbytes.net/implant-roulette-part-1:-nimplant/) per maggiori dettagli):

Se compili sorgenti Nim in una DLL, sembra che avrai sempre un `NimMain` esportato, indipendentemente dal fatto che tu specifichi o meno il tuo `DllMain` (??). Questo potrebbe potenzialmente essere usato come firma, non so quante aziende stiano effettivamente usando Nim nel loro stack di sviluppo. Sicuramente si distingue.

## Scrivere Nim senza il Nim Runtime
Poiché Nim è fortemente segnalato dalle soluzioni Antivirus, un modo per aggirare il problema è scrivere programmi Nim senza il runtime di Nim. [Writing Nim-less Nim](https://www.youtube.com/watch?v=EXX3HmCG3pw) è un talk che illustra i passi per scrivere codice Nim senza il runtime di Nim e C; il codice sorgente di questo talk è disponibile [qui](https://github.com/m4ul3r/writing_nimless). Il talk segue ed espande il lavoro di [zimawhit3](https://github.com/zimawhit3) con [Bitmancer](https://github.com/zimawhit3/Bitmancer/tree/main).
Il presupposto è fare affidamento sulle definizioni dei tipi di `winim` e sfruttare una scrittura del codice che non comporti l'uso del runtime di Nim.
## Convertire codice C in Nim
https://github.com/nim-lang/c2nim
L'ho usato per tradurre un sacco di piccoli snippet C, non ho provato nulla di più complesso.
## Ponti linguistici
- Integrazione Python https://github.com/yglukhov/nimpy
* Questo è in realtà super interessante, [specialmente questa parte](https://github.com/yglukhov/nimpy/blob/master/nimpy/py_lib.nim#L330). Con qualche modifica, potrebbe caricare PythonxXX.dll dalla memoria?
- Integrazione Jave VM: https://github.com/yglukhov/jnim
## Debugging
Usa la funzione `repr()` in combinazione con `echo`, supporta quasi tutti (??) i tipi di dato, persino le struct!
Vedi [questo post sul blog per maggiori dettagli](https://nim-lang.org/blog/2017/10/02/documenting-profiling-and-debugging-nim-code.html)
## Configurare un ambiente di sviluppo
Questo repository supporta [VSCode Devcontainers](https://code.visualstudio.com/docs/remote/create-dev-container) che ti permette di sviluppare in un container Docker. Questo automatizza la configurazione di un ambiente di sviluppo per te.
1. Installa VSCode e Docker desktop
2. Clona questo repo e aprilo in VSCode
3. Installa l'estensione `Visual Studio Code Remote - Containers`
4. Apri la palette dei comandi e seleziona il comando `Remote-Containers: Reopen in Container`
VScode ora costruirà l'immagine Docker (ci vorrà un po') e ti porterà direttamente nel tuo ambiente di sviluppo Nim pre-costruito!
## Insidie in cui mi sono imbattuto
- Quando chiami winapi con Winim e provi a passare un valore nullo, assicurati di passare il valore `NULL` (definito all'interno della libreria Winim) invece del valore `nil` nativo di Nim. (Ugh)
- Per ottenere l'handle di sistema del file creato dopo aver chiamato `open()` su Windows, devi chiamare `f.getOsFileHandle()` **non** `f.getFileHandle()` per qualche motivo.
- Il compilatore Nim accetta argomenti nella forma `-a=value` o `--arg=value` anche se guardando l'uso sembra accettare solo argomenti passati come `-a:value` o `--arg:value`. (Importante per i Makefile)
- Quando definisci un byte array, devi anche indicare almeno nel primo valore che si tratta di un byte array; un po' strano ma ok (https://forum.nim-lang.org/t/4322)
Byte array in C#:```csharp
byte[] buf = new byte[5] {0xfc,0x48,0x81,0xe4,0xf0,0xff}
Array di byte in Nim:```nim var buf: array[5, byte] = [byte 0xfc,0x48,0x81,0xe4,0xf0,0xff]
## Librerie Nim interessanti
- 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
## Link per lo sviluppo di implant in 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
## Contributori
Un abbraccio virtuale a tutti coloro che hanno contribuito ❤️
<a href="https://github.com/byt3bl33d3r/OffensiveNim/graphs/contributors">
<img src="https://contrib.rocks/image?repo=byt3bl33d3r/OffensiveNim" />
</a>
| File | Descrizione |
|---|
| pop_bin.nim | Chiama MessageBox WinApi senza usare la libreria Winim |
| pop_winim_bin.nim | Chiama MessageBox con la libreria Winim |
| pop_winim_lib.nim | Esempio di creazione di una DLL Windows con un DllMain esportato |
| execute_assembly_bin.nim | Ospita il CLR, esegue in modo riflessivo assembly .NET dalla memoria |
| clr_host_cpp_embed_bin.nim | Ospita il CLR incorporando direttamente codice C++, esegue un assembly .NET dal disco |
| scshell_c_embed_bin.nim | Mostra come armare rapidamente codice C esistente incorporando SCShell (C) direttamente in Nim |
| fltmc_bin.nim | Enumera tutti i driver Minifilter |
| blockdlls_acg_ppid_spoof_bin.nim | Crea un processo sospeso che falsifica il suo PPID a explorer.exe, abilita anche BlockDLLs e ACG |
| named_pipe_client_bin.nim | Client Named Pipe |
| named_pipe_server_bin.nim | Server Named Pipe |
| embed_rsrc_bin.nim | Incorpora una risorsa (file zip) al momento della compilazione ed estrae i contenuti a runtime |
| self_delete_bin.nim | Un modo per eliminare un eseguibile bloccato o in esecuzione sul disco. Metodo scoperto da @jonasLyk |
| encrypt_decrypt_bin.nim | Crittografia/Decrittografia usando AES256 (Modalità CTR) tramite la libreria Nimcrypto |
| amsi_patch_bin.nim | Applica patch ad AMSI dal processo corrente |
| amsi_providerpatch_bin.nim | Applica patch alla DLL del provider AMSI (in questo caso MpOav.dll) per bypassare AMSI. Pubblicato qui |
| etw_patch_bin.nim | Applica patch a ETW dal processo corrente (Contribuito da ) |
| wmiquery_bin.nim | Interroga i processi in esecuzione e gli AV installati usando WMI |
| out_compressed_dll_bin.nim | Comprime, codifica in Base-64 e restituisce codice PowerShell per caricare una DLL gestita in memoria. Port dello script PowerSploit originale in Nim. |
| dynamic_shellcode_local_inject_bin.nim | POC per iniettare localmente shellcode recuperato dinamicamente invece di codificarlo in un array. |
| shellcode_callback_bin.nim | Esegue shellcode utilizzando funzioni di callback |
| shellcode_bin.nim | Crea un processo sospeso e inietta shellcode con VirtualAllocEx/CreateRemoteThread. Dimostra anche l'uso di definizioni in fase di compilazione per rilevare architettura, OS, ecc. |
| shellcode_fiber.nim | Esecuzione di shellcode tramite fiber |
| shellcode_inline_asm_bin.nim | Esegue shellcode usando assembly inline |
| ssdt_dump.nim | Recupero semplice dell'SSDT usando la tabella delle funzioni di runtime dalla directory delle eccezioni. Tecnica ispirata dall'articolo di MDSEC |
| syscalls_bin.nim | Mostra come effettuare chiamate di sistema dirette |
| execute_powershell_bin.nim | Ospita il CLR ed esegue PowerShell attraverso un runspace non gestito |
| passfilter_lib.nim | Registra le modifiche alle password su un file (ab)usando un filtro di complessità delle password |
| minidump_bin.nim | Crea un dump della memoria di lsass usando MiniDumpWriteDump |
| http_request_bin.nim | Dimostra un paio di modi per effettuare richieste HTTP |
| execute_sct_bin.nim | Esecuzione di file .sct tramite GetObject() |
| scriptcontrol_bin.nim | Esegue dinamicamente VBScript e JScript usando l'oggetto COM MSScriptControl |
| excel_com_bin.nim | Inietta shellcode usando l'oggetto COM di Excel e le macro |
| keylogger_bin.nim | Keylogger usando SetWindowsHookEx |
| memfd_python_interpreter_bin.nim | Usa la syscall memfd_create per caricare un binario in un file anonimo ed eseguirlo con la syscall execve. |
| uuid_exec_bin.nim | Pianta shellcode da un array UUID nello spazio heap e usa la callback EnumSystemLocalesA per eseguire lo shellcode. |
| unhookc.nim | Sgancia ntdll.dll per eludere gli hook di EDR/AV (incorpora il template di codice C da ired.team) |
| unhook.nim | Sgancia ntdll.dll per eludere gli hook di EDR/AV (implementazione pura in Nim) |
| taskbar_ewmi_bin.nim | Usa l'iniezione di memoria della finestra extra tramite la proprietà Running Application della TaskBar per eseguire lo shellcode. |
| fork_dump_bin.nim | (ab)usa l'implementazione di fork() di Windows e acquisisce un handle a un processo remoto usando il diritto di accesso PROCESS_CREATE_PROCESS. Tenta quindi di dumpare la memoria del processo forkato usando MiniDumpWriteDump() |
| ldap_query_bin.nim | Esegue query LDAP tramite COM usando il provider ADSI di ADO |
| sandbox_process_bin.nim | Questo mette in sandbox un processo impostando il suo livello di integrità a Untrusted e rimuove token importanti. Può essere usato per "disabilitare silenziosamente" un processo PPL (es. AV/EDR) |
| list_remote_shares.nim | Usa NetShareEnum per elencare le condivisioni accessibili dall'utente corrente |
| chrome_dump_bin.nim | Legge e decripta i cookie dal database sqlite di Chrome |
| suspended_thread_injection.nim | Esecuzione di shellcode tramite iniezione di thread sospesi |
| dns_exfiltrate.nim | Esfiltrazione DNS semplice tramite query di record TXT |
| rsrc_section_shellcode.nim | Esegue shellcode incorporato nella sezione .rsrc del binario |
| token_steal_cmd.nim | Ruba un token/impersona e poi esegue un comando |
| anti_analysis_isdebuggerpresent.nim | Semplice anti-analisi che controlla la presenza di un debugger |
| sandbox_domain_check.nim | Semplice tecnica di evasione sandbox, che controlla se il computer è connesso al dominio o meno |
| Hook.nim | Esempio di hook offensivo per MessageBoxA |
| anti_debug.nim | Mostra due tecniche di anti-debugging |
| anti_debug_via_tls.nim | Anti-debugging tramite TLS |
| local_pe_execution.nim | Esegue file exe e dll in memoria |
| stack_string_allocation.nim | Alloca stringhe c e wide sullo stack usando array |
| hardware_breakpoints.nim | Aggancia funzioni usando breakpoint hardware |