Reversing the shad0w framework part 3
2020-07-08
In the time of me writing this post, the author of the shad0w framework added some more features and ways to inject its modules, and execute code. This is actually quite nice since the list with commands and modules was expanded, which in turn made this third part a lot more interesting to work on than two weeks ago.
In the previous part we looked at the way that the beacon receives its tasks, and automated the way we can read those tasks using x64dbg. In this part we will take this one step further by also looking at the actual modules being executed, and in the case of the Stdlib function even read out the commands.
Executing C2 commands
Before executing anything, the beacon checks the value of the task key. The following values and their procedures are described in the beacon.c
file (https://github.com/bats3c/shad0w/blob/e453ac319c8f4af8b47eabd3cebd3cf20f4dbdff/beacon/src/beacon.c#L85)
0x1000
-> Do nothing and sleep (1 second sleep by default);0x2000
-> Execute modules likehijack
;0x3000
-> Execute code by spawning a new process (svchost.exe by default);0x4000
-> stdlib -> there’s a couple predefined stdlibs (defined in: https://github.com/bats3c/shad0w/blob/e453ac319c8f4af8b47eabd3cebd3cf20f4dbdff/beacon/src/core.c#L558);0x5000
-> Inject a DLL in a running process;0x6000
-> Kill the beacon;
So how do we find these routines? The main
function in beacon.c
is a good starting point to at least know which hex values line up with the kind of commands are going to be executed. This will also play a role later in this research process. We can find this switch statement in the disassembly view by looking for some of the strings that are defined in the main
function of beacon.c
like the URI buffer format string (https://github.com/bats3c/shad0w/blob/846546da9af81450f6bfb1ea0a5bf042d83c767a/beacon/src/beacon.c#L67):
When we scroll down a little bit further in the disassembly view , we can observe the start of the while loop that is present in the main
function. Starting with the C2 callback call, this will store the received buffer in [RBP+1864]
:
After the beacon has communicated with the C2, and received some data, it will continue checking the OpCode
value:
This execution routine is important it will help us further down the road.
Case 0x2000 – Execute Modules
To test this module, we can execute the hijack
command in the C2 panel. For the purposes of this test I have spawned a new explorer.exe process with PID 4772, and executed:
hijack -p 4772 -f /root/shad0w/shellcode.bin
My shellcode.bin
is actually an empty file, but for the purposes of this test this doesn’t really matter. I’m going to take a little bit of the easy route by simply placing a breakpoint on the debug statement of the InjectCode
function (https://github.com/bats3c/shad0w/blob/e453ac319c8f4af8b47eabd3cebd3cf20f4dbdff/beacon/src/loader.c#L295):
For the insecure beacon this is a fairly straight forward code injection , it uses the following routine:
Get a handle on the process using
OpenProcess
;Allocate memory in this process with
VirtualAllocEx
, and write the code (contents ofshellcode.bin
) into the allocated memory;Find a thread in the process using
GetThread
and suspend this thread usingSuspendThread
;Get the current context of the thread that was suspended by using the handle from
GetThread
withGetThreadContext
;Set the address of the Instruction Pointer (RIP) to the address of the buffer (
shellcode.bin
);
Start executing the thread again with ResumeThread
;
The above routine can be found in the disassembly of x64dbg by breaking on the debug statement.
Case 0x3000 – SpawnExecuteCode
When the OpCode matches 0x3000
, the execution of user code routine is being followed . The whoami
command is one of the commands that has the 0x3000
OpCode. When the switch statement is executed , and the buffer is given as an argument to the SpawnExecuteCode
function it will still be a base64 blob which it received with the BeaconCallBackC2
function.
The SpawnCode
function (https://github.com/bats3c/shad0w/blob/e453ac319c8f4af8b47eabd3cebd3cf20f4dbdff/beacon/src/loader.c#L127) is part of the loader.c
file on Github which sort of displays what kind of routine this is going to be. The beacon uses this loader function to spawn a new svchost.exe process, and then inject the code that needs to be executed into this process.
In this SpawnCode
function we can see that a named pipe is used to read the stdout of the newly created process, as this is also one of the arguments that is used for the newly created thread (https://github.com/bats3c/shad0w/blob/e453ac319c8f4af8b47eabd3cebd3cf20f4dbdff/beacon/src/loader.c#L203).
We will dive into this to read out the results. One thing to note about this ReadFromPipe
function is that is using the ReadFile
API to read out the value of MAX_OUTPUT
bytes which has been set to 1000 as its default value, this means that this will run a couple times if a large output is given back (with Mimikatz for example).
Reading SpawnExecuteCode results
Getting result output from commands and/or code that is being run in another process can be quite tricky. You could pray that it ran successfully, but this won’t help you much if you want to actually use the information that is given back to you when you want those juicy hashes dumped by Mimikatz.
To get around this problem the author makes use of named pipes. I won’t go into what named pipes are, or how they work for that matter, all you need to know is that you can read them like you would with a file. The named pipe in this case is used to read out the buffer that is returned from the svchost.exe process which is spawned to execute the code, to read this buffer the ReadFile
API is used.
The ReadFromPipe
function can be spotted in the disassembly views of x64bg while in the SpawnExecuteCode
routine:
NOTE: I have placed comments next to each of the instructions to make it clear which parameters are used to call the CreateThread
API (https://github.com/bats3c/shad0w/blob/e453ac319c8f4af8b47eabd3cebd3cf20f4dbdff/beacon/src/loader.c#L203).
If we look at this function in the disassembly view we can match the arguments passed to the ReadFile
API call:
If we run the whoami
command in the C2 console while having a breakpoint set at the chBuf
parameter, follow the address RDX
is pointing to in memory, and run until the return of the ReadFile
API call, we’ll see the results of the executed module in the memory dump:
64 65 73 6B 74 6F 70 2D 62 67 64 74 34 36 72 5C desktop-bgdt46r\
6D 61 6E 64 79 00 00 00 00 00 00 00 00 00 00 00 mandy...........
Case 0x4000 – Stdlib
When executing a command that is part of the Stdlib
value in the Github code, we will observe indeed that it will jump to the Stdlib
call while debugging. The Stdlib
function is part of the core.c
file on Github (https://github.com/bats3c/shad0w/blob/e453ac319c8f4af8b47eabd3cebd3cf20f4dbdff/beacon/src/core.c#L572).
We can observe the following hex values being used for the different modules:
0x1000
-> listdirs0x2000
-> readfile0x3000
-> getdir0x4000
-> removefile0x5000
-> makedirectory0x6000
-> changedir0x7000
-> getpid
When looking at the Stdlib
execution routine in the disassembly view we can correlate this with the C++ code on the Github page:
I placed a comment behind the instruction of note; the RBP-14
address holds the OpCode (exec_id
) which is being checked in the following routine:
As an example I executed the pwd
directory which corresponds with 0x3000
, or getdir
, this command takes no arguments and is thus fairly plain. This command is described in the getdir.c
file on Github (https://github.com/bats3c/shad0w/blob/2e4232a3ab95130c5c1bb6dbbbc8ee268161c049/beacon/lib/stdlib/getdir.c) which uses Windows API calls to retrieve the current working directory , it then returns the output of this command in RAX
upon returning.
After executing either of the above routines in the switch statement, the execution will continue to set everything up for the call to the BeaconCallbackC2
routine:
The DO_CALLBACK
has hex value 0x4000
, this can be observed in the helper file on Github: https://github.com/bats3c/shad0w/blob/1e51e7b3585242cf7ccd84addc6eca2c84ce03cb/beacon/src/core.h#L11
Case 0x5000 – InjectExecuteDll
This module can be triggered when executing the migrate
command in the C2. For the purpose of this check I spawned a new explorer .exe process and executed the migrate -p 4772
command.
This routine can be found by looking for string references to:
"InjectDLL (%d) -> %d"
If we set a breakpoint right before the call to DEBUG
, we can observe the PID that was given as an argument in the C2 console:
When you run the beacon in insecure mode , the insecure method of process injection will be carried out;
Get a handle on the process which was chosen with
OpenProcess
Allocate process memory with
VirtualAllocEx
;Write the DLL into the process memory that was allocated with
VirtualAllocEx
, usingWriteProcessMemory
;Suspend the thread in the target process with
GetThread
andSuspendThread
;Store the current context of the thread in the target process with
GetThreadContext
, using the handle on the thread that was received withGetThread
;Write the thread context into a code cave using
VirtualAllocEx
andWriteProcessMemory
;Set up a new thread context;
Write the remote thread context to a code cave using
WriteProcessMemory
;Create
0x2000
bytes of stack;Write the updated thread context with
SetThreadContext
Resume the thread using
ResumeThread
;
The above routine can be found in the disassembly view when breaking on the debug string mentioned above.
Reading out the received commands, automagically
No blogpost would be complete without some sort of automation. The above information can be used to automate the reading of the received tasks, and in case of the Stdlib
function, even read out the received commands.
The following script, while not being perfect, illustrates the automated fashion to ‘spy’ on the beacon itself. This was a fun exercise for pushing me looking up x64dbg script commands, and overall tinkering;
And an example image of the beacon receiving the SpawnExecuteCode
OpCode:
Conclusion
In this part of the shad0w framework reverse engineering series we have looked at the way that the beacon executes its commands, and even dived into some of these routines.
It’s a fun exercise to reverse engineer open source projects and I definitely learned a lot while doing this. Having the source code at your disposal so you can check/verify some things when you get stuck really helps when you’re just starting out reverse engineering.
Last updated