On December 13, 2020 FireEye published important details of a newly discovered supply chain attack. An unknown attacker, referred to as UNC2452 or DarkHalo planted a backdoor in the SolarWinds Orion IT software. This backdoor, which comes in the form of a .NET module, has some really interesting and rather unique features.
We spent the past days checking our own telemetry for signs of this attack, writing additional detections and making sure that our users are protected. At the moment, we identified approximately ~100 customers who downloaded the trojanized package containing the Sunburst backdoor. Further investigation is ongoing and we will continue to update with our findings.
Now, several things really stand out for this incident. This supply chain attack was designed in a very professional way – kind of putting the “A” in “APT” – with a clear focus on staying undetected for as long as possible. For instance, before making the first internet connection to its C2s, the Sunburst malware lies dormant for a long period, of up to two weeks, which prevents an easy detection of this behavior in sandboxes. Other advanced threat groups are also known to adopt similar strategies, for instance with hardware or firmware implants, which “sleep” for weeks or months before connecting to their C2 infrastructure. This explains why this attack was so hard to spot.
One of the things that sets this apart from other cases, is the peculiar victim profiling and validation scheme. Through the SolarWinds Orion IT packages, the attackers reached about 18,000 customers, according to the SolarWinds alert. Yet, out of these 18.000, it would appear that only a handful were interesting to them. Considering the fact that having the resources to manually exploit 18,000 computer networks is probably outside the reach of most if not all the attackers out there, this leads to the point that obviously some of those would have been a higher priority. Finding which of the 18,000 networks were further exploited, receiving more malware, installing persistence mechanisms and exfiltrating data is likely going to cast some light into the attacker’s motives and priorities.
In the initial phases, the Sunburst malware talks to the C&C server by sending encoded DNS requests. These requests contain information about the infected computer; if the attackers deem it interesting enough, the DNS response includes a CNAME record pointing to a second level C&C server.
Our colleagues from FireEye published several DNS requests that supposedly led to CNAME responses on Github: https://github.com/fireeye/sunburst_countermeasures/blob/main/indicator_release/Indicator_Release_NBIs.csv
DNS CNAME request-response pairs (Copyright 2020 by FireEye, Inc.)
Knowing that the DNS requests generated by Sunburst encode some of the target’s information, the obvious next step would be to extract that information to find out who the victims are!
Our colleagues from QiAnXin Technology already published a Python script to decode the domain names (on Github, of course): https://github.com/RedDrip7/SunBurst_DGA_Decode/blob/main/decode.py . Unfortunately, that script cannot decode all the DNS requests, besides it is always good to practice in reverse engineering anyway, so let’s look in the malware code.
Three of the requests from FireEye’s Github repository can be mapped to two domain names that belong to a government organization and a telecommunications company in the US.
The sample we’ll be analyzing is 2c4a910a1299cdae2a4e55988a2f102e. All we need is a .NET decompiler (dnSpy is a good one).
The logic that is interesting to us is located in OrionImprovementBusinessLayer.Update, which in turn calls one of the four functions: GetCurrentString, GetPreviousString, GetNextStringEx and GetNextString.
These four functions correspond to four different DNS-based communication methods.
Now, to find out what kind of data is encoded in the DNS requests (the hostname variable) we need to look closer into each one of these functions.
The first function GetCurrentString generates strings that contain a supposedly unique target’s identifier (this.guid), the target’s hostname (this.dnStrLower) and the rest of the hostname that will be in form of “appsync-api.*.avsvmcloud[.]com”. The encoding of the data is done by the functions CreateSecureString and CreateString.
The function GetPreviousString is bigger, but produces a similar hostname for a DNS request. It includes a part of the target’s hostname in the request, so that it would match the limitations on the request length. Each such request also includes the sequence number (this.nCount) that is the offset of the current substring from the beginning of the hostname.
The remaining two functions, GetNextStringEx and GetNextString, generate a different type of DNS requests. They include only the target’s UID, hashes of the running processes of interest and (only in the Ex version) the list and status of these processes. The target’s UID is then encrypted, and the data is encoded with CreateSecureString.
The encryption used in the malware is just a simple XOR operation, and the encoding is either a substitution cipher or Base32 with a custom alphabet. However, if we reverse the sequence of operations of GetPreviousString or GetCurrentString for the known CNAME DNS requests published by FireEye, the resulting strings don’t look like valid domain names!
A possible explanation is that the requests were generated by the third or fourth communication methods, described as GetNextStringEx or GetNextString. Indeed, they can be decoded without errors and the size of decoded data fits. However, these requests don’t have the target’s name included!
At this point, a question arises – can we match any of existing private and public DNS data for the malware root C2 domain, “avsvmcloud[.]com” with the CNAME records, to identify who was targeted for further exploitation?
A list of SUNBURST-generated domain names that include the domain names were kindly shared by John Bambenek on Github: https://github.com/bambenek/research/blob/main/sunburst/uniq-hostnames.txt .
Here’s a few such examples:
nnbggtlr1iv0v3vfnfaddfe.appsync-api.us-west-2.avsvmcloud[.]com
nq97kdu88pn1qpv8f3t5.appsync-api.us-east-1.avsvmcloud[.]com
nr2ia9qfa349b0q2oi60bou6iuir02rn.appsync-api.us-east-1.avsvmcloud[.]com
We complemented John’s data with our own datasets as well as other publicly available pDNS databases. Each one of these DNS requests also has the Base32-encoded UID. Since the UIDs are also included in other types of requests (types 3 and 4) in encrypted form, this allows us to match the requests!
The target’s UID is calculated in OrionImprovementBusinessLayer.GetOrCreateUserID by MD5-hashing the MAC address of the first online network adapter, then XORing it down to 64 bits.
The DNS requests published by FireEye on their GitHub have the following encrypted UIDs inside:
DNS request | UID (64 bit) |
6a57jk2ba1d9keg15cbg.appsync-api.eu-west-1.avsvmcloud[.]com | 0xEED328E059EB07FC |
7sbvaemscs0mc925tb99.appsync-api.us-west-2.avsvmcloud[.]com | 0x683D2C991E01711D |
gq1h856599gqh538acqn.appsync-api.us-west-2.avsvmcloud[.]com | 0x2956497EB4DD0BF9 |
ihvpgv9psvq02ffo77et.appsync-api.us-east-2.avsvmcloud[.]com | 0xF7A37335B9E57DDB |
k5kcubuassl3alrf7gm3.appsync-api.eu-west-1.avsvmcloud[.]com | 0xA46E6E874771323C |
mhdosoksaccf9sni9icp.appsync-api.eu-west-1.avsvmcloud[.]com | 0xA46E6E874771323C |
In total, we analyzed 1722 DNS records, leading to 1026 unique target name parts and 964 unique UIDs.
Matching the two lists we got the following data:
domain name part(0x2956497EB4DD0BF9)=central.****.g
domain name part(0x2956497EB4DD0BF9)=ov
domain name part(0x683D2C991E01711D)=central.****.g
domain name part(0x683D2C991E01711D)=ov
domain name part(0xF7A37335B9E57DDB)=***net.***.com
These steps effectively decoded 3 of the 6 CNAME records provided by FireEye into two possible domains:
***net.***.com – a rather big telecommunications company from the US, serving more than 6 million customers
central.***.gov – a governmental organization from the US
Please note that for ethical reasons, we do not include these exact domain names here. We notified the two organizations in question though, offering our support to discover further malicious activities, if needed.
It should also be noted that there is no way to be sure that machines in these two domains were actually further exploited. This being a probabilistic puzzle, we can assume with a high degree of certitude the two decoded domains were interesting to the attackers, however, we cannot be 100% sure that associated organizations were the subject of further malicious activities.
To summarize our research, the UIDs we discovered match two domain names that belong to a US government organization and a large US telecommunications company. It is likely that other interesting targets were selected by the attackers for further exploitation. If you happen to have access to large DNS databases, including CNAME replies for any subdomain in “avsvmcloud[.]com”, please let us know! (contact: intelreports (at) kaspersky [dot] com)
In order to help the community to potentially identify other interesting targets for the attackers, we are publishing the source code for the decoder:
https://github.com/2igosha/sunburst_dga
Stay safe!
More details and mitigations about Sunburst, UNC2452 / DarkHalo are available to customers of Kaspersky Intelligence Reporting. Contact: intelreports (at) kaspersky [dot] com