FlawOpen

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

● SolarWinds · CWE-506 / CWE-829 · September 2019 – December 2020 · Kritisch
Sicherheitsforschung · FlawOpen

SUNBURST: Als die Build-Pipeline die Schwachstelle war

SUNSPOT änderte Orion-Quellcode beim Build und brachte SUNBURST in signierte Updates. Eine Signatur belegte die Herkunft, nicht die Code-Integrität.

💡 Einfache Erklärung (ELI5)

Stellen Sie sich einen vertrauenswürdigen Schlüsseldienst vor, der versiegelte, gestempelte Wartungskits an Tausende Gebäude schickt. Jemand bricht in die Fabrik ein, in der die Kits zusammengestellt werden, und legt in jedes ein kleines Zusatzteil, bevor Siegel und Stempel aufgebracht werden. Jedes Gebäude erhält ein Kit, das wirklich vom Schlüsseldienst stammt, und baut es ein. Das Siegel wurde nie gebrochen, weil die Manipulation vor dem Versiegeln geschah.

Kernkonzepte & Begriffe

SUNSPOT
Das von CrowdStrike analysierte Implantat auf dem Build-Server. Es wartete, bis MSBuild.exe Orion baute, und ersetzte für die Dauer des Builds eine Quelldatei durch die präparierte Version.
SUNBURST
Die in SolarWinds.Orion.Core.BusinessLayer.dll kompilierte Hintertür. Sie blieb bis zu zwei Wochen inaktiv und kontaktierte dann per HTTP die Infrastruktur der Angreifer.
Code-Signatur
Eine kryptografische Signatur, die zeigt, dass ein Binary vom Schlüsselinhaber stammt. Über eine Manipulation des erzeugenden Builds sagt sie nichts aus.
Reproduzierbarer Build
Ein Build, der aus demselben Quellcode bitgleiche Ausgaben erzeugt, sodass unabhängige Builder ihre Ergebnisse gegenseitig prüfen können.
CWE-506
Eingebetteter Schadcode. Hier wurde er während des Builds beim Hersteller selbst eingefügt, nicht im Quellcode-Repository.

Framework-Zuordnungen

Vorfall-Zeitstrahl

2019-09-04

Die Angreifer verschaffen sich Zugang zur Umgebung von SolarWinds; am 12. September schleusen sie Testcode in einen Orion-Build ein, um die Methode zu erproben.

2020-02-20

SUNBURST wird über SUNSPOT in Orion-Builds kompiliert.

2020-03-26

SolarWinds beginnt, Orion-Hotfixes auszuliefern, die unbemerkt SUNBURST enthalten; betroffen sind unter anderem 2019.4 HF5 und 2020.2.

2020-06-04

Die Angreifer entfernen SUNSPOT aus der Build-Umgebung.

2020-12-13

FireEye veröffentlicht seine SUNBURST-Analyse, und die CISA erlässt die Emergency Directive 21-01, die Bundesbehörden anweist, Orion vom Netz zu nehmen.

Schritt-für-Schritt Angriffsablauf

Schritt 1

Der Build-Server wird kompromittiert

Die Angreifer verschafften sich Zugang zur Build-Umgebung von SolarWinds und installierten SUNSPOT auf dem Server, der Orion kompilierte.

Schritt 2

Eine Quelldatei wird mitten im Build getauscht

Sah SUNSPOT MSBuild.exe die Orion-Solution bauen, ersetzte es InventoryManager.cs durch eine präparierte Version und stellte nach der Kompilierung das Original wieder her.

Schritt 3

Der echte Schlüssel signiert das Ergebnis

Die kompilierte SolarWinds.Orion.Core.BusinessLayer.dll durchlief den normalen Signaturschritt, sodass die präparierte DLL eine gültige SolarWinds-Signatur trug.

Schritt 4

Kunden installieren ein vertrauenswürdiges Update

Weniger als 18.000 Kunden installierten betroffene Updates. Danach wählten die Angreifer eine viel kleinere Gruppe von Opfern für weitere Eindringversuche aus.

Quellcode: Verwundbar vs. Sicher

Illustratives C#, nicht die Pipeline von SolarWinds. Der verwundbare Job vertraut einem einzigen, langlebigen Build-Server und signiert alles, was er erzeugt – genau das nutzte SUNSPOT aus. Das gehärtete Gate verlangt zwei Builds desselben freigegebenen Commits auf frisch bereitgestellten, getrennt administrierten Buildern, vergleicht ihre SHA-256-Digests in konstanter Zeit und verweigert bei jeder Abweichung die Signatur. Ein Implantat auf einem Builder führt dann zu einer Abweichung statt zu einem signierten Release; das schlägt nur fehl, wenn der Angreifer beide Builder kontrolliert, weshalb sie keine Zugangsdaten oder Images teilen dürfen.

VERWUNDBARE IMPLEMENTIERUNG
using System;
using System.Diagnostics;

public static class ReleasePipeline
{
    // Builds verwenden die gemeinsame, beschreibbare Arbeitskopie eines Buildservers und signieren
    // jedes Ergebnis. Auch Änderungen am Quellbaum während des Builds werden signiert.
    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
    }
}
GEHÄRTETER SICHERHEITS-PATCH
using System;
using System.IO;
using System.Security.Cryptography;

public static class ReleaseGate
{
    // Zwei isolierte Builder kompilieren denselben fixierten Commit aus frischen, schreibgeschützten Checkouts,
    // mit /p:Deterministic=true. Die Prüfung signiert nur identische Ergebnisse.
    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
    }
}

Checkliste für Engineering & Systemsicherheit

Quellen