GOing 4 A Hunt

Leo Pitt
9 min readMay 4, 2020

--

Hunting for my GO Shellcode Runner

Introduction

This post serves as a companion to my previous post on creating a shellcode runner in GO. No offensive post is complete without covering the defensive portion. This post highlights methods to aid in detecting each of the shellcode runner components. These detections are not all-encompassing but serve more to highlight the various indicators/artifacts that the shellcode runner creates. Rather than broad detections to detect multiple variations of a specific technique, these detections skew towards precise for the Go4ARun runner. Please leave a comment if there are any additional artifacts that you come across that Go4ARun creates.

Shellcode Encryption

Detecting shellcode is typically done using static analysis. It involves comparing flagged shellcode templates to a dictionary of known bad indicators. Although not a stable mechanism to rely on, flagging on shellcode is useful to establish a baseline and to catch defaults. There are various blogs on how the smallest change can throw off these brittle detections. Flagging on shellcode is a brittle indicator because the attacker controls it and thus can be easily changed. We are more interested in areas in which the attacker cannot modify to perform a specific technique.

Block DLLs

As a quick refresher, the block Dynamic-Link Libraries (DLLs) mechanism in the shellcode runner is an attempt to block third party DLLs from injecting into our target process. As stated in the previous post, the effectiveness of this evasion method is entirely dependent on the Endpoint Detection and Response (EDR) solution using userspace hooks via DLL injection.

A simple detection would be Application Programming Interface (API) monitoring for theUpdateProcThreadAttributeAPI call. API monitoring is a standard function of EDR solutions. Using API Monitor, we can see the API calls of RemoteThread.exe, which is the Go4ARun shellcode runner. We can see theUpdateProcThreadAttributeAPI call, which updates the attributes for process and thread creation. We can see that the PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY parameter used to update the mitigation policy.

UpdateProcThreadAttribute API with the Mitigation Policy set as a parameter.

Using PowerShell’s Get-ProcessMitigation cmdlet is another method of detection, as described by ired.team. This cmdlet can enumerate the mitigation settings of running processes. With some small modifications to their example, we can see which running processes have theMicrosoftSignedOnly or the AllowStoreSignedBinaries policies set. These policies allow for only Microsoft Signed binaries to inject into the process or only allow Microsoft Store Binaries to inject into our process, respectively.

RemoteThread.exe is executed, which used the default of Notepad as the process to apply the mitigation policy and inject our shellcode. Based on my testing, a few applications legitimately use these mitigation policies: Chrome, Slack, and Microsoft Edge (which includes browser_broker). After running the PowerShell commands, we can see that the Notepad process is uncharacteristically running with the MicrosoftSignedOnly mitigation policy set.

Notepad (5988) has the MicrosoftSignedOnly policy set (Block non-ms Field Header).

After changing the shellcode runner only to allow Microsoft Store Binaries, we can see that the Notepad process is running with the AllowStoreSignedBinaries mitigation policy set.

Notepad (5864) has the AllowStoreSignedBinaries policy set (Only MS Store Field Header).

Spoof Parent Process

Parent Process Spoofing is an evasion technique that abuses the Microsoft API calls to assign the parent of a new process explicitly. According to MITRE ATT&CK, it states that Event Tracing for Windows (ETW) is an excellent data source for detection purposes. ETW is the mechanism Windows uses to trace and log system events. ETW is preferred because Windows Security Logs, Sysmon, Task Manager, Process Explorer, and Process Hacker all show the spoofed parent process as the legitimate parent. I was able to get the essential information by leveraging PowerShell.

For my testing, Explorer is the target to become the spoofed parent of the Notepad process.

Target for Parent Spoofing is Explorer (4068)

The specific provider of interest is Microsoft-Windows-Kernel-Process. Leveraging the code from F-secure, I modified the PowerShell script to monitor for the ETW events.

As a baseline, I opened Notepad from File Explorer to view the ETW event of normal execution:

Normal Notepad execution with Explorer as the parent

The excerpt of the ETW event above shows that within normal execution, the ParentProcessID and the Event Header ProcessID both correlate to 4068, which is Explorer.

Next I launched RemoteThread.exe from File Explorer:

RemoteThread.exe (8628) launched by Explorer (4068)

The ETW event above indicates that Explorer (Event Header ProcessID 4068 and ParentProcessID 4068) starts RemoteThread.exe, which has a ProcessID of 8628. That’s legitimate, but the capturing of the actions that RemoteThread.exe performs is where ETW shines.

RemoteThread.exe starts Notepad and sets Explorer as the parent process:

Spoofed Parent which is RemoteThread.exe (8628)

The above ETW event shows that ETW captures the real parent process, which is Event HeaderProcessID 8628 (RemoteThread.exe), and captures the spoofed parent, which is ParentProcessID 4068 (Explorer). Unlike other tools, ETW accurately captures the accurate parent process in the Event Header.

