Extracting Cobalt Strike from Windows Error Reporting

Introducing malware into a network can often cause problems. You’re adding an unknown software into an unknown environment and while there’s a lot of testing put into preventing application crashes, it cannot be guaranteed. Often during an investigations, we’ll see surges in application crashes following the actors presence due to abnormal behaviours on the network.

Windows Error Reporting is the native control for handling application crashes, leaving behind some handy logging and dumps that can help track an actors presence. This entry will go through how we can extract Cobalt Strike from a Windows Error Reporting process dump. This can be a great method of detecting abnormal behaviour after a process crashed.


What is Windows Error Reporting?

Windows Error Reporting (WER) acts as a debugging layer when an application crashes or hangs. Depending on the process specific settings, this can provide some useful troubleshooting information including:

  1. A report on the state of the application when it crashed,

  2. Process Dump,

  3. Digital Certificate and Application Combability references.

The report is the only guaranteed file created with Windows Error Reporting. These files get stored within two paths by default, one for more recent entries and one for more historic entries. They have the following paths:

  1. C:\ProgramData\Microsoft\Windows\WER\ReportQueue

  2. C:\ProgramData\Microsoft\Windows\WER\ReportArchive

The process dumps can be configured to allow for process specific setting. This can be particularly useful when you know an actor is reliably crashing a specific process, like a web shell crashing w3wp. You can access the process specific settings at:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\Windows Error Reporting\LocalDumps\

Within the LocalDumps key, you can configure:

  1. DumpCount: # of dumps to keep before rollover.

  2. DumpFolder: Where to output the process dumps.

  3. DumpType:

    0. Custom Dump

    1. Mini Dump

    2. Full Dump (Process)

Enhancing the data collected for that single process can give you an analytic edge on the actors actions, while also ensuring you don’t fill up the hard drive.


The Scenario

Note: I’ve replicated this scenario from a previous investigation. If you’d like a copy of the dump, let me know! :)

During an investigation, I had YARA flag some Cobalt Strike rules on an Windows Error Reporting dump for a native Windows process. This process was set to collect a full process dump, so we had about 400MB worth of memory to dig through.

Looking at the report.wer, there’s no interesting module loads. This makes sense though, if it is Cobalt Strike, it’s going to be reflectively loaded. Once we load the process into windbg, we can cross check the loaded modules in the report.wer against the loaded module addresses.


Windbg

The Error

First command you should run when investigating a crash dump is “!analyze -v”. This will give you some basic analytics around why the command crashed and can give a better understanding of what the actor was doing.

From the NTSTATUS Code 0xC0000005, we know that there was a access violation pointing to 0xffffffffffffffff.

Finding the YARA hit

We can do a search for the yara strings that hit on the process dump to get a region where Cobalt Strike might be loaded. Doing a search for three of the strings, we can find they’re all located within two similar memory regions.

We can do a search for MZ headers within that memory those MZ address ranges.

We can pull out the two headers that are just before our strings. Now that we have the address of the DLLs (address minus 0x4e), and surprise surprise, it doesn’t line up with any of our loaded modules.

When we look at the DLL address in memory panel and instantly see three of our main PE executable signs:

  1. MZ header

  2. This program cannot be run in DOS mode

  3. PE header

Accessing the PE Header

Reading the image DOS header, we can get the address of the PE header location from “e_lfanew”. Adding the offset to the address, we can confirm that we have the “PE” header using the display ascii command.

Parsing that address using the “_IMAGE_NT_HEADERS” shows the contents of the PE header.

The final entry in the above image, “Size of Image”, gives us a rough size of the DLL. If we add the size of image to the base address of the DLL, we can see expected end address for the DLL. Referring back to the YARA string addresses, we can confirm that those strings are located within the memory region for our DLL.

Now that we’ve confirmed that start and end address, we can export that memory region to get a copy of the CobaltStrike module.

Note: It’s worth noting that you won’t get a perfect copy of the DLL. Usually the SizeOfImage is inaccurate and will result in garbage being written to the end of the file because we’ve written too much.

Parsing the Config

We can now use a config parser to extract the Cobalt Strike config from the DLL. This gives us further indicators of compromise to continue searching across the network for.

From this, we can see that the default cobalt strike config is being used.


Wrap Up

  • Windows Error Reporting is a super valuable artifact. I’ve used it to detect everything from DLL injection to lateral movement to credential dumping.

  • If you know that an actors presence is purposely crashing a process, you can use that knowledge to gather more detailed process dumps.

Quick one this week, just getting back into blogging after a couple of conference talks. As always, hit me up on twitter with any questions.

Previous
Previous

A Begginers All Inclusive Guide to ETW

Next
Next

How would you analyse 200,000 executables?