Thread Stack Spoofing - PoC for an advanced In-Memory evasion technique allowing to better hide injected shellcode's memory allocation from scanners and analysts.

Thread Stack Spoofing PoC

A PoC implementation for an advanced in-memory evasion technique that spoofs Thread Call Stack. This technique allows to bypass thread-based memory examination rules and better hide shellcodes while in-process memory.

Intro

This is an example implementation for Thread Stack Spoofing technique aiming to evade Malware Analysts, AVs and EDRs looking for references to shellcode's frames in an examined thread's call stack. The idea is to walk back thread's call stack and overwrite return addresses in subsequent function frames thus masquerading allocations containing malware's code.

An implementation may differ, however the idea is roughly similar to what MDSec's Nighthawk C2 offers for its agents. Especially demonstrated in this video:

Nighthawk - Thread Stack Spoofing

How it works?

This program performs self-injection shellcode (roughly via classic VirtualAlloc + memcpy + CreateThread). Then when shellcode runs (this implementation specifically targets Cobalt Strike Beacon implants) a Windows function will be hooked intercepting moment when Beacon falls asleep kernel32!Sleep. Whenever hooked MySleep function gets invoked, it will spoof its own call stack leading to this MySleep function and begin sleeping. Having awaited for expected amount of time, the Thread's call stack will get restored assuring stable return and shellcode's execution resumption.

