Home

Awesome

<p align="center"> <img height="300" alt="OffensiveNim" src="https://user-images.githubusercontent.com/5151193/98487722-ed729600-21e1-11eb-9d77-a79b0f3634de.png"> </p>

OffensiveNim

My experiments in weaponizing Nim for implant development and general offensive operations.

Table of Contents

Why Nim?

Examples in this repo that work

FileDescription
pop_bin.nimCall MessageBox WinApi without using the Winim library
pop_winim_bin.nimCall MessageBox with the Winim libary
pop_winim_lib.nimExample of creating a Windows DLL with an exported DllMain
execute_assembly_bin.nimHosts the CLR, reflectively executes .NET assemblies from memory
clr_host_cpp_embed_bin.nimHosts the CLR by directly embedding C++ code, executes a .NET assembly from disk
scshell_c_embed_bin.nimShows how to quickly weaponize existing C code by embedding SCShell (C) directly within Nim
fltmc_bin.nimEnumerates all Minifilter drivers
blockdlls_acg_ppid_spoof_bin.nimCreates a suspended process that spoofs its PPID to explorer.exe, also enables BlockDLLs and ACG
named_pipe_client_bin.nimNamed Pipe Client
named_pipe_server_bin.nimNamed Pipe Server
embed_rsrc_bin.nimEmbeds a resource (zip file) at compile time and extracts contents at runtime
self_delete_bin.nimA way to delete a locked or current running executable on disk. Method discovered by @jonasLyk
encrypt_decrypt_bin.nimEncryption/Decryption using AES256 (CTR Mode) using the Nimcrypto library
amsi_patch_bin.nimPatches AMSI out of the current process
amsi_providerpatch_bin.nimPatches the AMSI Provider DLL (in this case MpOav.dll) to bypass AMSI. Published here
etw_patch_bin.nimPatches ETW out of the current process (Contributed by )
wmiquery_bin.nimQueries running processes and installed AVs using using WMI
out_compressed_dll_bin.nimCompresses, Base-64 encodes and outputs PowerShell code to load a managed dll in memory. Port of the orignal PowerSploit script to Nim.
dynamic_shellcode_local_inject_bin.nimPOC to locally inject shellcode recovered dynamically instead of hardcoding it in an array.
shellcode_callback_bin.nimExecutes shellcode using Callback functions
shellcode_bin.nimCreates a suspended process and injects shellcode with VirtualAllocEx/CreateRemoteThread. Also demonstrates the usage of compile time definitions to detect arch, os etc..
shellcode_fiber.nimShellcode execution via fibers
shellcode_inline_asm_bin.nimExecutes shellcode using inline assembly
ssdt_dump.nimSimple SSDT retrieval using runtime function table from exception directory. Technique inspired from MDSEC article
syscalls_bin.nimShows how to make direct system calls
execute_powershell_bin.nimHosts the CLR & executes PowerShell through an un-managed runspace
passfilter_lib.nimLog password changes to a file by (ab)using a password complexity filter
minidump_bin.nimCreates a memory dump of lsass using MiniDumpWriteDump
http_request_bin.nimDemonstrates a couple of ways of making HTTP requests
execute_sct_bin.nim.sct file Execution via GetObject()
scriptcontrol_bin.nimDynamically execute VBScript and JScript using the MSScriptControl COM object
excel_com_bin.nimInjects shellcode using the Excel COM object and Macros
keylogger_bin.nimKeylogger using SetWindowsHookEx
memfd_python_interpreter_bin.nimUse memfd_create syscall to load a binary into an anonymous file and execute it with execve syscall.
uuid_exec_bin.nimPlants shellcode from UUID array into heap space and uses EnumSystemLocalesA Callback in order to execute the shellcode.
unhookc.nimUnhooks ntdll.dll to evade EDR/AV hooks (embeds the C code template from ired.team)
unhook.nimUnhooks ntdll.dll to evade EDR/AV hooks (pure nim implementation)
taskbar_ewmi_bin.nimUses Extra Window Memory Injection via Running Application property of TaskBar in order to execute the shellcode.
fork_dump_bin.nim(ab)uses Window's implementation of fork() and acquires a handle to a remote process using the PROCESS_CREATE_PROCESS access right. It then attempts to dump the forked processes memory using MiniDumpWriteDump()
ldap_query_bin.nimPerform LDAP queries via COM by using ADO's ADSI provider
sandbox_process_bin.nimThis sandboxes a process by setting it's integrity level to Untrusted and strips important tokens. This can be used to "silently disable" a PPL process (e.g. AV/EDR)
list_remote_shares.nimUse NetShareEnum to list the share accessible by the current user
chrome_dump_bin.nimRead and decrypt cookies from Chrome's sqlite database
suspended_thread_injection.nimShellcode execution via suspended thread injection
dns_exfiltrate.nimSimple DNS exfiltration via TXT record queries
rsrc_section_shellcode.nimExecute shellcode embedded in the .rsrc section of the binary
token_steal_cmd.nimSteal a token/impersonate and then run a command
anti_analysis_isdebuggerpresent.nimSimple anti-analysis that checks for a debugger
sandbox_domain_check.nimSimple sandbox evasion technique, that checks if computer is connected to domain or not
Hook.nimOffensive Hooking example for MessageBoxA
anti_debug.nimShowcasing two anti debugging techniques
anti_debug_via_tls.nimAnti-debugging vis TLS
local_pe_execution.nimExecute exe and dll files in memory
stack_string_allocation.nimAllocate c and wide strings on the stack using arrays
hardware_breakpoints.nimHook functions using hardware breakpoints

