Using SystemFunction032 for shellcode decryption
🧐

Using SystemFunction032 for shellcode decryption

📅 [ Archival Date ]
Nov 10, 2022 7:13 PM
🏷️ [ Tags ]
WindowsShellcodeObf
✍️ [ Author ]
Fabian Mosch alias S3cur3Th1sSh1t

Some days ago I woke up in the middle of the night - thinking about the Advapi32.dll/SystemFunction032 function. Really? Yes. Strange, this InfoSec folks. This post will show my nightly idea and sample Code on how to weaponize it.

SystemFunction032??

I did not know about this function before digging into Sleep obfuscation techniques like Foliage or Ekko. Although Benjamin Delphi already wrote about it in 2013 and used it in Mimikatz.

So this function is able to encrypt/decrypt memory regions via RC4 encryption. As for example the ReactOS Code shows it takes a pointer to an RC4_Context structure as input as well as a pointer to the encryption key:

image

“Why the heck do you see something special in that?” you could ask. Well, at least I personally did not know about alternative functions for existing memory region encryption/decryption except for XOR operations. But as you can read in for example Kyle Avery’s blog about Avoiding Memory Scanners a simple XOR even with a longer key got in the meanwhile to detect for AV/EDR vendors.

Although RC4 is considered as insecure and even broken for years it provides a much better memory evasion for e.G. Shellcode to us than simple XOR. It would be even more OpSec save to use AES here instead. But one single Windows API is at least very easy to use.

The midnight idea

Typically if you want to execute Shellcode in a process you will need the following steps:

  1. Open a Handle to the Process
  2. Allocate Memory in that Process with RW/RX or RWX permissions
  3. Write the Shellcode into that region
  4. (Optional) change Permissions to RX from RW for execution
  5. Execute the Shellcode as Thread/APC/Callback/whatever

To avoid signature based detections we could encrypt our Shellcode and decrypt that on runtime before execution. For e.g. AES decryption the flow would typically look like this:

  1. Open a Handle to the Process
  2. Allocate Memory in that Process with RW/RX or RWX permissions
  3. Decrypt the Shellcode, so that we can write the cleartext value into memory
  4. Write the Shellcode into the allocated region
  5. (Optional) change Permissions to RX from RW for execution
  6. Execute the Shellcode as Thread/APC/Callback/whatever

In this case, the Shellcode itself could get detected when writing it into memory e.g. by userland hooks as we would need to pass a pointer of the cleartext Shellcode to WriteProcessMemory or NtWriteVirtualMemory.

The usage of XOR could avoid that, because we can even XOR decrypt the memory region after writing the encrypted value into memory. It would look like this:

  1. Open a Handle to the Process
  2. Allocate Memory in that Process with RW/RX or RWX permissions
  3. Write the Shellcode into the allocated region
  4. XOR decrypt the Shellcode memory region
  5. (Optional) change Permissions to RX from RW for execution
  6. Execute the Shellcode as Thread/APC/Callback/whatever

But XOR can easily be detected. So we don’t want to use that. You already got the idea?

As an alternative we could make use of SystemFunction032 to decrypt the Shellcode after writing it into memory. So let’s do that!

The PoC

First I had the idea of generating Shellcode and just RC4 encrypt it with OpenSSL. So my idea was to generate it as follows:

But later on - when debugging - it turned out, that SystemFunction032 somehow encrypts/decrypts different to OpenSSL/RC4. So we cannot do it like that.

09.11.2022: Update

an0n_r0 gave further information on how to do the encryption with OpenSSL. You can do it as follows:

We could also use the following Nim Code to get an encrypted Shellcode blob (Windows OS only):

09.11.2022: Update

snovvcrash also published a simple Python Script after this blog which simplifies the encryption with a Python Script:

To execute this, we could simply use the following Nim code:

At least Defender does not complain here:

image

By using that we can nearly ignore userland hooks because our cleartext Shellcode is never passed to any function (Only SystemFunction032 itself). Of course, all those vendors could detect us by hooking Advapi32/SystemFunction032 - I did ask this question into the InfoSec community regarding to Sleep obfuscation detection some time ago.

But:

  1. There seam to be some privacy reasons why vendors can’t easily hook it, because they would get too many sensitive informations out of legitimate Processes.
  2. There are many alternatives to SystemFunction032, just read the Benjamin Delphi article linked above or take a look at the ReactOS code.
  3. We could also unhook the function before using it.

At the moment at least vendors seam to not hook it. I personally guess this will change in the future.

Homework for the interested

Another idea was even better from my mind. By using PIC-Code we could also skip all other Win32 functions which were used in my PoC. Because when writing PIC-Code, all code is contained in the .text section, and this section typically has RX permissions by default, which is enough many times. So we would not need to change memory permissions and we don’t need to write the Shellcode to memory.

It would just be as short as follows:

  1. Call SystemFunction032 to decrypt the Shellcode
  2. Directly call it

Sample Code for PIC-Code can for example be found here. For the Nim-Fans, one library was released ~2 weeks ago which also enables us to relatively easy write PIC-Code called Bitmancer.

Is a program, that just calls SystemFunction032 potentially malicious? :-) Or one, that just calls any other encryption/decryption function?

Links & Resources