Another Go Shellcode Runner
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 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.
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).
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.
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.
We can further reduce the binary size using UPX. UPX is excellent at compressing the binary.
Utilizing Defender Check, no threats were found so we should not run into issues with our binary being flagged by Microsoft Defender.
The following is an excerpt from Process Hacker. Our coolBeans.exe
launched notepad.exe
(8208) with the parent of explorer.exe
(3304).
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.
In contrast using the onlystore
variable, the Signatures restricted
note specifies that only apps within the Microsoft store can hook into our process.
Execution was successful and we obtained the beacon in CobaltStrike
References:
- https://nostarch.com/blackhatgo
- www.thepolyglotdeveloper.com/2018/02/encrypt-decrypt-data-golang-application-crypto-packages/
- https://medium.com/syscall59/a-trinity-of-shellcode-aes-go-f6cec854f992
- https://ired.team/offensive-security/defense-evasion/preventing-3rd-party-dlls-from-injecting-into-your-processes
- https://hackplanet.io/aiovg_videos/building-with-azure-devops-gadget-to-jscript-2020-02-19/
- https://gist.github.com/rvrsh3ll/1e66f0f2c7103ff8709e5fd63ca346ac
- https://github.com/BishopFox/sliver
- https://github.com/bluesentinelsec/OffensiveGoLang