By: Igor Lahav
SUNBURST is a massive, fifth-generation cyber attack, waged against US government agencies and technology companies. The attack led to the compromise of systems in over 40 government agencies, including the National Nuclear Security Administration (NNSA), the US agency responsible for nuclear weapons. Targets in other countries, including Canada, Belgium, Britain, and Israel, were also hit.
SUNBURST is a supply chain attack that targets large organizations indirectly, by breaching their direct suppliers. Attackers leveraged SUNBURST to breach US software company SolarWinds. SolarWinds provides technology to manage and protect computer networks.
The attacker managed to hide a Trojan in a software update of the SolarWinds Orion software, and pushed this update to 18,000 customers, including almost all Fortune 500 companies, the aforementioned government agencies, and government contractors including Lockheed Martin. The attack was only discovered in December, 2020, eight months after the original breach.
In this article, you will learn:
The SUNBURST attack uses the following high-level process:
The SUNBURST backdoor is not yet fully understood. Spanning almost 3500 lines of code, “obfuscated” with casual naming, trying to evade shallow review, it has many subtleties yet to uncover.
The Cynet research team attempted to gain a better understanding of the command-and-control communication channel, its various stages, and conditions required for execution.
Our findings explain many of the observations seen so far regarding the SUNBURST backdoor which was implanted in the Orion attack. The main goal of this investigation is to find infected beaconing machines. We will focus mainly on anything that is passed on the wire, while touching upon a few of the evasion techniques employed by the SUNBURST backdoor.
The backdoor begins its execution in the legitimate SolarWinds.Orion.Core.BusinessLayer.BackgroundInventory.InventoryManager.RefreshInternal function.
Cleverly masqueraded as OrionImprovementBusinessLayer this function call does not draw any attention at first glance.
Furthermore, as it runs, it checks first if it is executed as part of the legitimate “solarwinds.businesslayerhost” process. Following by staying dormant between 12 to 14 days, after first arriving or an update. Afterwards it confirms it is the only instance of the backdoor currently running on the machine using named pipe existence as a synchronization mechanism.
Diving deeper to the communication of the backdoor, we make a distinction between 3 stages in the communication:
The main function of this stage is OrionImprovementBusinessLayer.DnsHelper.CheckServerConnection. The function receives “api.solarwinds.com” as an input.
All classification of IP is done inside OrionImprovementBusinessLayer.IPAddressesHelper.GetAddressFamily and the most detailed classification is based on a list of ranges called “nList”. The actual logic of this stage can be summarized with the following diagram:
Figure 1: Actual logic behind of stage 0
This logic allows it to stop execution and evade detection on many sandboxes and hostile environments where there is some sort of a “catch-all” domain resolver.
The code for this stage resides in the OrionImprovementBusinessLayer.Update function. While we consider the call to UpdateNotification to be part of Stage 0, all the following code, up to the call to HttpHelper.Initialize,is in Stage 1.
In the first part of this stage, a hostname is generated using one of the following 4 functions:
At the end of this part, hostName will hold the FQDN to contact and resolve. No matter which method is chosen, the subdomain will be appended with one of the following 4 suffixes generated from the GetStatus function:
addressFamilyEx, in turn, will hold the resolved IP’s classification mostly based on the mentioned “nList” of ranges.
In the second part of this stage, actions will be taken according to the classification of returned IP for this subdomain.
Any IP classification besides AddressFamilyEx.NetBios will ultimately cause failure to move to the next stage and a local config ReportWatcherRetry to be updated, but only if it were set beforehand to any value between 3 and 5.
A classification of AddressFamilyEx.Atm (anything that would have caused stage 0 to fail – meaning IP is a loopback device or in the local network or multicast IP) will cause the backdoor to call the OrionImprovementBusinessLayer.ProcessTracker.SetAutomaticMode function which will try to turn back on services in the OrionImprovementBusinessLayer.svcList list, which were previously disabled by the backdoor in OrionImprovementBusinessLayer.ProcessTracker.SetManualMode. These attempts are to shut down software which might be interfering with clear communication with the C2 DNS server. A list of products attempted to be manipulated can be found in Appendix A.
Decoded nList is shown below for reference:
To move to Stage 2 (HTTPS communication channel) we need 2 conditions:
Classification of AddressFamilyEx.NetBios is given to the following ranges:
Furthermore, the last 2 bytes of the IP resolved will have implications on the communication structure and will be discussed at the next stage.
Upon closer inspection of public partial list of passive DNS resolution for subdomains of *.appsync-api.*.avsvmcloud.com among 1460 subdomain, we found only 1 resolution that would truly activate the next stage of the backdoor. This is a testament to the pinpoint precision and OPSEC which the malicious actor was practicing.
After getting through all the conditions of Stage 0 and Stage 1, we finally arrive to the last stage, Stage 2. This stage starts with the execution of OrionImprovementBusinessLayer.HttpHelper.Initialize function. Here we start to work with a Job-related state machine, in a loop.
Each round in the loop begins with some random delay (IsSynchronized). Then, if a minute passed since last time, some defense evasion checks are implemented (TrackEvent and subsequent ProcessTracker.TrackProcesses). Any intimidating process (from assemblyTimeStamps list or svcList[*].timeStamps lists) will cause this stage to abort and exit.
CreateUploadRequest is responsible for delivering results and errors of previous execution, as well as fetching the next command to execute.
ParseServiceResponse is responsible for parsing the received command from CreateUploadRequest to a Job and arguments.
Finally, ExecuteEngine executes received commands with arguments and prepares any errors and results to be sent back later.
The analysis of this section is based of GetBaseUriImpl as well as relevant contextual information. The URL of the 2nd Stage is largely dependent on the resolved IP of the subdomain at Stage 1. As a rule, the backdoor tries to make these URLs unique, but will give up eventually. Although HTTPS URLs are used, any certificate errors are discarded and connection continues as usual. The URL begins with https://<cname>/ and afterwards there are 3 distinct cases (“pki”, “fonts” and “swip”):
swip/Upload.ashx – last command had big output ( >10,000 bytes after compression )
swip/Events – last command had small output ( <= 10,000 bytes after compression )
swip/upd/ – see options in figure below.
Figure 2: URL Structure for “swip” case, percentage represent probability of each part to appear in the final URL.
Figure 3: URL structure for “fonts” case, no matter if response exists or not.
Figure 4: URL structure for “pki” case, no matter if response exists or not.
If there is a result (“response”) to be sent back from previous command, it will be concatenated with the error (“err”) and the generated GUID (“customerId”). Afterwards it is compressed and XORed with the checksum. If the response is short, it is further encoded as a JSON object.
Either way, regarding the HTTP method, when there is a result (inData in CreateUploadRequestImpl), a POST method will be used, otherwise a GET method will be used.
Figure 5: First transformation to the result of previous command
Figure 6: Model of result of last command encoded as JSON object
The analysis in this part is based on ParseServiceResponse function. First of all, to extract anything meaningful 200 OK status code for the HTTP response required. Parsing of the HTTP response to the above-described HTTP request depends on the case we are working in, which in turn depends on the last number in the IP returned for the subdomain (Stage 1).
If the response is shorter than 4 bytes, no command is attempted to be recovered. For the first part of the parsing (“body”) can be as simple as skipping 48 bytes (in the “fonts” case) or 12 bytes (in the “pki” case). In the remaining “swip” case a more elaborate scheme employed:
After these steps, for all cases the following steps follow (which is almost the opposite of how the previous’ command result was encoded):
Figure 7: Transformation of incoming command
The rest of the command parsing is left as an exercise to the reader.
The analysis in this part is based on the ExecuteEngine function. Ultimately the back supported the following command:
We have covered many aspects of the SUNBURST backdoor, such as defense evasion mechanisms, but most notably the various stages the backdoor communicates and tries to blend in.
Future work can be directed towards figuring out all the different subdomain encoding schemes, which in turn will hopefully allow to decode many of the C2 subdomains. We hope the information provided will be helpful to the Cyber Defense Community in their efforts with identifying and remediating any active beacons of this SUNBURST backdoor, from Cozy Bear actors, or whomever it may be.
The SolarWinds breach still poses a critical threat. To ensure the security of IT environments, organizations need to identify and block all potential points of exposure. Detecting all relevant vulnerabilities can be complex, especially in big IT environments. However, there are several techniques that can help improve your security posture.
Here are five security measures that can help you detect the SUNBURST backdoor, as well as subsequent activities and other complex threats.
Rest assured: Cynet 360 customers are fully protected against any attempts of abusing the SUNBURST backdoor implanted in the Orion attack. Customers who utilize the SolarWinds Orion software have been notified by our CyOps team.
Cynet XDR has released relevant detections for the compromised software and the
malicious backdoor, based on multiple detection vectors. We will continue to add additional
IOCs as new ones emerge.
Thanks to the Hashcat Team for cracking the hashes of the malware.
Below are listed service names which are also keys that can be found in the registry at HKLM\SYSTEM\CurrentControlSet\services and the corresponding vendor.