Shellcode Fluctuation: advanced in-memory evasion technique
Shellcode Fluctuation PoC
A PoC implementation for another in-memory evasion technique that cyclically encrypts and decrypts shellcode’s contents to then make it fluctuate between RW
(or NoAccess
) and RX
memory protection. When our shellcode resides in RW
or NoAccess
memory pages, scanners such as Moneta
or pe-sieve
will be unable to track it down and dump it for further analysis.
Intro
After releasing ThreadStackSpoofer I’ve received a few questions about the following README’s point:
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)
Beforewards I was pretty sure the community already knows how to encrypt/decrypt their payloads and flip their memory protections to simply evade memory scanners looking for anomalous executable regions. Questions proven otherwise so I decided to release this unweaponized PoC to document yet another evasion strategy and offer sample implementation for the community to work with.
This PoC is a demonstration of a rather simple technique, already known to the offensive community (so I’m not bringing anything new here really) in the hope to disclose secrecy behind magic showed by some commercial frameworks that demonstrate their evasion capabilities targeting both aforementioned memory scanners.
Here’s a comparison when fluctuating to RW (another option is to fluctuate to PAGE_NOACCESS
– described below):
- Beacon not encrypted
- Beacon encrypted (fluctuating)
This implementation along with my ThreadStackSpoofer brings Offensive Security community sample implementations to catch up on the offering made by commercial C2 products, so that we can do no worse in our Red Team toolings. 💪
How does it work?
This program performs self-injection shellcode (roughly via classic VirtualAlloc
+ memcpy
+ CreateThread
). When shellcode runs (this implementation specifically targets Cobalt Strike Beacon implants) a Windows function will be hooked intercepting the moment when Beacon falls asleep kernel32!Sleep
. Whenever hooked MySleep
function gets invoked, it will localise its memory allocation boundaries, flip their protection to RW
and xor32
all the bytes are stored there. Having waited for an expected amount of time, when the shellcode gets back to our MySleep
handler, we’ll decrypt the shellcode’s data and flip protection back to RX
.
PAGE_READWRITE
works as follows
Fluctuation to - Read shellcode’s contents from file.
- Hook
kernel32!Sleep
pointing back to our callback. - Inject and launch shellcode via
VirtualAlloc
+memcpy
+CreateThread
. In contrary to what we had inThreadStackSpoofer
, here we’re not hooking anything in ntdll to launch our shellcode but rather jump to it from our own function. This attempts to avoid leaving simple IOCs in memory pointing at modified ntdll memory. - As soon as Beacon attempts to sleep, our
MySleep
callback gets invoked. - Beacon’s memory allocation gets encrypted and protection flipped to
RW
- We then unhook original
kernel32!Sleep
to avoid leaving simple IOC in memory pointing thatSleep
have been trampolined (in-line hooked). - A call to original
::Sleep
is made to let the Beacon’s sleep while waiting for further communication. - After Sleep is finished, we decrypt our shellcode’s data, flip it memory protections back to
RX
and then re-hookkernel32!Sleep
to ensure interception of subsequent sleep.
PAGE_NOACCESS
works as follows
Fluctuation to - Read shellcode’s contents from file.
- Hook
kernel32!Sleep
pointing back to our callback. - Inject and launch shellcode via
VirtualAlloc
+memcpy
+CreateThread
… - Initialize Vectored Exception Handler (VEH) to setup our own handler that will catch Access Violation exceptions.
- As soon as Beacon attempts to sleep, our
MySleep
callback gets invoked. - Beacon’s memory allocation gets encrypted and protection flipped to
PAGE_NOACCESS
- We then unhook original
kernel32!Sleep
to avoid leaving simple IOC in memory pointing thatSleep
have been trampolined (in-line hooked). - A call to original
::Sleep
is made to let the Beacon’s sleep while waiting for further communication. - After Sleep is finished, we re-hook
kernel32!Sleep
to ensure interception of subsequent sleep. - Shellcode then attempts to resume its execution which results in Access Violation being throwed since its pages are marked NoAccess.
- Our VEH Handler catches the exception, decrypts and flips memory protections back to
RX
and shellcode’s is resumed.
Install & Use
Author: Mariusz Banach / mgeeky, 21
<mb [at] binary-offensive.com>
(https://github.com/mgeeky)