Examples that are a WIP

FileDescription
amsi_patch_2_bin.nimPatches AMSI out of the current process using a different method (WIP, help appreciated)
excel_4_com_bin.nimInjects shellcode using the Excel COM object and Excel 4 Macros (WIP)

Compiling the examples in this repo

This repository does not provide binaries, you're gonna have to compile them yourself. This repo was setup to cross-compile the example Nim source files to Windows from Linux or MacOS.

Easy Way (Recommended)

Use VSCode Devcontainers to automatically setup a development environment for you (See the Setting Up a Dev Environment section). Once that's done simply run make.

Hard way (For the bold)

Install Nim using your systems package manager (for Windows use the installer on the official website)

(Nim also provides a docker image on Dockerhub)

You should now have the nim & nimble commands available, the former is the Nim compiler and the latter is Nim's package manager.

Install the Mingw toolchain needed for cross-compilation to Windows (Not needed if you're compiling on Windows):

Finally, install the magnificent Winim library, along with zippy and nimcrypto

Then cd into the root of this repository and run make.

You should find the binaries and dlls in the bin/ directory

Cross Compiling

See the cross-compilation section in the Nim compiler usage guide, for a lot more details.

Cross compiling to Windows from MacOs/*nix requires the mingw toolchain, usually a matter of just brew install mingw-w64 or apt install mingw-w64.

You then just have to pass the -d=mingw flag to the nim compiler.

E.g. nim c -d=mingw --app=console --cpu=amd64 source.nim

Interfacing with C/C++

See the insane FFI section in the Nim manual.

If you're familiar with csharps P/Invoke it's essentially the same concept albeit a looks a tad bit uglier:

Calling MessageBox example

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)

For any complex Windows API calls use the Winim library, saves an insane amount of time and doesn't add too much to the executable size (see below) depending on how you import it.

Even has COM support!!!

Creating Windows DLLs with an exported DllMain

Big thanks to the person who posted this on the Nim forum.

The Nim compiler tries to create a DllMain function for you automatically at compile time whenever you tell it to create a windows DLL, however, it doesn't actually export it for some reason. In order to have an exported DllMain you need to pass --nomain and define a DllMain function yourself with the appropriate pragmas (stdcall, exportc, dynlib).

You need to also call NimMain from your DllMain to initialize Nim's garbage collector. (Very important, otherwise your computer will literally explode).

Example:

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

To compile:

nim c -d=mingw --app=lib --nomain --cpu=amd64 mynim.dll

Creating XLLs

You can make an XLL (an Excel DLL, imagine that) with an auto open function that can be used for payload delivery. The following code creates a simple for an XLL that has an auto open function and all other boilerplate code needed to compile as a link library. The POC compiles as a DLL, you can then change the extension to .xll and it will open in Excel and run the payload when double clicked:

#[
    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

There are many other sneaky things that can be done with XLLs. See more examples of XLL tradecraft here.

Optimizing executables for size

Taken from the Nim's FAQ page

For the biggest size decrease use the following flags -d:danger -d:strip --opt:size

Additionally, I've found you can squeeze a few more bytes out by passing --passc=-flto --passl=-flto to the compiler. Also take a look at the Makefile in this repo.

These flags decrease sizes dramatically: the shellcode injection example goes from 484.3 KB to 46.5 KB when cross-compiled from MacOSX!

Reflectively Loading Nim Executables

Huge thanks to @Shitsecure for figuring this out!

By default, Nim doesn't generate PE's with a relocation table which is needed by most tools that reflectively load EXE's.

To generate a Nim executable with a relocation section you need to pass a few additional flags to the linker.

Specifically: --passL:-Wl,--dynamicbase

Full example command:

nim c --passL:-Wl,--dynamicbase my_awesome_malwarez.nim

Executable size difference when using the Winim library vs without

Incredibly enough the size difference is pretty negligible. Especially when you apply the size optimizations outlined above.

The two examples pop_bin.nim and pop_winim_bin.nim were created for this purpose.

The former defines the MessageBox WinAPI call manually and the latter uses the Winim library (specifically winim/lean which is only the core SDK, see here), results:

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

If you import the entire Winim library with import winim/com it adds only around ~20ish KB which considering the amount of functionality it abstracts is 100% worth that extra size:

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 Considerations

Because of how Nim resolves DLLs dynamically using LoadLibrary using it's FFI none of your external imported functions will actually show up in the executables static imports (see this blog post for more on this):

If you compile Nim source to a DLL, seems like you'll always have an exported NimMain, no matter if you specify your own DllMain or not (??). This could potentially be used as a signature, don't know how many shops are actually using Nim in their development stack. Definitely stands out.

Writing Nim without the Nim Runtime

Since Nim is heavily flagged by Anti-Virus solutions, one way around this is writing Nim programs without the Nim runtime. Writing Nim-less Nim is a talk given on the steps outlining how to write Nim code without the Nim and C runtime, source code from this talk is available here. The talk follows and expands on zimawhit3's work with Bitmancer.

The premise is to rely on winim's type definitions and leverage code writing that would not result in Nim's runtime being used.

Converting C code to Nim

https://github.com/nim-lang/c2nim

Used it to translate a bunch of small C snippets, haven't tried anything major.

Language Bridges

Debugging

Use the repr() function in combination with echo, supports almost all (??) data types, even structs!

See this blog post for more

Setting up a dev environment

This repository supports VSCode Devcontainers which allows you to develop in a Docker container. This automates setting up a development environment for you.

  1. Install VSCode and Docker desktop
  2. Clone this repo and open it in VSCode
  3. Install the Visual Studio Code Remote - Containers extension
  4. Open the command pallete and select Remote-Containers: Reopen in Container command

VScode will now build the Docker image (will take a bit) and put you right into your pre-built Nim dev environment!

Pitfalls I found myself falling into

Byte array in C#:

byte[] buf = new byte[5] {0xfc,0x48,0x81,0xe4,0xf0,0xff}

Byte array in Nim:

var buf: array[5, byte] = [byte 0xfc,0x48,0x81,0xe4,0xf0,0xff]

Interesting Nim libraries

Nim for implant dev links

Contributors

Virtual hug to everyone who contributed ❤️

<a href="https://github.com/byt3bl33d3r/OffensiveNim/graphs/contributors"> <img src="https://contrib.rocks/image?repo=byt3bl33d3r/OffensiveNim" /> </a>