LOLBAS Threat Hunting

Late 2019, early 2020, I was given the opportunity to familiarize with SentinelOne and chose to conduct some ad hoc threat hunting. Since then, SentinelOne’s capabilities have significantly increased and Ursnif (more on that later) has evolved. Having finally received clearance to publish a sanitized version of my report in 2021, I felt that the process and findings were still relevant and could be useful to some. That shortened report follows.

Background

LOLBAS are binaries, scripts, and libraries that are typically found as a part of a normal Windows installation that can be used by an attacker for malicious purposes. It can be difficult to detect because it uses trusted, legitimate (and generally digitally signed) tools that are used by Windows. Protective measures like application whitelisting will often trust activity from these programs since they’re a normal part of the system’s operations, and a defender must comb through legitimate uses of each program in order to identify any malicious usage. Ultimately, if malicious activity is identified, it can be difficult to identify the attacker since they are using a Windows binary instead of their own malware.

One of the behaviors that was searched for was misuse of the Windows Management Instrumentation (WMI) Command line (WMIC) binary, wmic.exe. This maps to the MITRE ATT&CK Enterprise Technique T1218 (Signed Binary Proxy Execution) and to the MITRE Cyber Analytics Repository (CAR) Analytic CAR-2016-03-002 (Create Remote Process via WMIC).

Using the CAR or information from the LOLBAS Project , we know that one way to identify suspect WMIC behavior is by looking through command line logging for instances of wmic.exe that include the string “process call create.” For example:


wmic.exe process call create calc

In this instance, wmic.exe is being used to execute calc.exe.

The Hunt

Searching

Within SentinelOne, using the Visibility tool, we can identify similar activity with the following query:


ProcessName ContainsCIS "wmic.exe" AND ProcessCmd ContainsCIS "process call create"

This query will look for processes with a name that contains “wmic.exe” regardless of letter-case (it will match both “wMiC.exe” as well as “wmic.exe” and any other combination of cases) and a process command that contains the string “process call create” regardless of letter-case (CIS meaning “case insensitive”). With the time frame for our search set to “Last 3 Months” we get results like the following:

Identification

At this point, we don’t know whether we have identified malicious activity, but we know that our search for suspicious WMIC activity has returned results. Using Sentinel One Visibility, we can view the details of each of these processes by clicking on them.

Reviewing the “Command Line” details for the process, we can see here that wmic.exe is being utilized to create a new PowerShell process. That PowerShell process is executing a command via “iex” (abbreviation for “Invoke-Expression”).

That command is derived from the value of the registry key named

CfgSedui
that is saved at
HKCU:\Software\AppDataLow\Software\Microsoft\[UID]\
. That value is converted to a string and then converted from Bytes to ASCII text so that Invoke-Expression can execute it.

This is not a command that you would expect to see in a normally functioning Windows machine and is very likely malicious code being run on the device.  The next item to note is the frequency with which this code is running.

It is running each morning on an almost daily basis, with recurring gaps on Sundays and Wednesdays, suggesting that the malicious code is executing every time the user logs into their workstation. This hypothesis seems to be supported by the process tree, showing winlogon.exe as the great-grandparent to our process.

Persistence

There are a couple of different methods for executing instructions on a Windows device any time a user logs on. One is via scheduled tasks , and another is via registry run keys. Depending on agent version, SentinelOne can provide us with insight into registry key data and scheduled task execution. We know the time for each process, so we can run a new search for that time window to see what the device is doing.

Since there are only four in the relevant time window, it’s easy to review all the scheduled tasks to see if any look suspicious. None do. There is far more registry activity than scheduled task activity, so we will need to refine our search a bit. An example query can be seen below. Sadly, while the registry logging feature of SentinelOne is an exciting new addition, it doesn’t seem to quite capture all usage, particularly registry reads.

For example, we know that the suspicious wmic.exe command is reading the value of a registry key, however we see no such read reflected in the results above.

