#Solorigate : SUPERNOVA forensics using Code Property Graph

Chetan Conikee
ShiftLeft Blog
Published in
8 min readJan 3, 2021

--

The fallout of SolarWinds compromise has resulted in a bevy of new malware families, each with different characteristics and behaviors.

SolarWinds advisory : https://www.solarwinds.com/securityadvisory#anchor2

In this post, we will focus on the SUPERNOVA trojan, describing how this weaponized DLL was patched into Solarwinds SDLC (Software Development Life Cycle) post infiltration. Further, we will discuss anti evasion techniques employed by the APT actor.

The SUPERNOVA web shell implant is a trojanized copy of a legitimate ‘app_web_logoimagehandler.ashx.b6031896.dll’ library used by SolarWinds Orion web application.The purpose of the original DLL is to serve up a user-configured logo to web pages in the Orion web application. Let’s visually illustrate this benign functionality that serves a legitimate workflow in the Orion web application

Normal functionality of benign, unaltered DLL (app_web_logoimagehandler)

Web form of Orion with Logo rebranding workflow
The original ProcessRequest()

This module is purposed to return the logo image (white label based rebranding feature) configured by the user to various web pages of the SolarWinds Orion web application.

This is done through the ProcessRequest() method of the LogoImageHandler class.

Altered app_web_logoimagehandler DLL with backdoor to C2 server

Trojanized workflow during rebranding
Trojanized ProcessRequest that accepts the attacker controlled input

The DynamicRun() method is heart of the SUPERNOVA webshell.

This method accepts

  • C# source code blob,
  • the class to instantiate,
  • the associated method to invoke,
  • and the method’s arguments.

These parameters will be used to compile and execute an in-memory .NET assembly sent by the attacker over HTTP channel and after invoking successfully the response is packaged and returned to the attacker.

This functionality allows the attackers to compile and execute .NET payloads as and when needed, within the context of SolarWinds Orion Web Application. This mechanism does not leverage any exploit, but weaponizes a fundamental .NET feature called MetaProgramming. This is powerful, as it allows the malware to execute robust compiled code on the fly, without dropping any additional files to the file system or running any obvious commands being monitored over the wire.

Hacking the SDLC to weaponize C# MetaProgramming

Writing new programs at runtime and manipulating programs at runtime aren’t mutually exclusive concepts.The classic definition for a metaprogram is “a computer program that writes new computer programs.” This sounds a lot like the definition of a compiler. A compiler for a programming language like C# could be thought of as the ultimate metaprogram, because its only job is to produce other programs from source code.

The .NET framework provides compilers for C#, VB and JScript. These are the classes

  • Microsoft.CSharp.CSharpCodeProvider (wraps around the native compiler csc.exe),
  • Microsoft.VisualBasic.VBCodeProvider (wraps around the native compiler vbc.exe) and
  • Microsoft.JScript.JScriptCodeProvider (wraps around the native compiler jsc.exe)

Since theses compilers operate on files on the file system, the wrapper classes need to save the source files into temporary files to be able to pass them to the compilers.

Likewise, the compiled assemblies are (temporarily) saved to disk and then loaded by the wrappers. Because of that, true in-memory assembly generation is not possible with these classes. Also, these classes need full-trust permissions.

The compiler option can be set with the class CompilerParameters. Among others, there is a property called GenerateInMemory. If this is set to true, the compiled assemblies get deleted after being loaded into memory. Using this setting, an in-memory generation can be mimicked.

Examples of compiling metaprograms based on CodeDom (predates Roslyn) and Roslyn are presented here

CodeDom based: https://gist.github.com/conikeec/59d5c2e3652dd49cf5fefd38113f4b31

Roslyn based : https://gist.github.com/conikeec/6e13e0d558cc244689a44c9a4f0ff938

SUPERNOVA Evasion techniques

  • This attack was not induced by the same APT actor (UNC2452) as #SUNBURST as this trojanized DLL is not digitally signed and is not similar in characteristics to SUNBURST.
  • The try { … } catch(Exception) { } with an empty catch block sinkholes any exception generated leading to no-log/evidence being created which further-on does not trigger any SEIM/SOAR based ruleset. How did this change-request or patch pass code review?
  • GenerateInMemory is set to true leading to the malicious source-code blob that is injected via HTTP to not leave any traces on disk prior to passing them of to the compiler
  • The APT (advanced persistent threat) actor possibly infiltrated the SDLC process of SolarWinds Orion application in gather sufficient information (needed some formal knowledge to understand whether he/she should use a CodeDom or Roslyn based meta program — refer section above)

Using Code Property graph to detect webshell/backdoor patterns

