CyberDefenders— BlackEnergy Lab Walkthrough

Endpoint Forensic Investigation with Volatility 2

Drew Arpino
11 min readSep 22, 2024
Image Credit: https://cyberdefenders.org/blueteam-ctf-challenges/blackenergy/

Introduction:

Imagine this: an organization has suffered a cyber attack, and you’ve been handed a memory dump from an infected machine to investigate the incident. If this sounds like a thriller you want to be part of, you’ve stumbled on the right blog!

Welcome to my weekly walkthrough! This week, we’ll tackle the BlackEnergy Lab from CyberDefenders. Using the Volatility framework, we’ll dissect a memory dump of a device infected with a new variant of the BlackEnergy malware. We’re going to search for suspicious processes, hunt evidence of process injection, and uncover malicious DLLs to assess the scope and impact of this malware. Sounds like fun, right? Let’s get to it!

In the spirit of learning, I won’t be revealing any flags in this write-up, but I hope that this guide sets you on the right track — you got this! If you find this walkthrough is helpful in leveling up your skills or getting you through a tricky question, give it a clap! Your feedback lets me know that I helped you out on your security journey. Thanks for reading!

Challenge Link: https://cyberdefenders.org/blueteam-ctf-challenges/blackenergy/

Challenge Scenario:

A multinational corporation has been hit by a cyber attack that has led to the theft of sensitive data. The attack was carried out using a variant of the BlackEnergy v2 malware that has never been seen before. The company’s security team has acquired a memory dump of the infected machine, and they want you, as a soc analyst, to analyze the dump to understand the attack scope and impact.

Setup the REMnux Analysis Environment & Extract the challenge file:

Safety first! It’s always important when working with lab/challenge files from CyberDefenders (or any educational lab/challenge/range) to keep yourself protected by performing these tasks in a dedicated, isolated virtual machine environment. For example, I’m using REMnux for this challenge and walkthrough.

To keep this write-up focused I’m going to skip the step-by-step setup of REMnux. If you’d like to set up your own REMnux environment please follow the directions provided by REMnux directly. For reference, I opted for the virtual appliance method:

Okay! Now that we have our virtual environment created, updated, isolated, and snapshotted, we can extract the challenge file and start the investigation!

Question 1: Which volatility profile would be best for this machine?

Let’s start out by extracting the challenge file with the password included on the challenge page.

Since the question mentions Volatility, let’s take a quick detour to get a refresher of what it is. According to the Volatility Framework website:

The Volatility Framework was developed as an open source memory forensics tool written in Python.

Meaning we will use Volatility to analyze the contents of the .raw memory dump provided to us. Now, there are a couple of versions of Volatility: Volatility 2.6 (The original, not in active development) and the latest, Volatility 3 (in active development) which are a little different.

For the purposes of this challenge, one of the key differences is that Volatility 2 uses “profiles” to identify the operating system of the dump to accurately identify the locations of artifacts in memory. OS profiles like this aren’t used in Volatility 3.

Now what does this all mean? Well, Question 1 is asking about profile usage so going forward we know that the challenge will have us using Volatility 2 (which I am just going to call Volatility for the rest of the write-up).

With that background out of the way, let’s finally invoke Volatility and use the -h option to review the help file. This is a great idea to get an overview of what commands are available.

vol.py -h

We’re looking for a specific command that can help us determine which operating system profile we’ll use going forward. After reviewing the available options, we’ll find that imageinfo is the best choice.

vol.py -f CYBERDEF-567078-20230213-171333.raw imageinfo

After running the command against the memory dump, we’ll find the answer to Question 1 in the Suggested Profile(s) list.

Question 2: How many processes were running when the image was acquired?

Now that we know what profile to apply, we’ll need to analyze the memory dump and determine how many processes were running when the image was acquired. To do this, let’s review the Volatility help again to see if we can find a command that can display this data.

Let’s try the pslist command to display all the running processes and apply the profile we discovered in Question 1:

vol.py -f CYBERDEF-567078-20230213-171333.raw --profile=QUESTION-1-ANSWER pslist

Nice! The output shows the running processes so it should be a simple matter of counting them to answer Question 2, right? Well, almost. There is just one small detail to note. We are looking for running processes so the ones with a date/time in the Exit column or that have 0 threads are not actually running at the time of the capture, so we need to subtract them from the total.

Question 3: What is the process ID of cmd.exe?

Let’s continue analyzing the output generated with the pslist command. To answer Question 3, we’re going to focus on cmd.exe.

Once we locate the process name, we can check the process ID (PID) column to find the answer!

Question 4: What is the name of the most suspicious process?

To answer Question 4, we’ll continue examining the process list. Typically, some familiarity with normal Windows processes would be beneficial but fortunately for us, the suspicious process is obviously visible within the list.

Question 5: Which process shows the highest likelihood of code injection?

Okay, now we need to dig a little deeper with Volatility to locate the process with the highest likelihood of code injection.

First, let’s get some high-level background on what code injection is from MITRE ATT&CK (T1055) to better understand what we’re looking for exactly. According to MITRE, Process Injection is:

A method of executing arbitrary code in the address space of a separate live process. Running code in the context of another process may allow access to the process’s memory, system/network resources, and possibly elevated privileges. Execution via process injection may also evade detection from security products since the execution is masked under a legitimate process.

So, we’re looking for a process injected with malware running its memory space. Let’s see what Volatility commands are available to help us by referring to Volatility’s help file again and using grep to show us only the options with the word “inject” in them.

vol.py -h | grep "inject"

There are three options available! Let’s start with the malfind command at the top of the list. According to the Volatility command reference:

The malfind command helps find hidden or injected code/DLLs in user mode memory, based on characteristics such as VAD tag and page permissions.