Understanding now that the registry activity data in SentinelOne, while great, is incomplete at best, we can next take advantage of an extremely powerful (if somewhat frightening) feature that now exists in SentinelOne: Remote Shell. If enabled via policy, and access is granted to the researcher as a user, then this will allow you to open an Administrative shell directly on the device in question. All commands and results are recorded during the session and made available in an encrypted archive for download later.

Using this shell, we can directly query the registry on the device with PowerShell. Knowing that the suspicious WMIC.exe process is running under the local user’s account, we will need to query their specific HKCU hive. Because our shell is an administrative shell and not running under the user in question, this means that we actually need to query

HKEY_USERS[SID]\
instead of HKEY_CURRENT_USER\[SID]. Starting with the common HKCU run locations, we quickly find a suspicious item in
HKEY_USERS\[SID]\Software\Microsoft\Windows\CurrentVersion\Run
.


PS C:\WINDOWS\TEMP> Get-ItemProperty-Path Registry::HKEY_USERS\[SID]\Software\Microsoft\Windows\CurrentVersion\Run.

...
Cameplua: C:\WINDOWS\system32\wbem\wmic.exe /output:clipboard process call create "powershell -w hidden iex([System.Text.Encoding]::ASCII.GetString((get-itemproperty 'HKCU:\Software\AppDataLow\Software\Microsoft\[UID]').CfgSedui))"
...

The value of

Cameplua
perfectly matches the command that we are seeing executed in SentinelOne. Given its location in the registry, it would execute any time the user with that SID logged in. We’ve found the source of our suspicious process.

Execution

Turning our attention next to the registry location mentioned in our process (

HKCU:\Software\AppDataLow\Software\Microsoft\[UID]
) we can query via our remote shell (once again using
HKEY_USERS\[SID]
).


PS C:\WINDOWS\TEMP> Get-ItemProperty-Path Registry::HKEY_USERS\[SID]\Software\AppDataLow\Software\Microsoft\[UID]

...
Cameplua: C:\WINDOWS\system32\wbem\wmic.exe /output:clipboard process call create "powershell -w hidden iex([System.Text.Encoding]::ASCII.GetString((get-itemproperty 'HKCU:\Software\AppDataLow\Software\Microsoft\[UID]').CfgSedui))"
...

Here we see the exact same value as in the Run registry. Looking at other keys in the same location, there are some other items of interest.


PS C:\WINDOWS\TEMP> Get-ItemProperty Registry::HKEY_USERS\[SID]\Software\AppDataLow\Software\Microsoft\[UID]\

