In this first of two blogs on this XWorm attack, we'll dive into the four initial files, how you can decode them, and an overview of the .NET loader involved in the attack.
Given the overall obfuscation of XWorm, our team decrypted each file to drill into what the attack entailed. As the most recent known version, XWorm 4 uses multiple techniques, with some similar to and others different from previous versions like those seen by Elastic and Sonicwall. Like in Elastic's case, this attack leveraged PowerShell scripts which result in deploying a .NET loader. A similarity shared across both previous examples was the attack's persistence as well.
Comparatively, however, this attack leveraged a multiple file (.ps1, .vbs, and .bat)-based approach, instead of the .pdfs, documents, and executables used in previous attacks. Here are each of those files, and how to decode them.
The only obfuscated part in this file is the 4th line with the character array. The great news is we can utilize native PowerShell to see what it was doing here.
A way to quickly test is to take the encoded command and run it.
.(-join[char[]](105,101,120))(-join [char[]](36)+[char](82)+[char](68)+…
NOTE: There are inherent dangers in actually doing this in practice, as running the encoded command will cause a command to run within PowerShell on your machine. Without proper set-up of a controlled environment, this could have started potential malware on the host, and caused all sorts of issues. Whenever reversing malware, be sure to only do so in a controlled environment.
With this knowledge, we can see that there seems to be two join groupings. Let's decode the first one:
$output = -join[char[]](105,101,120)
Output: iex
So, we found that the first join is iex (Invoke-Expression), which explains the command being run.
Here's what decoding the second one looks like:
2nd_output = -join [char[]](36)+[char](82)+[char](68)+[char](84)+…
Output: $RDTFYGUHIHUYFTDRTD = <##> New-ScheduledTaskAction <##> -Execute <##> $HH
$ERSTDYUGUTRDDRTFER = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 3)
Register-ScheduledTask -Action $RDTFYGUHIHUYFTDRTD -Trigger $ERSTDYUGUTRDDRTFER -TaskName $HHH
Here, we can see persistence established via a scheduled task. Additionally, there are <##> throughout the line. This seems to be a temporary placeholder, that will be built out with the functionality from the .vbs running.
When deobfuscating this, we need to break it down part by part. For the majority of this obfuscation, it utilizes string manipulation through StrReverse, Replace, and built-in methods (_&).
We can see that there are 3 different main parts to this.
Set NWIUFSBCVDAFKSERNUKPCG
Here we can see that they are assigning a variable.
Set LIDIRZZSKFPSQFRQCGUGAU
Assigning a 2nd variable
RROKBQOOGGKTOGNCTWAGAA = LIDIRZZSKFPSQFRQCGUGAU.Create(…)
A Create() method is utilized
With this knowledge, we can rerun existing string deobfuscation to see what could be contained in each variable and then we can remake the Create() method with the variables that were created. If you want to be a bit more cautious we will also show how you can reverse the string manually to rebuild it.
For the sake of time, we will focus on one example to show how it can be done for all string deobfuscation.
WRUYWHALQTWDRNENJGYIFC = "GLZIICQOWZCJFYOQQFJQRROIJZGBGQKWAVJPAXFCQZQB"
WRUYWHALQTWDRNENJGYIFC = Replace(WRUYWHALQTWDRNENJGYIFC, "GLZIICQOWZCJFYOQQFJQRR", "v"_ &"e")
Breaking apart this line, we can see the string being assigned to a variable that is then utilized in the Replace() function call.
Replace() takes in a string and replaces the contents of the 2nd argument("GLZIICQOWZCJFYOQQFJQRR") in the string with the 3rd argument("v"_&"e").
In Python, _& is handled as a concatenation so it will be treated as "ve," so we can break it down as such:
Utilizing these techniques, you can go through the entirety of the file and recreate the commands that are running.
This is much simpler, they create an alias for individual characters in the sEt command. This utilizes inline variables to create the command string to execute. They utilize a good amount of escape and built-in bash characters to further obfuscate.
You can, however, go through the command and map the characters over the strings to recreate the command that was run.
Example:
@c^M%VNINDQOQHNTLEJXHIWAWIX%.E"x"%GLZIICQOWZCJFYOQQFJQRR% /c
=%ZSANUYNDQPEPPJJGIGSLHA%oW%GLZIICQOWZCJFYOQQFJQRR%rS^h%GLZIICQOWZCJFYOQQFJQRR%lL"."%GLZIICQOWZCJFYOQQFJQRR%Xe
Output:
@cMd.Exe /c PoWerShelL.eXe
It's important to note here that the last line in this decoded example is where the .NET loader is deployed onto the endpoint, which is responsible for infecting the endpoint with XWorm.
The first primary component of this file are the 2 large buffers, both buffers have the same Replace() logic. We'll just cover the first one here.
$GLZIICQOWZCJFYOQQFJQRR = "+72-20+-+0-+3-37-250-+33-+0-+-234-+50-25+-0-+43-66-80-2+5-+99-200-80-+44-76-+49-+40-+53-+5+-+42-2+2-+74-208-20-+65-++0-53-+38-53-+68-202-+65-27-6+-+07-+7-246-234-++4-93-+0+-4-22-+30-+9-2+2-99-+34-+3+-248-+80-205-7-73-88-+8+-++8-224-+6+-+40-27-89-59-79-+44-+44-32-57…".Replace("-",",").Replace("+","1")
$OIJZGBGQKWAVJPAXFCQZQB = ($GLZIICQOWZCJFYOQQFJQRR -Join '')|&('I'+'EX')
$VNINDQOQHNTLEJXHIWAWIX = ($OIJZGBGQKWAVJPAXFCQZQB)
First, this will go through the string and replace all instances of - with , and all instances of + with 1 (I.e., 172,201,10,13,37,250,133…)
Afterward, we do a join followed by a |& IEX. This will perform an Invoke-Expression on the comma separated decimal list. This will run the join "" transforming the comma separated list into a byte decimal byte array.
The decryption here utilizes similar string manipulation techniques as the vbs please reference, the vbs String Manipulation section.
These are the key indicators found in the 2nd .NET assembly.
These are the settings being instantiated at the beginning of the program, this is where we can see a custom AES Decrypt function performing the decryption on the values.
This is the custom AES Decrypt function that was referenced, here we can see an MD5 as well as an Array copy to create an AES decrypt key.
This is the PowerShell Script we made to quickly decode the Mutex key utilized for the AES Decrypt key.
Based on our current understanding of the binary, these are the primary functionalities of the .NET loader
We’re continuing to reverse this malware and will focus on the functionalities and anything else we learn about what XWorm 4 entails in our next blog.