As earlier reported by FireEye, the actors behind a global intrusion campaign have managed to trojanise SolarWinds Orion business software updates in order to distribute malware.
The original FireEye write-up already provides a detailed description of this malware. Nevertheless, as the malicious update
SolarWinds-Core-v2019.4.5220-Hotfix5.mspwas still available for download for hours since the FireEye's post, it makes sense to have another look into the details of its operation.
The purpose of this write-up is to provide new information, not covered in the original write-up. Any overlaps with the original description provided by FireEye are not intentional.
For start, the malicious component
SolarWinds.Orion.Core.BusinessLayer.dllinside the MSP package is a non-obfuscated .NET assembly. It can easily be reconstructed with a .NET disassembler, such as ILSpy, and then fully reproduced in C# code, using Microsoft Visual Studio. Once reproduced, it can be debugged to better understand how it works.
In a nutshell, the malicious DLL is a backdoor. It is loaded into the address space of the legitimate SolarWinds Orion process
The critical strings inside the backdoor's class
SolarWinds.Orion.Core.BusinessLayer.OrionImprovementBusinessLayerare encoded with the DeflateStream Class of the .NET's System.IO.Compression library, coupled with the standard base64 encoder.
Once loaded, the malware checks if its assembly file was created earlier than 12, 13, or 14 days ago. The exact number of hours it checks is a random number from 288 to 336.
Next, it reads the application settings value
ReportWatcherRetry. This value keeps the reporting status, and may be set to one of the states:
- New (4)
- Truncate (3)
- Append (5)
When the malware runs the first time, its reporting status variable
ReportWatcherRetryis set to
The reporting status is an internal state that drives the logic. For example, if the reporting status is set to
Truncate, the malware will stop operating by first disabling its networking communications, and then disabling other security tools and antivirus products.
In order to stay silent, the malware periodically falls asleep for a random period of time that varies between 30 minutes and 2 hours.
At the start, the malware obtains the computer's domain name. If the domain name is empty, the malware quits.
It then generates a 8-byte User ID, which is derived from the system footprint. In particular, it is generated from MD5 hash of a string that consists from the 3 fields:
- the first or default operational (can transmit data packets) network interface's physical address
- computer's domain name
- UUID created by Windows during installation (machine's unique ID)
Even though it looks random, the User ID stays permanent as long as networking configuration and the Windows installation stay the same.
Domain Generation Algorithm
The malware relies on its own CryptoHelper class to generate a domain name. This class is instantiated from the 8-byte User ID and the computer's domain name, encoded with a substitution table: "
For example, if the original domain name is "domain", its encoded form will look like: "n2huov".
To generate a new domain, the malware first attempts to resolve domain name "api.solarwinds.com". If it fails to resolve it, it quits.
The first part of the newly generated domain name is a random string, produced from the 8-byte User ID, a random seed value, and a substitution table "
Because it is generated from a random seed value, the first part of the newly generated domain name is random.
For example, it may look like "fivu4vjamve5vfrt" or "k1sdhtslulgqoagy".
To produce the domain name, this string is then appended with the earlier encoded domain name (such as "n2huov") and a random string, selected from the following list:
For example, the final domain name may look like:
Next, the domain name is resolved to an IP address, or to a list of IP addresses. For example, it may resolve to
The resolved domain name will be returned into
IPAddressstructure that will contain an
AddressFamilyfield - a special field that specifies the addressing scheme.
If the host name returned in the
IPAddressstructure is different to the queried domain name, the returned host name will be used as a C2 host name for the backdoor.
Otherwise, the malware will check if the resolved IP address matches one of the patterns below, in order to return an 'address family':
|IP Address||Subnet Mask||'Address Family'|
For example, if the queried domain resolves to
184.108.40.206, it will match the entry in the table
220.127.116.11, for which the returned 'address family' will be
The returned 'address family' invokes an additional logic in the malware.
Disabling Security Tools and Antivirus Products
If the returned 'address family' is
Atm, the malware will enumerate all processes and for each process, it will check if its name matches one of the pre-defined hashes.
Next, it repeats this processed for services and for the drivers installed in the system. If a process name or a full path of an installed driver matches one of the pre-defined hashes, the malware will disable it.
For hashing, the malware relies on Fowler–Noll–Vo algorithm.
For example, the core process of Windows Defender is
MsMpEng.exe. The hash value of "MsMpEng" string is
5183687599225757871. This value is specifically enlisted the malware's source under a variable name
timeStamps = new ulong
The service name of Windows Defender is
windefend- the hash of this string (
917638920165491138) is also present in the malware body. As a result, the malicioius DLL will attempt to stop the Windows Defender service.
In order to disable various security tools and antivirus products, the malware first grants itself
SeTakeOwnershipPrivilegeprivileges, using the native
AdjustTokenPrivileges()API. With these privileges enabled, the malware takes ownership of the service registry keys it intends to manipulate.
The new owner of the keys is first attempted to be explicitly set to Administrator account. If such account is not present, the malware enumerates all user accounts, looking for a SID that represents the administrator account.
The malware uses Windows Management Instrumentation query "Select * From Win32_UserAccount" to obtain the list of all users. For each enumerated user, it makes sure the account is local and then, when it obtains its SID, it makes sure the SID begins with
S-1-5-and ends with
-500in order to locate the local administrator account.
Once such account is found, it is used as a new owner for the registry keys, responsible for manipulation of the services of various security tools and antivirus products. With the new ownership set, the malware then disables these services by setting their
registryKey2.SetValue("Start"), 4, RegistryValueKind.DWord);
If the returned 'address family' for the resolved domain name is
NetBios, as specified in the lookup table above, the malware will initialise its
HttpHelperclass, which implements an HTTP backdoor.
The backdoor commands are covered in the FireEye write-up, so let's check only a couple of commands to see what output they produce.
One of the backdoor commands is
CollectSystemDescription. As its name suggests, it collects system information. By running the code reconstructed from the malware, here is an actual example of the data collected by the backdoor and delivered to the attacker's C2 with a separate backdoor command
5. [E] Microsoft Windows NT 6.2.9200.0 6.2.9200.0 64
Description: Killer Wireless-n/a/ac 1535 Wireless Network Adapter #2
DNSServerSearchOrder: 18.104.22.168, 192.168.20.1
IPAddress: 192.168.20.30, fe80::8412:d7a8:57b9:5886
IPSubnet: 255.255.255.0, 64
DefaultIPGateway: 192.168.20.1, fe80::1af1:45ff:feec:a8eb
NOTE: Field #7 specifies the number of days (0) since the last system reboot.
GetProcessByDescriptioncommand will build a list of processes running on a system. This command accepts an optional argument, which is one of the custom process properties enlisted here.
If the optional argument is not specified, the backdoor builds a process list that looks like:
[ 1720] svchost
[ 8184] chrome
[ 4732] svchost
If the optional argument is specified, the backdoor builds a process list that includes the specified process property in addition to parent process ID, username and domain for the process owner.
For example, if the optional argument is specified as "ExecutablePath", the
GetProcessByDescriptioncommand may return a list similar to:
[ 3656] sihost.exe C:\WINDOWS\system32\sihost.exe 1720 DESKTOP-VL39FPO\UserName
[ 3824] svchost.exe C:\WINDOWS\system32\svchost.exe 992 DESKTOP-VL39FPO\UserName
[ 9428] chrome.exe C:\Program Files (x86)\Google\Chrome\Application\chrome.exe 4600 DESKTOP-VL39FPO\UserName
Other backdoor commands enable deployment of the 2nd stage malware. For example, the
WriteFilecommand will save the file:
using (FileStream fileStream = new FileStream(path, FileMode.Append, FileAccess.Write))
fileStream.Write(array, 0, array.Length);
The downloaded 2nd stage malware can then the executed with
using (Process process = new Process())
process.StartInfo = new ProcessStartInfo(fileName, arguments)
CreateNoWindow = false,
UseShellExecute = false
Alternatively, it can be configured to be executed with the system restart, using registry manipulation commands, such as
Article Link: https://blog.prevasio.com/2020/12/sunburst-backdoor-deeper-look-into.html