Let’s run the command and see what we can find.

vol.py -f CYBERDEF-567078-20230213-171333.raw --profile=WinXPSP2x86 malfind

After going through the output, we’ll find a couple of processes but there is one that seems a little suspicious. Notice the ASCII string MZ and the corresponding hex (4D 5A)? This is the magic byte that indicates the file’s format. In this example it appears that a Windows executable is injected into this process — that’s probably not good.

But we don’t have a clear answer if this is malicious yet. Let’s do some additional research about malfind to understand if we are interpreting the results correctly.

Below is an excerpt from an excellent blog on Volatility forensics from security company Varonis:

As an incident responder when using ‘malfind’ if you see these values within a process then it is very likely you have identified a piece of malware that has injected itself into another process.

Okay, this gives us a bit more confidence that we’ve found the correct process to answer Question 5 but let’s perform one last check. We’re going to dump this process, check it against VirusTotal, and see if it is malicious or not. To dump the process, we can use the command below which specifies the PID (-p) of the malicious process and the output directory for the dump (-D).

vol.py -f CYBERDEF-567078-20230213-171333.raw --profile=WinXPSP2x86 malfind -p 880 -D <Path-to-Outputfile>

Now that we have a dump of the process, we can use the SHA256sum command to get the SHA256 file hash of the process.

sha256sum process.0x89aab590.0x980000.dmp

Finally, submit the hash to VirusTotal the number of detection hits confirms that the process was injected with malicious code.

Question 6: There is an odd file referenced in the recent process. Provide the full path of that file.

Now that we have dumped the process and confirmed that it is malicious, let’s pivot and do some static analysis on the dumped file. To find the answer to Question 6, we’ll use the strings command from the terminal to pull out text inside of the file that we can analyze.

strings process.0x89aab590.0x980000.dmp

After running the strings command, scroll through the output to look for any “odd” referenced files or paths.

Toward the end of the output, we’ll stumble across the highlighted path to a .sys file — this is the file we are looking for!

Question 7: What is the name of the injected dll file loaded from the recent process?

Now, let’s jump back into the Volatility help and see what options we have for analyzing DLL files. We can do the same method we did in Question 5 and grep dll” to see the available commands.

vol.py -h | grep -i "dll"

Let’s start with the dlllist option, focusing on the malicious process we found back in Question 5 to see if anything sticks out as suspicious.

vol.py -f CYBERDEF-567078-20230213-171333.raw --profile=WinXPSP2x86 dlllist -p 880 

After a quick review, nothing seems obviously suspicious with the dlllist output. Let’s refer back to the Volatility Command Reference and see if we can discover more about another DLL command — ldrmodules.

There are many ways to hide a DLL. One of the ways involves unlinking the DLL from one (or all) of the linked lists in the PEB. However, when this is done, there is still information contained within the VAD (Virtual Address Descriptor) which identifies the base address of the DLL and its full path on disk. To cross-reference this information (known as memory mapped files) with the 3 PEB lists, use the ldrmodules command.

So, using the ldrmodules command might help us discover a hidden DLL which has been unlinked from all the lists in the Process Environment Block (PEB) which contains information about loaded DLLS.

Let’s try it and filter on the malicious PID:

vol.py -f CYBERDEF-567078-20230213-171333.raw --profile=WinXPSP2x86 ldrmodules -p 880

One of these DLLs is not like the others and is pretty suspicious. Notice the highlighted DLL is not present in any of the three linked PEB lists — I think we found our answer!

Question 8: What is the base address of the injected dll?

Okay, we’ve made it to the last question! How can we find the base address of the injected DLL we just uncovered? We know from the last question that the dlllist command doesn’t list the DLL. We also know that ldrmodules does list an address, but it’s too long to fit the answer format. What to do, what to do?

Well, let’s fall back to the malfind output that we used back in Question 5. Remember that there was an Address for the suspicious process listed? Let’s try that one…

Hey, that worked! Now that we have uncovered the base address of the injected dll, let’s wrap up this investigation.

Conclusion:

Mission accomplished! With the help of Volatility, we successfully identified the suspicious processes, hunted for evidence of process injection, and uncovered malicious DLLs to assess the scope and impact of this malware. With the objectives completed, let’s close out this walkthrough of the BlackEnergy Lab challenge!

A big thank you to CyberDefenders for another engaging and challenging lab. This lab was a great example of the importance of memory dump analysis during DFIR cases and showcased some excellent scenarios for analyzing memory artifacts. It’s been a while since I’ve worked with Volatility hands-on, and it’s always a fun and insightful to practice with the tool. This time was no different, especially since I had no previous experience with Volatility 2 and have only worked with Volatility 3 in the past, so there was an added learning component for me too!

Please don’t forget that if you found this walkthrough helpful in leveling up your skills or getting you through a tricky question, give it a clap! Your feedback lets me know that I helped you out on your security journey. We’re in this together! Thanks for the support!

Until next week’s challenge — stay curious and be safe out there!

Tools & References:

REMnux: https://remnux.org/

Volatility Framework Website: https://volatilityfoundation.org/the-volatility-framework/

Volatility GitHub: https://github.com/volatilityfoundation/volatility

Volatility Wiki Command Reference: https://github.com/volatilityfoundation/volatility/wiki/Command-Reference

Volatility Wiki Command Reference — Mal: https://github.com/volatilityfoundation/volatility/wiki/Command-Reference-Mal

VirusTotal: https://www.virustotal.com/gui/file/8638ab1e5f9ba4cffc66400d36d47f7805733fae828a0cace9421d0bd83eaefa

MITRE ATT&CK — Process Injection (T1055): https://attack.mitre.org/techniques/T1055/

Varonis: https://www.varonis.com/blog/how-to-use-volatility

--

--