...
Client32: {133, 184, 78, 156...}
Client64: {133, 184, 78, 156...}
CfgSedui: {36, 119, 100, 98...}
Cameplua: C:\WINDOWS\system32\wbem\wmic.exe
/output:clipboard process call
create "powershell -w hidden iex([Sys
tem.Text.Encoding]::ASCII.GetString((
get-itemproperty 'HKCU:\Software\AppD
ataLow\Software\Microsoft\[UID]
[UID-cont]').CfgSedui)
)"
Client: {89, 12, 0, 0...}
...

The value of the key

Cameplua
appears to be an array of decimal value. Taking a cue from the PowerShell command, if we convert those values to ASCII, then we see another command taking shape, the one that our suspicious wmic.exe process is executing. The array is extremely long and trying to print the entire thing proved to be too much for the remote shell to handle, so this is where our on-host investigation ended. Below is a sample of the ASCII text that is being executed. You can see that it is decoding Base64-encoded data provided via command-line argument and then converting to ASCII in a manner similar to the process that we have been investigating.


$wdbhynwlgv="hpxrkfbtfp";function twqmjhkpphn{$hcxf=[System.Convert]::FromBase64String($args[0]);[System.Text.Encoding]::ASCII.GetString($hcxf);};

Note, too, the registry keys

Client32
and
Client64
. It’s possible that these contain malicious code to be run on the system based on whether it is a 32-bit or 64-bit Windows installation. Considering the fact that the process tree in SentinelOne shows PowerShell spawning C# Compiler child processes, I suspect that the process is selecting the appropriate value and compiling and executing via
csc.exe
and
cvtres.exe
.

Findings

At this point, we’ve identified a Windows Registry Run key (T1547.001) using wmic.exe (T1218) to run PowerShell (T1059.001) which reads values from other registry keys (T1012) and executes code on the system. This is not behavior that you would find from benign programming but are clear signs of a fileless malware infection on the system. Googling various indicators leads to numerous analyses of Ursnif infections utilizing the same techniques, suggesting that we are dealing with the same on the client system. Assuming, for a moment, that this hypothesis is correct, that would suggest that the infection vector was via a malicious Microsoft Office document that was delivered via phishing email.

Creating WordPress Shortcodes

As I built this site, I found myself wanting to have more and more control over the content of these posts. As someone who started out building websites with notepad.exe, I’m used to having complete, and more importantly, up front control over content. When I learned that I couldn’t simply add php or js to the body of a post, it made some sense from a security standpoint, but I wanted to be able to add my own dynamic content without reverting to other people’s products by default.
I started with the desire to be able to insert today’s date. The end product is currently utilized in the site’s canary at the bottom of our privacy page. It will probably need to be replaced with a month by month update or something similar to appropriately, and legally function, but it was a good exercise for now.

I used two guides to figure out how to do this, located here and here

The first step was to create a child theme. I currently use WordPress’ Twenty Seventeen theme, but if I wanted to create my own functions without worrying about them being deleted on an update, a child is necessary. First we create a folder for the child theme, containing style.css and functions.php files.

mkdir /var/www/html/wp-content/themes/twentyseventeen-child
touch /var/www/html/wp-content/themes/twentyseventeen-child/style.css
touch /var/www/html/wp-content/themes/twentyseventeen-child/functions.php
chown -R www-data:www-data /var/www/html/wp-content/themes/twentyseventeen-child/

Note that the best practice is to name child themes with their parent’s name and -child appended to it. Next we edit style.css to add the requisite theme header to it:

/*
 Theme Name:    Twenty Seventeen Child
 Theme URI:     http://example.com/twenty-seventeen-child/
 Description:   Twenty Seventeen Child Theme
 Author:        CairnSec
 Author URI:    http://example.com
 Template:      twentyseventeen
 Version:       1.0.0
 License:       GNU General Public License v2 or later
 License URI:   http://www.gnu.org/licenses/gpl-2.0.html
 Tags:          test
 Text Domain:   twenty-seventeen-child
*/

Best practice for importing the parent’s style is now to do so in functions.php:

<?php
add_action( 'wp_enqueue_scripts', 'my_theme_enqueue_styles' );
function my_theme_enqueue_styles() {
        wp_enqueue_style( 'parent-style', get_template_directory_uri() . '/style.css' );
}
?>

If we look at themes on our wordpress site, we should now be able to see our child theme available. Activate it (and unfortunately fix several of the customization settings, not sure if there’s a way to carry those over…). We are now ready to write our shortcode. In functions.php, within our tags, create a function:

<?php
...
function getToday( $atts ) {
        return date(get_option('date_format'));
}
...
?>

This function will return today’s date by pulling ‘date_format’ from $atts, that is, it will use the site’s date format. Kind of neat. Last thing is to define the shortcode itself. We have the function that the shortcode will execute now. To define the shortcode:

<?
...
function getToday( $atts ) {
        return date(get_option('date_format'));
}
add_shortcode( 'today', 'getToday');
...
?>

In add_shortcode(), the first parameter is the shortcode itself. It is what we will type in our post in order to execute getToday(). The second parameter is just the name of the function, we’re tying the function to that name.

Now, we should be able to type [[today]] and get today’s date: [today]