Additionally, one could monitor the API call for CreateProcessW and UpdateProcThreadAttribute. To facilitate Parent Process Spoofing, CreateProcessW uses the EXTENDED_STARTUPINFO_PRESENT parameter andUpdateProcThreadAttribute uses thePROC_THREAD_ATTRIBUTE_PARENT_PROCESS parameter. Keep in mind that User Account Control (UAC) legitimately uses parent process spoofing to elevate privileges, so not all instances are automatically malicious.

API calls to UpdateProcThreadAttribute and CreateProcessW to facilitate Parent Process Spoofing

Process Injection

Process injection is the critical area to focus on when hunting for this shellcode runner as it facilities the actual execution of the shellcode. Go4ARun allows for remote process injection using CreateRemoteThread or QueueUserAPC.

Using API Monitor, we can see the API calls that facilitate process injection for both methods. In addition to the CreateRemoteThread and QueueUserAPC API calls, we can see the other API calls which allow for remote process injection in the shellcode runner: OpenProcess, VirtualAllocEx, WriteProcessMemory, and ResumeThread (for theQueueUserAPC method).

API Calls for the Shellcode Runner using CreateRemoteThread (RemoteThread.exe)
API Calls for the Shellcode Runner using QueueUserAPC (APC2.exe)

Another option is process monitoring with Sysmon. Implementation is pretty simple for CreateRemoteThread as Sysmon Event ID 8 covers this. However, QueueUserAPC is not as simple as there is not a directly related Sysmon event. Although, we can key on traits related to both process injection methods. A common characteristic of both injection methods is that the OpenProcess call is needed to access the process we intend to inject our shellcode. We can leverage Sysmon Event ID 10 as it maps to OpenProcess.

The shellcode runner utilizes the following access rights for the OpenProcess call:

PROCESS_CREATE_THREAD (0x0002)

PROCESS_QUERY_INFORMATION (0x0400)

Note: A handle that has the PROCESS_QUERY_INFORMATION access right automatically inherits PROCESS_QUERY_LIMITED_INFORMATION(0x1000)

PROCESS_VM_OPERATION (0x0008)

PROCESS_VM_WRITE (0x0020)

PROCESS_VM_READ(0x0010)

These rights equate to a value of (0x143A).

With this information, the following query in HELK was able to identify instances of my payloads which used CreateRemoteThread and QueueUserAPC.

(event_id : 10 AND process_granted_access : 0x143A) OR event_id : 8

Although crude, the query is effective at quickly identifying instances of the shellcode runner.

ProcessAccess Event Details (Sysmon Event ID 10) in HELK for Shellcode Runner using QueueUserAPC (APC2.exe)
ProcessAccess Event Details (Sysmon Event ID 10) in HELK for the Shellcode Runner using CreateRemoteThread (RemoteThread.exe)
CreateRemoteThread Event Details (Sysmon Event ID 8) in HELK for the Shellcode Runner using CreateRemoteThread (RemoteThread.exe)

Additional Artifacts

The following are items that I came across upon digging into the shellcode runner. These items do not fall into the core components of the runner but also may indicate malicious activity.

File Compression

There are multiple tools malware developers use to compress Portable Executables (PE)s. The tool I commonly use with Go4ARun is Ultimate Packer for Executables (UPX). UPX is an open-source executable packer. UPX allows us to not only decrease the size of the executable but scrambles and masks the executable making it more difficult for an analyst to figure out what is going on. UPX works by compressing the sections stored within the Section Table of the PE file. A strong indicator of UPX usage is the renaming of the header names (UPX0/UPX1/UPX2).

Using CFF explorer, we can see the section headers before using UPX.

Excerpt of Section Headers before using UPX

After using UPX, it renames the section headers to UPX0, UPX1, and UPX2.

Excerpt of Section Headers after using UPX

Background Activity Moderator (BAM)

BAM is a Windows service that controls the activity of background applications. This service exists in Windows 10 only after the Fall Creators update (version 1709). The shellcode runner sets a registry entry related to BAM upon execution.

ProcMon Excerpt showing the Registry Key Set Related to BAM

Looking into the registry, we can see that BAM contains a list of paths for executables, and the value of each of those is the time last executed in Windows Filetime (64bit little Endian) format in UTC.

BAM Registry Entry for RemoteThread.exe

File Properties Information

I noticed that the file information was blank after building the shellcode runner. An attacker can easily change this by modifying the resource file. For GO, the goversioninfo project allows for easy modification of the file properties.

Excerpt of Sysmon ProcessCreate Event ID 1 which shows blank metadata
Excerpt of Sysmon ProcessCreate Event ID 1 after leveraging goversioninfo which shows metadata

Memory

Looking into the memory of Notepad.exe, we note that there is a readable writeable, and executable (RWX) region of memory that is unsupported by a PE file from disk.

The region of memory with RWX and not mapped to an on-disk PE

Upon inspection, we can see indicators of our CobaltStrike shellcode.

Excerpt of shellcode in Notepad memory

Conclusion

This post serves as a dissection of the various components of the shellcode runner. By no means are these detections robust enough for enterprise implementation. However, it does highlight various artifacts that could serve as a starting point for creating robust detections or areas to investigate to determine malicious behavior.

References

--

--