GOing 4 A Run

Leo Pitt
Posts By SpecterOps Team Members
6 min readMar 18, 2020

--

Another Go Shellcode Runner

Art by clgtart

Introduction

After reading through BlackHat Go, I wanted a project that would further my familiarity with Go. I figured a shellcode runner would be a fun exercise with the added benefit of resulting in something I could potentially use operationally.

I had the following goals:

  • Shellcode Encryption (To increase the difficulty of reversing and for AV evasion)
  • Process Injection (Using CreateRemoteThread initially with other methods to be added later)
  • Block DLLs (To prevent hooking by some AV/EDRs)
  • Spoof Parent Process (To increase detection difficulty and for AV/EDR evasion)

The end result is Go4aRun. I am a complete n00b to Go and I am sure there are probably better ways to implement all of these goals. Still, I wanted to share this in case a portion of this is helpful to someone else. The rest of this post goes into some obstacles I faced while developing this tool as well as a quick tutorial.

Shellcode Encryption

Typically in shellcode runners, applying XOR to the shellcode is the standard method of obfuscating the shellcode. My attempts to implement XOR with a passphrase within GO lead to various issues. Instead, I used the AES cipher implementation from Nic Raboy. The added benefit with this implementation is the inclusion of a nonce. A nonce is an arbitrary number that can be used just once in a cryptographic communication. Since this keeps changing upon each encryption iteration, it increases evasion chances from static analysis on the shellcode. If the shellcode is flagged, simply rerunning the encryption would result in new encrypted shellcode without any changes to the underlying functionality of the shellcode or needing to change the passphrase.

Process Injection

For the process injection portion, I heavily leveraged the approach from the OffensiveGoLang and Sliver projects. Currently, Go4aRun is only utilizing the CreateRemoteThread method of process injection. This method mainly requires the following API calls:

  • OpenProcess (To obtain a process handle to the target process)
  • VirtualAllocEx (To allocate virtual memory in the target process)
  • WriteProcessMemory (To write our payload to the target process memory)
  • CreateRemoteThread (To execute the payload on the target process)

This CreateRemoteThread method is by far the most popular method for remote process injection. Due to this, it is fairly simple to detect the usage using the Sysmon Event ID 8: CreateRemoteThread. In the future I plan to add other methods, especially the less utilized QueueUserAPC method (Spoiler Alert!: I have) to increase evasion chances. However, in the current form, users may want to look into processes that normally use CreateRemoteThread for injection candidates as they are more likely to be excluded from alerts.

Block DLLs

The block dlls functionality has been in Cobaltstrike since last year. Although unlikely to block most EDRs, blocking some is better than none. So the main resource for this was actually a Hack The Planet stream in which they were going over GadgetToJscript and the implementation they developed incorporated block dlls to prevent 3rd party applications from hooking into the injected process. However, the effectiveness of this evasion method is entirely dependent on the EDR doing userspace hooks via DLL injection. Furthermore, some EDRs have had their DLLs signed by Microsoft (e.g. Crowdstrike Falcon) making this technique ineffective.

I attempted to utilize the Arbitrary Code Guard method as well but as noted by xpn, injecting something like a Cobalt Strike beacon will not currently work with this method.

Spoof Parent Process

To minimize flags for defenders and EDRs that look for abnormal parent child relationships, I wanted to implement parent process spoofing. Again, I leveraged the example from the Hack The Planet stream. The method used requires requires enumerating the running processes on the target, obtaining the Process Identifier (PID) for the intended process to spoof, feeding this PID to the OpenProcess API call, and using that API call as a parameter of the UpdateProcThreadAttribute API call to set it as the parent. Detection methods for this technique are described here.

Excerpt related to the Spoof Parent Method

Example usage:

Note: The following is based on the default parameters which I highly recommend changing.

Key variables to change are passphrase, parentName, programPath and flipping between using nonms vs onlystore.

Within the hideit.go file:

Within the Go4it.go file:

The next step after adjusting variables, is converting and encrypting the raw Position-Independent Code. Hideit.go takes the shellcode, encodes it, and then encrypts it using the passphrase set (D00mfist by default).

Running the obfuscation piece

The end result is saved into theSc variable which is ultimately saved into shelly.go. This is then moved to the appropriate directory under Go4aRun\pkg\shelly\. I tried to implement a method to automatically remove the shelly.go from the hide directory but ran into issues.

Shellcode placed into Sc variable within shelly.go

Next is building the binary. The ldflags (linker flags)s and w have the benefit of removing the DWARF, symbol table and debug info. Which takes away some useful information in reversing the binary. Additionally, these removals reduce the binary size.

Building the binary the without the symbol table, debug information and the DWARF table

We can further reduce the binary size using UPX. UPX is excellent at compressing the binary.

Using UPX to shrink the binary
Able to shrink to a little over 1MB

Utilizing Defender Check, no threats were found so we should not run into issues with our binary being flagged by Microsoft Defender.

Passed DefenderCheck

The following is an excerpt from Process Hacker. Our coolBeans.exe launched notepad.exe (8208) with the parent of explorer.exe (3304).

Notepad launched with explorer as the parent

The process information for notepad shows explorer as the parent. Also, we can see the Signatures restricted note specifying that only Microsoft signed binaries are allowed to hook to our process.

Can see the Signature restricted to Microsoft binaries only

In contrast using the onlystore variable, the Signatures restricted note specifies that only apps within the Microsoft store can hook into our process.

Can see the Signature restricted to Store only

Execution was successful and we obtained the beacon in CobaltStrike

mmm Bacon, I mean Beacon

Originally published at https://medium.com on March 18, 2020.

--

--