FlawOpen

flawopen.com/Incidents/solarwinds-sunburst-build-compromise-december-2020

● SolarWinds · CWE-506 / CWE-829 · September 2019 – December 2020 · Crítica
Investigación · FlawOpen

SUNBURST: el ataque a la cadena de compilación

SUNSPOT alteró el código de Orion durante el build e incluyó SUNBURST en actualizaciones firmadas. La firma probaba el origen, no la integridad.

💡 Explicación en Lenguaje Sencillo (ELI5)

Piensa en un cerrajero de confianza que envía kits de mantenimiento precintados y sellados a miles de edificios. Alguien entra en la fábrica donde se montan los kits y añade una pieza extra a cada uno antes de ponerles el precinto y el sello. Todos los edificios reciben un kit que de verdad viene del cerrajero y lo instalan. El precinto nunca se rompió, porque la manipulación ocurrió antes de precintar.

Conceptos Clave y Términos

SUNSPOT
El implante del servidor de compilación que analizó CrowdStrike. Vigilaba MSBuild.exe compilando Orion y sustituía un fichero fuente por la versión con puerta trasera mientras duraba la compilación.
SUNBURST
La puerta trasera compilada en SolarWinds.Orion.Core.BusinessLayer.dll. Permanecía inactiva hasta dos semanas y después contactaba por HTTP con la infraestructura del atacante.
Firma de código
Una firma criptográfica que demuestra que un binario procede de quien tiene la clave. No dice nada sobre si se manipuló la compilación que lo generó.
Compilación reproducible
Una compilación que genera una salida idéntica bit a bit a partir del mismo código fuente, para que compiladores independientes puedan comprobar los resultados de los demás.
CWE-506
Código malicioso incrustado. En este caso se insertó durante la propia compilación del proveedor, no en el repositorio de código fuente.

Mapeos de marcos

Cronología del Incidente

2019-09-04

Los atacantes acceden al entorno de SolarWinds; el 12 de septiembre inyectan código de prueba en una compilación de Orion para comprobar que el método funciona.

2020-02-20

SUNBURST se compila en las versiones de Orion a través de SUNSPOT.

2020-03-26

SolarWinds empieza a distribuir hotfixes de Orion que, sin saberlo, contienen SUNBURST; entre las versiones afectadas están 2019.4 HF5 y 2020.2.

2020-06-04

Los atacantes retiran SUNSPOT del entorno de compilación.

2020-12-13

FireEye publica su análisis de SUNBURST y CISA emite la Emergency Directive 21-01, que ordena a las agencias federales desconectar Orion.

Flujo de Ataque Paso a Paso

Paso 1

Se compromete el servidor de compilación

Los atacantes lograron acceso al entorno de compilación de SolarWinds e instalaron SUNSPOT en el servidor que compilaba Orion.

Paso 2

Se cambia un fichero fuente en plena compilación

Cuando SUNSPOT veía que MSBuild.exe compilaba la solución de Orion, sustituía InventoryManager.cs por una versión con puerta trasera y restauraba el original al terminar.

Paso 3

La clave auténtica firma el resultado

El SolarWinds.Orion.Core.BusinessLayer.dll compilado pasaba por el paso de firma normal, así que la DLL con puerta trasera llevaba una firma válida de SolarWinds.

Paso 4

Los clientes instalan una actualización de confianza

Menos de 18.000 clientes instalaron actualizaciones afectadas. Después, los atacantes eligieron un grupo mucho más pequeño de víctimas para intrusiones posteriores.

Código Fuente: Vulnerable vs. Seguro

C# ilustrativo, no es el pipeline de SolarWinds. El trabajo vulnerable confía en un único servidor de compilación de larga vida y firma todo lo que produce, justo lo que explotó SUNSPOT. La puerta reforzada exige dos compilaciones del mismo commit aprobado en compiladores recién aprovisionados y administrados por separado, compara sus resúmenes SHA-256 en tiempo constante y se niega a firmar ante cualquier diferencia. Un implante en un compilador produce entonces una discrepancia en lugar de una versión firmada; solo falla si el atacante controla ambos compiladores, por eso no deben compartir credenciales ni imágenes.

IMPLEMENTACIÓN VULNERABLE
using System;
using System.Diagnostics;

public static class ReleasePipeline
{
    // Las compilaciones usan la copia de trabajo compartida y escribible de un servidor y firman
    // cualquier resultado. También se firma lo que modifique el árbol durante la compilación.
    public static void BuildAndSign(string project, string outputDll)
    {
        using var build = Process.Start("msbuild.exe", $"\"{project}\" /p:Configuration=Release");
        build!.WaitForExit();
        if (build.ExitCode != 0)
            throw new InvalidOperationException("build failed");

        Signer.Sign(outputDll);   // HSM-backed signing service client
    }
}
PARCHE SEGURO Y ROBUSTO
using System;
using System.IO;
using System.Security.Cryptography;

public static class ReleaseGate
{
    // Dos compiladores aislados compilan el mismo commit fijado desde checkouts nuevos y de solo lectura,
    // con /p:Deterministic=true. La etapa de control firma únicamente resultados idénticos.
    public static void VerifyAndSign(string builderAOutput, string builderBOutput,
                                     string builtCommit, string approvedCommit)
    {
        if (!string.Equals(builtCommit, approvedCommit, StringComparison.Ordinal))
            throw new InvalidOperationException("build is not from the approved commit");

        byte[] a = SHA256.HashData(File.ReadAllBytes(builderAOutput));
        byte[] b = SHA256.HashData(File.ReadAllBytes(builderBOutput));
        if (!CryptographicOperations.FixedTimeEquals(a, b))
            throw new InvalidOperationException("independent builds differ; refusing to sign");

        Signer.Sign(builderAOutput, Convert.ToHexString(a));   // digest is logged with the signature
    }
}

Lista de Verificación de Seguridad para Ingeniería

Fuentes