Ursnif – A Polymorphic Delivery Mechanism Explained

The Ursnif trojan, which has been around in various forms for quite a few years now, remains extremely active and clearly still under active development. While there’s been plenty of technical analyses of the malware and its payloads, less has been written about the delivery mechanism itself. In this post, I take a look at the technical details behind Ursnif’s delivery mechanism and how that helps it to evade reputation-based AV scanners.

While reviewing an Ursnif sample recently I came across some puzzling behaviour. During my testing, I quickly discovered that the delivery method of the final payload was actually far more interesting than the malware itself.

Ursnif and The Malicious VBA Macro

It started straightforwardly enough with a suspicious document file found, as is often the case, in a phishing email:

7202707191fc9f702ca503aeed19332afb15b169d9c37c21767434501942695a

The document file itself is easy to detect (Spoiler: it installs ursnif malware!), as shown here in the SentinelOne management console:Image of SentinelOne Detection
Image of SentinelOne console

Like very many threats these days, the malicious document contains a VBA Macro which executes when opened:

Image of Ursnif malware VBA script

The Macro executes a base64 encoded PowerShell command:

Image of malicious power shell command

The decoded script is rather easy to understand. The $response variable calls for and holds the payload defined at $uri. After setting the path and file name, the script writes the payload to the “CommonApplicationData” folder with the file name “XqSDzMLM.exe”. The VBA script then opens a Windows shell and executes the program.

Image of malicious power shell script

Investigating the Ursnif C2 Server

When attempting to download the payload from the C2 server, I noticed that the DNS record had since been removed (no shock there).

Image of using dig to check domain
There are various tools that we can use to review the DNS history. The tool that I used was the free community version of RiskIQ. Your searches are limited, but it is always a great tool to have access to. One of the records I found gave us the IP address 46.29.167.73.

Image of Using RiskIQ to check DNS

When testing the IP with netcat, it looked as though the server was actually still responding to requests:

Image of Using netcat

It’s not everyday that I find a C2 server still completely active after the DNS records have been purged. Next, we’ll try to get information about the payload by retrieving the headers with curl:

Image of Using Curl to get payload headers

Jackpot. Now to fetch the payload with wget and see what kind of file we are looking at:

Image of Using wget to fetch the payload

This first request was, in full disclosure, a complete mistake. I mistakenly left off the -O switch from wget when downloading, which gave the payload a horrible name. Now, a normal person would simply rename the file, and this is perfectly acceptable. Fortunately, as it turned out, for some reason I just added the missing parameters and downloaded a new copy:

Image of downloading with wget

While on auto-pilot I just continued on like nothing had happened:
Image of ursnif initial shasums

And that’s when things just got weird.

One Hash, Then Another…

Two files downloaded from the same URL with two different hashes? Something is off. Maybe I messed something up, so I wanted to download another copy to make sure I wasn’t going crazy.

Image of ursnif three more shasums

Three hashes….Get ready there is much more crazy to come. I downloaded 10 more copies, this time putting an incrementing sleep command into the call:

$: for v in {0..10}; do wget -O .$v; shasum .*; sleep $v; done

Image of ursnif multiple shasums

There’s at least two questions that might come up while reading this:

    1. Why not set a static sleep interval?
      Force of habit; I wanted to increment because I would run this loop a few times in order to figure out the mutation frequency. If you start with an interval too high or low, you might miss a mutation, which leads to inaccurate results.
    2. Why would you even do this?
      For science! Often times when analysing malware, we see the mutations happen after they have infected the machine. While what I was seeing here is not unheard of it, is by no means what I would label as ‘common,’ which makes it interesting to investigate.

After doing this several times and downloading literally hundreds of copies, a pretty neat pattern came to light. The payload will actually mutate itself on the C2 server roughly every 60 seconds. It seems odd that a payload could mutate so fast without breaking itself, so I used a Hex editor to try and find out how much it was changing:

ursnif first hex dump
ursnif second hex dump
ursnif last hex dump

From the Hex output we can see the server will change the same four bytes of data every time it mutates the payload. The change is very minor but will be very effective against simplistic detection methods like reputation-based detection. By doing this, the attackers can create a nearly endless supply of ‘unknown’ versions of their malware. This can exponentially increase their chances of bypassing the victim’s protection and possibly allow the payload to execute without interruption.

Demo

Conclusion

In this post, we’ve explored how a malicious attachment uses a VBA script to download its payload from a C2 server. The delivery mechanism was somewhat unusual in that it changed the payload every 60 seconds by manipulating the same 4 bytes of data. In doing so, the attackers clearly hope to avoid detection by legacy AV security solutions that rely on reputation and which do not use Next-Gen behavioral detection.