Hunting Sunburst (Solorigate\UNC2452) — Looking Beyond the Logs

Yoav Elata
Reflectiz
Published in
5 min readDec 19, 2020

It is not often that one resorts to a deep dive into a malware’s decompiled code in the process of determining whether or not his network was compromised. In most cases a simple IoCs search suffices to answer the most burning questions:

  1. Is the malware present in the network?
    if so
  2. What actions did it perform?

But this was not the case with Sunburst. I found two concerning IoCs in the network, comprised from a copy of SolarWinds.Orion.Core.BusinessLayer.dll, which contains the backdoor, and the DNS requests to hosts under the avsvmcloud[.]com domain. However, the value of ReportWatcherRetry in the SolarWinds.Orion.Core.BusinessLayer.dll.config file was set to 3, i.e. the backdoor was deactivated. Other than that no further IoCs were found.

But absence of evidence is not evidence of absence. How can I be certain that nothing happened between the activation and deactivation period of the backdoor? Due to the severity and very stealthy nature of this attack I decided I wasn’t going to settle for circumstantial evidence. I saw some snippets of the decompiled dll along with explanations of its behaviour and ways it obfuscates its activity. It occurred to me that if I could examine the code of the backdoor in its entirety I might just have enough information at hand to be able to paint a clear picture of what happened on the infected hosts. Perhaps by correlating the IoCs I found on the hosts and the state they are currently in (ReportWatcherRetry==3), with the code’s progression flow I would be able to determine (with fairly high confidence) whether I was missing anything.

I found a variant of the decompiled malicious dll in GitHub. Assisted by the analysis done so far (e.g. FireEye’s report) I began sifting through the code, looking for parts to correlate with the creation of the IoCs I found, trying to follow the crumbs that would lead me to the state the hosts are currently in. So I was looking for two datum points:

  1. where are the DNS requests made?
  2. where is ReportWatcherRetry set to 3?

Let’s dig in

The first thing the backdoor does is go through an initialization phase

Initialize()

Initialize()
  1. the malware checks that it is running under businesslayerhost.exe
  2. compares the current time to the file write time of the malicious DLL and exits if 12–14 days didn’t pass
  3. if 12–14 days passed it attempts to create a named pipe with the following value “583da945–62af-10e8–4902-a8f205c72b2e”
  4. checks the status of ReportWatcherRetry (ReadReportStatus()) — if it doesn’t equal 3 (Truncate), the program continues
  • the fact that we saw DNS requests means that the malware got past this point and, ipso facto, that the initial value of ReportWatcherRetry was NOT 3

5. DelayMin makes the malware sleep for sometime

6. the malware checks that the host is part of a domain

7. if it is, the malware sleeps again

8. creates a userID

9. sleeps some more

10. checks the value of ReportWatcherPostpone in the config file(ReadServiceStatus())

11. runs the main function — Update()

So from the fact that this part doesn’t implement the DNS requests capability I can derive that the malware went through the initialization process successfully and executed Update().

Update()

Update() — part 1
  1. it begins by initializing some variables it will need later (cryptoHelper,httpHelper,etc.)
  2. then it makes a DNS request to api.solarwinds.com by calling the UpdateNotification() function
Update() — part 2

For up to three attempts:

  1. Determines whether the value of ReportWatcherRetry is 4 (New) or 5 (Append)
  2. Based on the result of the above test it generates a subdomain of avsvmcloud[.]com
  3. Makes a DNS request to the generated domain and determines to which IP category it belongs to (GetAddressFamily())

So we know it got at least as far as this point in the execution process. Let’s see where ReportWatcherRetry is set to 3.

Update() — continued

Update — part 3

after the IP category of the IP the DNS request returned is stored in the addressFamilyEx variable, a switch-case statement is made to determine which path to take:

  1. If the address is in the NetBios category and if a CNAME record is present, the malware executes a Http(s) communications thread which communicates with the host specified in the record
  2. If the address is in the ImpLink or Atm categories, sets ReportWatcherRetry to 3 and exits
  3. If the address is in the Ipx category and ReportWatcherRetry==5 (Append), it sets ReportWatcherRetry to 4 (New)
  4. If the response address is not in any of the IP categories, the malware exits
  5. If the response is an error, the malware waits between 420 and 540 minutes before making the next attempt

Aforementioned point (2) is where we can breath again

ReportWatcherRetry is set to 3 (Truncate)

This means that the DNS resolved an address to one of the following subnets which comprise the ImpLink and Atm categories:

from FireEye’s report

Conclusion

Based on the above analysis I can determine with great certainty that nothing malicious had occurred in the network and the malware’s actions indeed amounted to only making DNS requests that resulted in the backdoor being deactivated.

But there still remain two caveats that might yet undermine this conclusion:

  • what if the DNS queries first resolved to IPs in the NetBios category and only at a later point in time turned to be resolved to the ImpLink\Atm categories?
  • what if ReportWatcherRetry is set to 3 elsewhere in the dll (beyond the scope of the OrionImprovementBusinessLayer class) where further malicious commands are executed?

To the former point I say this: while it is indeed a possibility, I find it very unlikely and unreasonable. I base this on the fact that the DNS logs I observed show no such pattern, and that this is unlikely behaviour from what seems to be a state-sponsored attack that is predominantly targeting US organizations.

As to the latter point, there isn’t a single report (at least not one that I came across) that supports this. It appears that the malware’s activity was truly confined to the OrionImprovementBusinessLayer class.

--

--

Yoav Elata
Reflectiz

Cyber enthusiast, CSOC Manager and Senior Analyst at BugSec, B.A. in Philosophy, Cognitive science, and Computer science. Autodidacticism is a guiding principle