The rough algorithm is following:

  1. Read shellcode's contents from file.
  2. Acquire all the necessary function pointers from dbghelp.dll, call SymInitialize
  3. Hook kernel32!Sleep pointing back to our callback.
  4. Inject and launch shellcode via VirtualAlloc + memcpy + CreateThread. A slight twist here is that our thread starts from a legitimate ntdll!RltUserThreadStart+0x21 address to mimic other threads
  5. As soon as Beacon attempts to sleep, our MySleep callback gets invoked.
  6. Stack Spoofing begins.
  7. Firstly we walk call stack of our current thread, utilising ntdll!RtlCaptureContext and dbghelp!StackWalk64
  8. We save all of the stack frames that match our seems-to-be-beacon-frame criterias (such as return address points back to a memory being MEM_PRIVATE or Type = 0, or memory's protection flags are not R/RX/RWX)
  9. We terate over collected frames (gathered function frame pointers RBP/EBP - in frame.frameAddr) and overwrite on-stack return addresses with a fake ::CreateFileW address.
  10. Finally a call to ::SleepEx is made to let the Beacon's sleep while waiting for further communication.
  11. After Sleep is finished, we restore previously saved original function return addresses and execution is resumed.

Function return addresses are scattered all around the thread's stack memory area, pointed to by RBP/EBP register. In order to find them on the stack, we need to firstly collect frame pointers, then dereference them for overwriting:

	*(PULONG_PTR)(frameAddr + sizeof(void*)) = Fake_Return_Address;

This precise logic is provided by walkCallStack and spoofCallStack functions in main.cpp.

How do I use it?

Look at the code and its implementation, understand the concept and re-implement the concept within your own Shellcode Loaders that you utilise to deliver your Red Team engagements. This is an yet another technique for advanced in-memory evasion that increases your Teams' chances for not getting caught by Anti-Viruses, EDRs and Malware Analysts taking look at your implants.

While delivering your advanced shellcode loader, you might also want to implement:

  • Process Heap Encryption - take an inspiration from this blog post: Hook Heaps and Live Free - which can let you evade Beacon configuration extractos like BeaconEye
  • Change your Beacon's memory pages protection to RW (from RX/RWX) and encrypt their contents before sleeping (that could evade scanners such as Moneta or pe-sieve)
  • Clean any leftovers from Reflective Loader to avoid in-memory signatured detections
  • Unhook everything you might have hooked (such as AMSI, ETW, WLDP) before sleeping and then re-hook afterwards.

Demo

This is how a call stack may look like when it is NOT spoofed:

not-spoofed

This in turn, when thread stack spoofing is enabled:

spoofed

Above we can see a sequence of kernel32!CreateFileW being implanted as return addresses. That's merely an example proving that we can manipulate return addresses. To better enhance quality of this call stack, one could prepare a list of addresses and then use them while picking subsequent frames for overwriting.

For example, a following chain of addresses could be used:

KernelBase.dll!WaitForSingleObjectEx+0x8e
KernelBase.dll!WaitForSingleObject+0x52
kernel32!BaseThreadInitThunk+0x14
ntdll!RtlUserThreadStart+0x21

When thinking about AVs, EDRs and other automated scanners - we don't need to care about how much legitimate our thread's call stack look, since these scanners only care whether a frame points back to a SEC_IMAGE memory pages, meaning it was a legitimate DLL/EXE call (and whether these DLLs are trusted/signed themselves). Thus, we don't need to bother that much about these chain of CreateFileW frames.

Example run

Use case:

C:\> ThreadStackSpoofer.exe <shellcode> <spoof>

Where:

  • <shellcode> is a path to the shellcode file
  • <spoof> when 1 or true will enable thread stack spoofing and anything else disables it.

Example run that spoofs beacon's thread call stack:

C:\> ThreadStackSpoofer.exe beacon64.bin 1
[.] Reading shellcode bytes...
[.] Thread call stack will be spoofed.
[+] Stack spoofing initialized.
[.] Hooking kernel32!Sleep...
[.] Injecting shellcode...

WalkCallStack: Stack Trace:
        2.      calledFrom: 0x7ff7c8ba7f54 - stack: 0xdc5eaffbd0 - frame: 0xdc5eaffce0 - ret: 0x2550d3ebd51 - skip? 0
        3.      calledFrom: 0x2550d3ebd51 - stack: 0xdc5eaffcf0 - frame: 0xdc5eaffce8 - ret: 0x1388 - skip? 0
        4.      calledFrom: 0x    1388 - stack: 0xdc5eaffcf8 - frame: 0xdc5eaffcf0 - ret: 0x2550d1ff760 - skip? 0
        5.      calledFrom: 0x2550d1ff760 - stack: 0xdc5eaffd00 - frame: 0xdc5eaffcf8 - ret: 0x1b000100000004 - skip? 0
        6.      calledFrom: 0x1b000100000004 - stack: 0xdc5eaffd08 - frame: 0xdc5eaffd00 - ret: 0xd00017003a0001 - skip? 0
        7.      calledFrom: 0xd00017003a0001 - stack: 0xdc5eaffd10 - frame: 0xdc5eaffd08 - ret: 0x2550d5b7040 - skip? 0
        8.      calledFrom: 0x2550d5b7040 - stack: 0xdc5eaffd18 - frame: 0xdc5eaffd10 - ret: 0x2550d3ccd9f - skip? 0
        9.      calledFrom: 0x2550d3ccd9f - stack: 0xdc5eaffd20 - frame: 0xdc5eaffd18 - ret: 0x2550d3ccdd0 - skip? 0
                        Spoofed: 0x2550d3ebd51 -> 0x7ffeb7f74b60
                        Spoofed: 0x00001388 -> 0x7ffeb7f74b60
                        Spoofed: 0x2550d1ff760 -> 0x7ffeb7f74b60
                        Spoofed: 0x1b000100000004 -> 0x7ffeb7f74b60
                        Spoofed: 0xd00017003a0001 -> 0x7ffeb7f74b60
                        Spoofed: 0x2550d5b7040 -> 0x7ffeb7f74b60
                        Spoofed: 0x2550d3ccd9f -> 0x7ffeb7f74b60
                        Spoofed: 0x2550d3ccdd0 -> 0x7ffeb7f74b60

===> MySleep(5000)

[+] Shellcode is now running.

WalkCallStack: Stack Trace:
        2.      calledFrom: 0x7ff7c8ba7f84 - stack: 0xdc5eaffbd0 - frame: 0xdc5eaffce0 - ret: 0x7ffeb7f74b60 - skip? 1
        3.      calledFrom: 0x7ffeb7f74b60 - stack: 0xdc5eaffcf0 - frame: 0xdc5eaffce8 - ret: 0x7ffeb7f74b60 - skip? 1
        4.      calledFrom: 0x7ffeb7f74b60 - stack: 0xdc5eaffcf8 - frame: 0xdc5eaffcf0 - ret: 0x7ffeb7f74b60 - skip? 1
        5.      calledFrom: 0x7ffeb7f74b60 - stack: 0xdc5eaffd00 - frame: 0xdc5eaffcf8 - ret: 0x7ffeb7f74b60 - skip? 1
        6.      calledFrom: 0x7ffeb7f74b60 - stack: 0xdc5eaffd08 - frame: 0xdc5eaffd00 - ret: 0x7ffeb7f74b60 - skip? 1
        7.      calledFrom: 0x7ffeb7f74b60 - stack: 0xdc5eaffd10 - frame: 0xdc5eaffd08 - ret: 0x7ffeb7f74b60 - skip? 1
        8.      calledFrom: 0x7ffeb7f74b60 - stack: 0xdc5eaffd18 - frame: 0xdc5eaffd10 - ret: 0x7ffeb7f74b60 - skip? 1
        9.      calledFrom: 0x7ffeb7f74b60 - stack: 0xdc5eaffd20 - frame: 0xdc5eaffd18 - ret: 0x7ffeb7f74b60 - skip? 1
                        Restored: 0x7ffeb7f74b60 -> 0x2550d3ebd51
                        Restored: 0x7ffeb7f74b60 -> 0x1388
                        Restored: 0x7ffeb7f74b60 -> 0x2550d1ff760
                        Restored: 0x7ffeb7f74b60 -> 0x1b000100000004
                        Restored: 0x7ffeb7f74b60 -> 0xd00017003a0001
                        Restored: 0x7ffeb7f74b60 -> 0x2550d5b7040
                        Restored: 0x7ffeb7f74b60 -> 0x2550d3ccd9f
                        Restored: 0x7ffeb7f74b60 -> 0x2550d3ccdd0

Word of caution

If you plan on adding this functionality to your own shellcode loaders / toolings be sure to AVOID unhooking kernel32.dll. An attempt to unhook kernel32 will restore original Sleep functionality preventing our callback from being called. If our callback is not called, the thread will be unable to spoof its own call stack by itself.

If that's what you want to have, than you might need to run another, watchdog thread, making sure that the Beacons thread will get spoofed whenever it sleeps.

If you're using Cobalt Strike and a BOF unhook-bof by Raphael's Mudge, be sure to check out my Pull Request that adds optional parameter to the BOF specifying libraries that should not be unhooked.

This way you can maintain your hooks in kernel32:

beacon> unhook kernel32
[*] Running unhook.
    Will skip these modules: wmp.dll, kernel32.dll
[+] host called home, sent: 9475 bytes
[+] received output:
ntdll.dll            <.text>
Unhook is done.

Modified unhook-bof with option to ignore specified modules

Author

Mariusz Banach / mgeeky, 
<mb [at] binary-offensive.com>, '21
Owner
Mariusz B.
Wanna sip a sencha?
Mariusz B.
Similar Resources

Hide skip button in cutscenes in Max Payne 3

Hide skip button in cutscenes in Max Payne 3

MaxPayne3.FusionFix This is a small project intended to add ability to hide button in Max Payne 3. Additionally, added an option to increase the size

Sep 29, 2022

A program that allows you to hide certain windows when sharing your full screen

A program that allows you to hide certain windows when sharing your full screen

Invisiwind Invisiwind (short for Invisible Window) is an application that allows you to hide certain windows when sharing your full screen.

Nov 25, 2022

Hide SMBIOS/disk/NIC serials from EFI bootkit

Hide SMBIOS/disk/NIC serials from EFI bootkit

Rainbow Rainbow is a bootkit like HWID spoofer for Windows. It abuses several hooks in EFI runtime services and uses clever DKOM to hide hardware seri

Nov 22, 2022

Hide a process,port,self under Linux using the ld_preload

vbackdoor 中文 Hide a process,port,self under Linux using the LD_PRELOAD rootkit. compile the library git clone https://github.com/veo/vbackdoor.git cd

Nov 24, 2022

Exploit allowing you to read registry hives as non-admin on Windows 10 and 11

Exploit allowing you to read registry hives as non-admin on Windows 10 and 11

HiveNightmare aka SeriousSam, or now CVE-2021–36934. Exploit allowing you to read any registry hives as non-admin. What is this? An zero day exploit f

Nov 14, 2022

ESP32 + GitHub Actions + Husarnet. A boilerplate project for ESP32 allowing in-field firmware update using GitHub Actions workflow.

esp32-internet-ota ESP32 + GitHub Actions + Husarnet. A boilerplate project for ESP32 allowing in-field firmware update using GitHub Actions workflow.

Sep 22, 2022

A set of tools allowing JUCE 6.1 + Cmake to build a CLAP

JUCE6/CMake Clap Support This is a set of code which, combined with a JUCE6/CMake project, allows you to build a (buggy, feature incomplete, work in p

Feb 15, 2022

Turn your ESP32 into a easy to use micro web-server allowing to interact with any GPIO by simple http(s) calls.

WebhooksTriggeredESP32WiFi Turn your ESP32 into an easy to use and manage wireless micro web-server allowing it to process reliably and asynchronouly

Nov 24, 2022

Beacon Object File allowing creation of Beacons in different sessions.

Beacon Object File allowing creation of Beacons in different sessions.

JumpSession_BOF This is a Beacon Object File allowing creation of Beacons in different sessions. Must be Elevated. This BOF was created on the heels o

Nov 18, 2022
Comments
  • mingw compile error

    mingw compile error

    Hi. I apologize very much, but I've been looking for an answer for the second day, but I haven't found it. I cannot compile on linux, using mingw (clang). Tell me in which direction to dig, if not difficult? Sorry for the stupid question)))

    main.cpp:37:5: error: no matching function for call to 'fastTrampoline'
        fastTrampoline(false, (BYTE*)::Sleep, &MySleep, &buffers);
        ^~~~~~~~~~~~~~
    ./header.h:70:6: note: candidate function not viable: no known conversion from 'void (*)(DWORD)' (aka 'void (*)(unsigned long)') to 'LPVOID' (aka 'void *') for 3rd argument
    bool fastTrampoline(bool installHook, BYTE* addressToHook, LPVOID jumpAddress, HookTrampolineBuffers* buffers = NULL);
    

    try with -fpermissive and -fno-permissive, trying to change bool to BOOL, void to VOID and many other things, which i embarrassed to name((( Thx

An advanced in-memory evasion technique fluctuating shellcode's memory protection between RW/NoAccess & RX and then encrypting/decrypting its contents
An advanced in-memory evasion technique fluctuating shellcode's memory protection between RW/NoAccess & RX and then encrypting/decrypting its contents

Shellcode Fluctuation PoC A PoC implementation for an another in-memory evasion technique that cyclically encrypts and decrypts shellcode's contents t

Nov 26, 2022
Cobalt Strike User-Defined Reflective Loader written in Assembly & C for advanced evasion capabilities.
Cobalt Strike User-Defined Reflective Loader written in Assembly & C for advanced evasion capabilities.

Cobalt Strike User-Defined Reflective Loader Cobalt Strike User-Defined Reflective Loader written in Assembly & C for advanced evasion capabilities. B

Nov 23, 2022
BokuLoader - Cobalt Strike User-Defined Reflective Loader written in Assembly & C for advanced evasion capabilities.
BokuLoader - Cobalt Strike User-Defined Reflective Loader written in Assembly & C for advanced evasion capabilities.

BokuLoader - Cobalt Strike Reflective Loader Cobalt Strike User-Defined Reflective Loader written in Assembly & C for advanced evasion capabilities. B

Nov 26, 2022
EarlyBird process hollowing technique (BOF) - Spawns a process in a suspended state, inject shellcode, hijack main thread with APC, and execute shellcode
EarlyBird process hollowing technique (BOF) - Spawns a process in a suspended state, inject shellcode, hijack main thread with APC, and execute shellcode

HOLLOW - Cobalt Strike BOF Authors: Bobby Cooke (@0xBoku) Justin Hamilton (@JTHam0) Octavio Paguaga (@OakTree__) Matt Kingstone (@n00bRage) Beacon Obj

Nov 12, 2022
FiveM Cheat with KEKHACK. Injected with simple injector in c++.
FiveM Cheat with KEKHACK. Injected with simple injector in c++.

FiveM Cheat with TriggersEvent [KEKHACK] This is the ultimate great source code for building the best cheat FiveM. I'm not going to tell you how to cr

Nov 12, 2022
Research tool able to detect and mitigate evasion techniques used by malware in-the-wild

JuanLesPIN IntelPin tool to detect and mitigate Windows malware evasion techniques. This tool is a prototype developed for a research project whose pa

May 20, 2022
C Program to input a string and adjust memory allocation according to the length of the string.

C-String C Program to input a string and adjust memory allocation according to the length of the string. With the help of this program, we have replic

Jan 20, 2022
A simple PoC to demonstrate that is possible to write Non writable memory and execute Non executable memory on Windows

WindowsPermsPoC A simple PoC to demonstrate that is possible to write Non writable memory and execute Non executable memory on Windows You can build i

Jul 21, 2022
Inject dll to explorer.exe and hide file from process.

Hide-FS Inject dll to explorer.exe and hide file from process. Requierments: Microsoft Detours Library - https://github.com/microsoft/Detours Compile:

Nov 9, 2022