The valid DNS requests generated by the malware fall into 2 groups:
The first type of DNS requests allows splitting long domain names into separate requests. These requests are generated by the malware's functions GetPreviousString() and GetCurrentString().
In general, the format of a DNS request that encodes a domain name may look like:
Let's try decoding the following 3 DNS requests:
Let's start from the 1st string in the list:
In this string, the first 15-character string is an encoded USER_ID: "olc62cocacn7u2q".
Once it is base-64 decoded, as explained in the previous post, it becomes a 9-byte byte array:
The first byte in this byte array is a XOR key: 0x86. Once applied to the 8 bytes that follow it, we get the 8-byte user ID - let's take a note and write it down, we will need it later:
Next, let's take the NUM part of the encoded domain: it's a character "2" located at the position #15 (starting from 0) of the encrypted domain.
In order to decode the NUM number, we have to take the first character of the encrypted domain, take the reminder of its division by 36, and subtract the NUM's position in the string "0123456789abcdefghijklmnopqrstuvwxyz":
The result is 1. That means the decrypted domain will be the 2nd part of a full domain name. The first part must have its NUM decoded as 0.
The COMPUTER_DOMAIN part of the encrypted domain is "2v02eu". Once decoded, using the previously explained method, the decoded computer domain name becomes "on.ca".
Let's decode the second passive DNS request from our list:
Just as before, the decoded 8-byte user ID becomes:
The NUM part of the encoded domain, located at the position #15 (starting from 0), is a character "6".
Let's decode it, by taking the first character ("r" = 114), take the reminder of its division by 36 (114 % 36 = 6), and subtracting the position of the character "6" in the "0123456789abcdefghijklmnopqrstuvwxyz", which is 6. The result is 0. That means the decrypted domain will be the 1st part of the full domain name.
The COMPUTER_DOMAIN part of the encrypted domain is "eoip02jovt6i2v0c". Once decoded, it becomes "city.kingston."
Next, we need to match 2 decrypted domains by the user ID, which is f9 a9 38 7f 7d 25 28 42 in both cases, and concatenate the first and the second parts of the domain. The result will be "city.kingston.on.ca".
Here comes the most interesting part. Lets try to decrypt the string #3 from our list of passive DNS requests:
The decoded user ID is not relevant, as the decoded NUM part is a number -29.
It's neither 0 nor 1, so what kind of domain name that is? If we ignore the NUM part and decode the domain name, using the old method, we will get "thx8xb", which does not look like a valid domain name.
Cases like that are not the noise, and are not some artificially encrypted artifacts that showed up among the DNS requests.
This is a different type of DNS requests. Instead of encoding local domain names, these types of requests contain data. They are generated by the malware's function GetNextStringEx().
The encryption method is different as well. Let's decrypt this request.
First, we can decode the encrypted domain, using the same base-64 method, as before.
The string will be decoded into 14 bytes:
Let's decode these bytes, starting from the 2nd byte, and using the first byte as a XOR key. We will get:
In this array, the bytes marked in yellow are an 8-byte User ID, encoded with a XOR key that is selected from 2 bytes marked in red.
Let's decode User ID:
The decoded byte array becomes:
The User ID part in marked in yellow. Does it look familiar? Indeed, it's the same User ID we've seen before, when we decoded "city.kingston.on.ca".
The next 3 bytes marked in red are: 25 98 20.
The first number 2 stands for the size of data that follows - this data is 00 03 (selected in green).
The number 0x59820, or 366,624 in decimal, is a timestamp. It's a number of 4-second periods of time since 1 January 2010.
To obtain the real time stamp, we need to multiple it by 15 to get minutes, then add those minutes to 1 January 2010:
For the number 0x59820, the time stamp becomes 16 July 2020 12:00:00 AM - that's the day when the DNS request was made.
The remaining 2 bytes, 00 03, encrypt the state of 8 security products, to indicate whether each one of them is running or whether it is stopped.
The 8 security products are:
2 states for 8 products require 2 * 8 = 16 bits = 2 bytes.
The 2 bytes 00 03 in binary form are:
Here, the least-significant bits 11 identify that the first product in the list, Windows Live OneCare / Windows Defender, is reported as 'running' (1) and as 'stopped' (1).
Now we know that apart from the local domain, the trojanised SolarWinds software running on the same compromised host on "city.kingston.on.ca" domain has also reported the status of the Windows Defender software.
As explained in the first part of our description, the malware is capable of stopping the services of security products, be manipulating registry service keys under Administrator account.
It's likely that the attackers are using DNS queries as a C2 channel to first understand what security products are present. Next, the same channel is used to instruct the malware to stop/deactivate these services, before the 2nd stage payload, TearDrop Backdoor, is deployed.
Armed with this knowledge, let's decode other passive DNS requests, printing the cases when the compromised host reports a running security software.