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:
Like very many threats these days, the malicious document contains a VBA Macro which executes when opened:
The Macro executes a base64
encoded PowerShell 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.

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).

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
.

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

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
:

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

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:

While on auto-pilot I just continued on like nothing had happened:

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.

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

There’s at least two questions that might come up while reading this:
-
- 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. - 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.
- Why not set a static sleep interval?
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:

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.