Extracting the Cobalt Strike Config from a TEARDROP Loader
This blog post will cover how to use dynamic analysis to extract the underlying Cobalt Strike config from a recent TEARDROP sample
Last updated
This blog post will cover how to use dynamic analysis to extract the underlying Cobalt Strike config from a recent TEARDROP sample
Last updated
During the analysis of the SolarWinds supply chain compromise in 2020, a second-stage payload was identified and dubbed TEARDROP. Analysis of the discovered samples showed that TEARDROP ultimately loaded a Cobalt Strike beacon into memory. A good overview of the SolarWinds supply chain attack and follow on compromise activity can be found here:
Despite wide discussion and coverage in security industry, actual samples of the TEARDROP malware were not initially made publicly accessible. However on 05-02-2021, the two TEARDROP samples referenced in the Symantec blog above were uploaded to VirusTotal.
For the remainder of this blog post we will analyse one of the uploaded TEARDROP samples with the goal of extracting the underlying Cobalt Strike config.
This blog post is not an exhaustive analysis of the TEARDROP loader and its behaviour, it focuses purely on extracting the Cobalt Strike beacon and the associated config information.
Loading the sample into PEStudio we can see that we're dealing with a 64bit DLL with a lot of DLL exports:
The high number of DLL exports makes it slightly more challenging to move onto dynamic analysis as we first need to identify which export we want to analyse. To keep this blog post digestible, we will skip this step for now and instead we can use the information provided in the Symantec report (as linked above) to give us the correct DLL export for the starting point of our analysis: Tk_CreateImageType
Now that we know we want to analyse the Tk_CreateImageType
export, we need to get to that location in our favourite debugging tool. This is a little more challenging to do with a DLL as we can't directly call the export using x64dbg, but fortunately it's still easy enough to achieve with the following steps:
Open rundll32.exe
in x64dbg
Configure x64dbg to automatically break on DLL entry
Configure the rundll32.exe command line arguments to call our DLL and desired export
Breakpoint on the entrypoint of our desired DLL export and run until we get to that location
First of all we're going to open rundll32.exe
in x64dbg (File -> Open -> C:\Windows\System32\rundll32.exe
) and then also configure x64dbg to automatically pause on every DLL entry point (Options -> Preferences -> DLL Entry):
Now we can change the command line arguments passed to rundll32.exe
so that when it's launched it will execute our DLL at the Tk_CreateImageType
export. To do this go to File -> Change Command Line:
After hitting "OK", and restarting the debugging process (Debug -> Restart), we can now allow execution to proceed knowing that x64dbg will automatically breakpoint at the entrypoint of every DLL, including our target DLL. Keep pressing F9 (or Debug -> Run) while keeping an eye on current DLL location listed in the bottom bar of x64ddb until we see that we've hit our target DLL (teardrop.dll in this case):
In the screenshot above we can see that we've successfully hit teardrop.dll
in x64dbg and specifically we are at the first TLS Callback of the DLL. Thread Local Storage (TLS) callbacks execute before the main entry point of PE files and have both legitimate and non-legitimate use-cases. Some malware samples have been known to leverage TLS Callbacks as a way to check if the process is being analysed before the main execution of the sample is reached:
For now we will move past the TLS callbacks and circle back later on if we need to dig deeper into the sample. Keep pressing F9 until we reach DLLMain
of teardrop.dll
:
Now that we're in the target DLL, all we need to do is breakpoint on the Tk_CreateImageType
export. To do this we can go to the Symbols
tab, select teardrop.dll
in the left pane and then right click on the correct export in the right pane and select Toggle Breakpoint
:
Finally we can once again allow debugging to continue (Debug -> Run) until the status bar in the bottom of the x64dbg window shows that we've reached the start of the Tk_CreateImageType
export:
At this point you may want to change the preferences of x64dbg so that it no longer breaks on every DLL entry, this will make debugging easier and we can easily jump back to the CreateImageType export now that we have a breakpoint set.
As mentioned at the start of this blog post, the main aim of the TEARDROP loader is to load a Cobalt Strike beacon into memory on the victim machine. Using this knowledge we can make an assumption that by breakpointing on memory related API calls we should hopefully be able to find the Cobalt Strike beacon being loaded into memory.
To start off this analysis route, we will set breakpoints on the following APIs:
VirtualAlloc - allocate memory regions in the current process
VirtualProtect - used to change the protection on a memory region
VirtualQuery - gather information about a memory region in the current process
VirtualFree - releases a memory region in the current process
If suspect that a sample may do some form of process injection, we may also want to set breakpoints on APIs such as VirtualAllocEx, OpenProcess, CreateRemoteThread, CreateProcessInternalW etc. However for this sample these breakpoints won't be necessary.
The easiest way to do this is to type bp <API>
in the command window towards the bottom of the x64dbg window:
Now that we have our breakpoints set, the initial plan is to follow the steps below:
Break on calls to VirtualAlloc
Track the allocated memory regions returned by the API call
Inspect these regions as execution continues to identify interesting content being loaded into memory
In its default configuration Cobalt Strike beacons are loaded into memory in the form of a PE file, so by tracking the contents of allocated memory regions we should hopefully be able to spot the Cobalt Strike PE file being loaded into memory prior to execution.
Allow the execution of the program to continue until we hit the first instance of VirtualAlloc
being called:
Inspecting the documentation for VirtualAlloc
shows us that the return value of a successful call is the "base address of the allocated region of pages". By clicking Debug -> Return to User Code
after the breakpoint on VirtualAlloc
we can allow the API call to complete and the base address of the new memory region should be now be stored in the RAX register. We can follow this memory region by right clicking on the RAX register and selecting "Follow in Dump":
After clicking on Follow in dump we can see the allocated memory region in the x64dbg dump window towards the bottom on the screen:
As we allow the execution of the program to continue we should see the contents of this memory region change, and hopefully we will see a PE file appear in this window relating to the Cobalt Strike beacon. If we hit subsequent VirtualAlloc
calls, we can follow the same process as above and track the regions in the different dump tabs.
After allowing the execution of the program to continue, tracking a number of allocated memory regions, and allowing execution to continue over a number of VirtualProtect
breakpoints, we can spot the start of a PE file in one of the memory regions:
Almost any time we see a PE file being loaded into memory during malware analysis, it's worth dumping it to disk and analysing it further. In this case we're hoping that this is our Cobalt Strike beacon, so to progress the analysis of this sample we can dump this region of memory to disk.
To do this we can do the following:
Right click on the desired memory region in the dump tab
Click "Follow In Memory Map"
In the new window that appears, right click on the highlighted memory region
Click "Dump Memory to File"
Now that we have the PE file on disk, the final step is to attempt to extract the Cobalt Strike config information so that we can identify IOCs and configuration information. Although we haven't confirmed that this PE file is definitely a Cobalt Strike beacon at this point, it's a safe bet when we take into account that the Symantec blog post reported that the sample will ultimately load a beacon into memory.
Fortunately it's very easy to check by using Sentinal One's Cobalt Strike config extractor:
Inspecting the parser code we can see that it looks for one of three byte patterns in order to identify the presence of a Cobalt Strike config. If any of the byte patterns are found, then the parser will attempt to decode and print the configuration information of the Cobalt Strike beacon. The byte patterns that the parser looks for are:
The first two patterns reflect the two different XOR keys used in version 3 (0x69) and version 4 (0x2e).
Running the parser over the PE file that we extracted from the TEARDROP sample confirms that the file is a Cobalt Strike beacon and that we can successfully extract the config: