
Mes expériences dans l'armement de Nim (https://nim-lang.org/)
Mes expériences d'armement de Nim pour le développement d'implantations et les opérations offensives générales.
DllMain exporté
mingw et de passer un seul drapeau au compilateur nim.| Fichier | Description |
|---|---|
| amsi_patch_2_bin.nim | Corrige AMSI du processus actuel en utilisant une méthode différente (WIP, aide appréciée) |
| excel_4_com_bin.nim |
Ce dépôt ne fournit pas de binaires, vous devrez les compiler vous-même. Ce dépôt a été configuré pour compiler de manière croisée les fichiers source Nim d'exemple vers Windows depuis Linux ou MacOS.
Utilisez VSCode Devcontainers pour configurer automatiquement un environnement de développement pour vous (voir la section Mise en place d'un environnement de développement). Une fois cela fait, exécutez simplement make.
Installez Nim en utilisant le gestionnaire de paquets de votre système (pour Windows, utilisez l'installeur sur le site officiel)
brew install nimapt install nimchoco install nim(Nim fournit également une image docker sur Dockerhub)
Vous devriez maintenant avoir les commandes nim et nimble disponibles, la première est le compilateur Nim et la seconde est le gestionnaire de paquets de Nim.
Installez la chaîne d'outils Mingw nécessaire pour la compilation croisée vers Windows (pas nécessaire si vous compilez sur Windows) :
apt-get install mingw-w64brew install mingw-w64Enfin, installez la magnifique bibliothèque Winim, ainsi que zippy et nimcrypto
nimble install winim zippy nimcryptoEnsuite, placez-vous dans la racine de ce dépôt et exécutez make.
Vous devriez trouver les binaires et DLL dans le répertoire bin/
Voir la section sur la compilation croisée dans le guide d'utilisation du compilateur Nim, pour beaucoup plus de détails.
La compilation croisée vers Windows depuis MacOS/*nix nécessite la chaîne d'outils mingw, généralement il suffit de brew install mingw-w64 ou apt install mingw-w64.
Il vous suffit ensuite de passer le drapeau -d=mingw au compilateur nim.
E.g. nim c -d=mingw --app=console --cpu=amd64 source.nim
Voir la section FFI dans le manuel Nim (impressionnante).
Si vous connaissez P/Invoke en C#, c'est essentiellement le même concept, bien que l'apparence soit un peu plus laide :
Exemple d'appel de `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)
Pour tout appel complexe aux API Windows, utilisez la bibliothèque [Winim](https://github.com/khchen/winim). Cela fait gagner un temps fou et n'ajoute pas trop à la taille de l'exécutable (voir ci-dessous) selon la manière dont vous l'importez.
Elle supporte même COM !!!
## Création de DLL Windows avec un `DllMain` exporté
Un grand merci à la personne qui a posté [ce message](https://forum.nim-lang.org/t/1973) sur le forum Nim.
Le compilateur Nim tente de créer automatiquement une fonction `DllMain` pour vous au moment de la compilation lorsque vous lui demandez de créer une DLL Windows, mais pour une raison quelconque, il ne l'exporte pas réellement. Pour avoir un `DllMain` exporté, vous devez passer `--nomain` et définir vous-même une fonction `DllMain` avec les pragmas appropriés (`stdcall, exportc, dynlib`).
Vous devez également appeler `NimMain` depuis votre `DllMain` pour initialiser le ramasse-miettes de Nim. (Très important, sinon votre ordinateur explosera littéralement).
Exemple :```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
Pour compiler:``` nim c -d=mingw --app=lib --nomain --cpu=amd64 mynim.dll
### Création de XLLs
Vous pouvez créer un XLL (une DLL Excel, imaginez-vous) avec une fonction d'ouverture automatique qui peut être utilisée pour la livraison de charges utiles. Le code suivant crée un simple XLL avec une fonction d'ouverture automatique et tout le code d'initialisation nécessaire pour compiler en tant que bibliothèque de liens. La POC se compile en DLL, vous pouvez ensuite changer l'extension en .xll et il s'ouvrira dans Excel et exécutera la charge utile lorsqu'il sera double-cliqué :```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
Il existe de nombreuses autres choses sournoises qui peuvent être faites avec les XLL. Voir plus d'exemples de techniques d'exploitation des XLL ici.
Extrait de la page FAQ de Nim
Pour une réduction de taille maximale, utilisez les flags suivants -d:danger -d:strip --opt:size
De plus, j'ai constaté que vous pouvez gagner quelques octets supplémentaires en passant --passc=-flto --passl=-flto au compilateur. Jetez également un œil au Makefile dans ce dépôt.
Ces flags réduisent la taille dramatiquement : l'exemple d'injection de shellcode passe de 484,3 Ko à 46,5 Ko lors de la compilation croisée depuis MacOSX!
Un grand merci à @Shitsecure pour avoir découvert cela!
Par défaut, Nim ne génère pas de PE avec une table de relocalisation, ce qui est nécessaire pour la plupart des outils qui chargent réflexivement des EXE.
Pour générer un exécutable Nim avec une section de relocalisation, vous devez passer quelques flags supplémentaires au linker.
Spécifiquement : --passL:-Wl,--dynamicbase
Exemple de commande complète :``` nim c --passL:-Wl,--dynamicbase my_awesome_malwarez.nim
## Différence de taille de l'exécutable avec et sans la bibliothèque Winim
Étonnamment, la différence de taille est assez négligeable. Surtout lorsque vous appliquez les optimisations de taille décrites ci-dessus.
Les deux exemples `pop_bin.nim` et `pop_winim_bin.nim` ont été créés à cet effet.
Le premier définit manuellement l'appel API Win32 `MessageBox` et le second utilise la bibliothèque Winim (plus précisément `winim/lean` qui est uniquement le SDK de base, voir [ici](https://github.com/khchen/winim#usage)), résultats :```
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
Si vous importez toute la bibliothèque Winim avec import winim/com, cela n'ajoute qu'environ ~20 Ko, ce qui, compte tenu de la quantité de fonctionnalités qu'elle abstrait, vaut absolument cette taille supplémentaire :```
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
## Considérations Opsec
Étant donné la manière dont Nim résout dynamiquement les DLL via `LoadLibrary` en utilisant sa FFI, aucune de vos fonctions importées externes n'apparaîtra dans les importations statiques de l'exécutable (voir [cet article de blog](https://web.archive.org/web/20210117002945/https://secbytes.net/implant-roulette-part-1:-nimplant/) pour plus de détails) :

Si vous compilez une source Nim en DLL, il semble que vous aurez toujours un `NimMain` exporté, même si vous spécifiez votre propre `DllMain` ou non (??). Cela pourrait potentiellement servir de signature, je ne sais pas combien d'entreprises utilisent réellement Nim dans leur stack de développement. Cela se démarque définitivement.

## Écrire du Nim sans le runtime Nim
Comme Nim est fortement signalé par les solutions antivirus, une solution consiste à écrire des programmes Nim sans le runtime Nim. [Writing Nim-less Nim](https://www.youtube.com/watch?v=EXX3HmCG3pw) est une présentation détaillant les étapes pour écrire du code Nim sans le runtime Nim et C, le code source de cette présentation est disponible [ici](https://github.com/m4ul3r/writing_nimless). La présentation suit et développe le travail de [zimawhit3](https://github.com/zimawhit3) avec [Bitmancer](https://github.com/zimawhit3/Bitmancer/tree/main).
Le principe est de s'appuyer sur les définitions de types de `winim` et de tirer parti d'une écriture de code qui n'entraînerait pas l'utilisation du runtime de Nim.
## Convertir du code C en Nim
https://github.com/nim-lang/c2nim
Utilisé pour traduire quelques petits extraits C, rien de majeur essayé.
## Ponts linguistiques
- Intégration Python : https://github.com/yglukhov/nimpy
* C'est en fait super intéressant, [surtout cette partie](https://github.com/yglukhov/nimpy/blob/master/nimpy/py_lib.nim#L330). Avec quelques modifications, pourrait-elle charger la PythonxXX.dll depuis la mémoire ?
- Intégration JVM : https://github.com/yglukhov/jnim
## Débogage
Utilisez la fonction `repr()` en combinaison avec `echo`, elle prend en charge presque tous (??) les types de données, même les structures !
Voir [cet article de blog pour plus d'informations](https://nim-lang.org/blog/2017/10/02/documenting-profiling-and-debugging-nim-code.html)
## Mise en place d'un environnement de développement
Ce dépôt prend en charge [les conteneurs de développement VSCode](https://code.visualstudio.com/docs/remote/create-dev-container) qui vous permettent de développer dans un conteneur Docker. Cela automatise la configuration d'un environnement de développement pour vous.
1. Installez VSCode et Docker Desktop
2. Clonez ce dépôt et ouvrez-le dans VSCode
3. Installez l'extension `Visual Studio Code Remote - Containers`
4. Ouvrez la palette de commandes et sélectionnez la commande `Remote-Containers: Reopen in Container`
VSCode va maintenant construire l'image Docker (cela prendra un peu de temps) et vous placera directement dans votre environnement de développement Nim pré-construit !
## Pièges dans lesquels je suis tombé
- Lors de l'appel d'API Windows avec Winim et en essayant de passer une valeur nulle, assurez-vous de passer la valeur `NULL` (définie dans la bibliothèque Winim) au lieu de la valeur `nil` native de Nim. (Ugh)
- Pour obtenir le handle système du fichier créé après avoir appelé `open()` sous Windows, vous devez appeler `f.getOsFileHandle()` **et non** `f.getFileHandle()` pour des raisons obscures.
- Le compilateur Nim accepte les arguments sous la forme `-a=value` ou `--arg=value` même si dans l'utilisation ils ne sont présentés que sous la forme `-a:value` ou `--arg:value`. (Important pour les Makefiles)
- Lors de la définition d'un tableau d'octets, vous devez également indiquer au moins la première valeur qu'il s'agit d'un tableau d'octets, un peu bizarre mais d'accord (https://forum.nim-lang.org/t/4322)
Tableau d'octets en C# :```csharp
byte[] buf = new byte[5] {0xfc,0x48,0x81,0xe4,0xf0,0xff}
Tableau d'octets en Nim:```nim var buf: array[5, byte] = [byte 0xfc,0x48,0x81,0xe4,0xf0,0xff]
## Bibliothèques Nim intéressantes
- 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
## Liens Nim pour le développement d'implant
- 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
## Contributeurs
Câlin virtuel à tous ceux qui ont contribué ❤️
<a href="https://github.com/byt3bl33d3r/OffensiveNim/graphs/contributors">
<img src="https://contrib.rocks/image?repo=byt3bl33d3r/OffensiveNim" />
</a>
| Fichier | Description |
|---|
| pop_bin.nim | Appeler MessageBox WinApi sans utiliser la bibliothèque Winim |
| pop_winim_bin.nim | Appeler MessageBox avec la bibliothèque Winim |
| pop_winim_lib.nim | Exemple de création d'une DLL Windows avec un DllMain exporté |
| execute_assembly_bin.nim | Héberge le CLR, exécute réflexivement des assemblys .NET depuis la mémoire |
| clr_host_cpp_embed_bin.nim | Héberge le CLR en intégrant directement du code C++, exécute un assembly .NET depuis le disque |
| scshell_c_embed_bin.nim | Montre comment armer rapidement du code C existant en intégrant SCShell (C) directement dans Nim |
| fltmc_bin.nim | Énumère tous les pilotes Minifilter |
| blockdlls_acg_ppid_spoof_bin.nim | Crée un processus suspendu qui usurpe son PPID à explorer.exe, active également BlockDLLs et ACG |
| named_pipe_client_bin.nim | Client de tube nommé |
| named_pipe_server_bin.nim | Serveur de tube nommé |
| embed_rsrc_bin.nim | Intègre une ressource (fichier zip) au moment de la compilation et extrait le contenu à l'exécution |
| self_delete_bin.nim | Un moyen de supprimer un exécutable verrouillé ou en cours d'exécution sur le disque. Méthode découverte par @jonasLyk |
| encrypt_decrypt_bin.nim | Chiffrement/Déchiffrement en AES256 (mode CTR) utilisant la bibliothèque Nimcrypto |
| amsi_patch_bin.nim | Corrige AMSI du processus actuel |
| amsi_providerpatch_bin.nim | Corrige la DLL du fournisseur AMSI (dans ce cas MpOav.dll) pour contourner AMSI. Publié ici |
| etw_patch_bin.nim | Corrige ETW du processus actuel (Contribué par ) |
| wmiquery_bin.nim | Interroge les processus en cours d'exécution et les antivirus installés en utilisant WMI |
| out_compressed_dll_bin.nim | Compresse, encode en Base-64 et produit du code PowerShell pour charger une DLL managée en mémoire. Portage du script PowerSploit original en Nim. |
| dynamic_shellcode_local_inject_bin.nim | POC pour injecter localement un shellcode récupéré dynamiquement au lieu de le coder en dur dans un tableau. |
| shellcode_callback_bin.nim | Exécute un shellcode en utilisant des fonctions de rappel |
| shellcode_bin.nim | Crée un processus suspendu et injecte un shellcode avec VirtualAllocEx/CreateRemoteThread. Montre également l'utilisation de définitions de temps de compilation pour détecter l'architecture, le système d'exploitation, etc. |
| shellcode_fiber.nim | Exécution de shellcode via des fibres |
| shellcode_inline_asm_bin.nim | Exécute un shellcode en utilisant l'assembleur en ligne |
| ssdt_dump.nim | Récupération simple de la SSDT en utilisant la table de fonctions d'exécution du répertoire d'exceptions. Technique inspirée de l'article de MDSEC |
| syscalls_bin.nim | Montre comment effectuer des appels système directs |
| execute_powershell_bin.nim | Héberge le CLR et exécute PowerShell via un espace d'exécution non managé |
| passfilter_lib.nim | Enregistre les changements de mot de passe dans un fichier en (détournant) un filtre de complexité de mot de passe |
| minidump_bin.nim | Crée un dump mémoire de lsass en utilisant MiniDumpWriteDump |
| http_request_bin.nim | Montre plusieurs façons de faire des requêtes HTTP |
| execute_sct_bin.nim | Exécution de fichier .sct via GetObject() |
| scriptcontrol_bin.nim | Exécute dynamiquement du VBScript et du JScript en utilisant l'objet COM MSScriptControl |
| excel_com_bin.nim | Injecte un shellcode en utilisant l'objet COM Excel et les macros |
| keylogger_bin.nim | Keylogger utilisant SetWindowsHookEx |
| memfd_python_interpreter_bin.nim | Utilise l'appel système memfd_create pour charger un binaire dans un fichier anonyme et l'exécuter avec l'appel système execve. |
| uuid_exec_bin.nim | Place un shellcode issu d'un tableau UUID dans l'espace du tas et utilise le rappel EnumSystemLocalesA pour exécuter le shellcode. |
| unhookc.nim | Décroche ntdll.dll pour contourner les hooks EDR/AV (intègre le modèle de code C de ired.team) |
| unhook.nim | Décroche ntdll.dll pour contourner les hooks EDR/AV (implémentation pure nim) |
| taskbar_ewmi_bin.nim | Utilise l'injection de mémoire de fenêtre supplémentaire via la propriété Application en cours d'exécution de la barre des tâches pour exécuter le shellcode. |
| fork_dump_bin.nim | (Détourne) l'implémentation de fork() de Windows et acquiert un handle sur un processus distant en utilisant le droit d'accès PROCESS_CREATE_PROCESS. Il tente ensuite de dumper la mémoire du processus forké avec MiniDumpWriteDump() |
| ldap_query_bin.nim | Effectuer des requêtes LDAP via COM en utilisant le fournisseur ADSI d'ADO |
| sandbox_process_bin.nim | Isole un processus en définissant son niveau d'intégrité à Non fiable et supprime les jetons importants. Cela peut être utilisé pour "désactiver silencieusement" un processus PPL (ex: AV/EDR) |
| list_remote_shares.nim | Utiliser NetShareEnum pour lister les partages accessibles par l'utilisateur actuel |
| chrome_dump_bin.nim | Lire et déchiffrer les cookies de la base de données sqlite de Chrome |
| suspended_thread_injection.nim | Exécution de shellcode via l'injection de thread suspendu |
| dns_exfiltrate.nim | Exfiltration DNS simple via des requêtes d'enregistrement TXT |
| rsrc_section_shellcode.nim | Exécuter un shellcode intégré dans la section .rsrc du binaire |
| token_steal_cmd.nim | Voler un jeton/emprunter une identité puis exécuter une commande |
| anti_analysis_isdebuggerpresent.nim | Anti-analyse simple qui vérifie la présence d'un débogueur |
| sandbox_domain_check.nim | Technique simple d'évasion de sandbox, qui vérifie si l'ordinateur est connecté à un domaine ou non |
| Hook.nim | Exemple de hook offensif pour MessageBoxA |
| anti_debug.nim | Présentation de deux techniques anti-débogage |
| anti_debug_via_tls.nim | Anti-débogage via TLS |
| local_pe_execution.nim | Exécuter des fichiers exe et dll en mémoire |
| stack_string_allocation.nim | Allouer des chaînes C et larges sur la pile en utilisant des tableaux |
| hardware_breakpoints.nim | Crocheter des fonctions en utilisant des points d'arrêt matériels |
| Injecte un shellcode en utilisant l'objet COM Excel et les macros Excel 4 (WIP) |