Why is Code Property Graph uniquely positioned to detect complex backdoor patterns, design flaws?

  • Legacy static analysis cannot be tuned to analyze the evolving development landscape (asymmetry between legacy security and evolved development landscape).
  • Grep does not cut it. Of course one can grep in-and-around code but lack of inter-procedural context and attacker controlled flows will yield high false positive rate without context.

The code property graph is a concept based on a simple observation: there are many different graph representations of code (abstract syntax tree, control flow graph and data flow graph), and patterns in code can often be expressed as patterns in these graphs. While these graph representations all represent the same code, some properties may be easier to express in one representation over another. So, why not merge representations to gain their joint power, and, while we are at it, express the resulting representation as a property graph, the native storage format of graph databases, enabling us to express patterns via graph-database queries.

Creating policy using NGSAST to detect SUPERNOVA

  1. Autodetect SOURCE (EntryPoints) — functions that are public and accept HTTPContext from external calls (via API/Web from)
  2. Autodetect SINKS (ExitPoints) — sys-call, compiler assembly call, network, memory based, etc
  3. Search graph for empty catch block associated with a try block and get encapsulating block to determine if it contains any SINKS from (2)
  4. Determine taint reachability from SOURCE to SINK that passes through compiler assembly function(s)

Is Address space layout randomization (ASLR) as an exploit protection technique relevant to this conversation?

The answer is “no” as the APT actor managed to compromise the SDLC which in essence gave him/her unfettered control to various aspect of the build process.

However given that we broached this topic, let us delve further to understand its relevance to protection from ROP (Return Oriented Programming) attacks.

Address Space Layout Randomization (ASLR) is a computer security technique which involves randomly positioning the base address of an executable and the position of libraries, heap, and stack, in a process’s address space. The random mixing of memory addresses performed by ASLR means that an attack no longer knows at what address the required code (such as functions or ROP gadgets) is actually located. That way, rather than removing vulnerabilities from the system, ASLR attempts to make it more challenging to exploit existing vulnerabilities..

ASLR was introduced in Windows Vista and is in all newer versions. To make use of it, the executable needs to be compiled with /DYNAMICBASE option as well. OS based DLLs have it by default.

Return Oriented Programming (ROP) has become the exploitation technique of choice for modern memory-safety vulnerability attacks. Recently, there have been multiple attempts at defenses to prevent ROP attacks. In a ROP attack, the attacker does not inject new code; instead, the malicious computation is performed by chaining together existing sequences of instructions (called gadgets).

One common defense for ROP attacks is ASLR which works by randomly moving the segments of a program (including the text segment) around in memory, preventing the attacker from predicting the address of useful gadgets. Despite ASLR, ROP attacks are still common in the wild for two reasons. First, if even a single module has ASLR disabled, a ROP attack may be formed around only the code in that module. Second, an attacker may use an information disclosure vulnerability to de-randomize some module

  • ASLR is not supported when the executable or DLLs are not built with ASLR support. Although Windows 8 and Windows 10 try to overcome this limitation (e.g., force ASLR in Windows 8), there are still exceptions that many times render the ASLR protection ineffective. Older version of Windows and legacy programs are particularly prone to this limitation. In addition, ASLR on 32-bit systems suffers from low entropy, making it vulnerable to brute force and similar attacks.
  • ASLR aims to prevent an attack from reliably reaching its target memory address. ASLR does not focus on trapping the attack, rather on making the attack unlikely to work. Once the shellcode jumps to the wrong address during the exploit (due to the memory randomization), the program behavior is undefined. The process might receive an exception, crash, get stuck or simply continue with inconsistent behavior as a result.
  • ASLR does not give any alerts about attack attempts. When a vulnerability is exploited and fails (due to ASLR’s memory randomization), no alert or attack indication is received. Essentially ASLR doesn’t ‘know’ when an attack happened.
  • Forensic information about an attack, exploitation and shellcode is crucial for any serious forensic investigation. Exploited processes, memory dumps and call stacks can be used to identify, fingerprint and tag exploits. ASLR cannot provide this information because it doesn’t actually know if an attack happens or at which point it was stopped.

Since Address Space Layout Randomization was introduced in Windows OS, it has been bypassed many times by real-world exploits and attacks. Attackers continuously develop new techniques to defeat ASLR defense. Bypass techniques include

  • using ROP chain in non-ASLR modules (e.g., CVE 2013–1347),
  • JIT/NOP spraying (e.g., CVE-2013–3346),
  • as well as memory disclosure vulnerabilities and other techniques (e.g., CVE-2015–1685, CVE-2015–2449, CVE-2013–2556, CVE-2013–0640, CVE-2013–0634).

Conclusion

We at ShiftLeft have been studying and provisioning backdoor/insider detection policies using code property graph since mid 2019. Speak to us and we can help assess and recommend more efficient processes and procedures.

--

--

Engineer, InfoSec tinkerer, Seed Investor, Founder/CTO of ShiftLeft Inc., (Opinions, my own)