2 Punkte von GN⁺ 2024-04-13 | 1 Kommentare | Auf WhatsApp teilen
  • Die Backdoor in XZ Utils/liblzma wurde am 29. März 2024 auf der Openwall-OSS-security-Mailingliste veröffentlicht. Das wahrscheinliche Endziel der Angreifer war es, dem OpenSSH-Server sshd auf systemd-basierten Distributionen die Fähigkeit zur Remote Code Execution einzupflanzen.
  • Die Infektionskette bestand aus einer mehrstufigen Einschleusung, die Testdateien und Build-Infrastruktur des XZ-Repositories nutzte. Über build-to-host.m4, bad-3-corrupt_lzma2.xz und good-large_compressed.lzma wurde während des Builds eine bösartige Objektdatei in liblzma gelinkt.
  • Die mit der Backdoor versehenen XZ 5.6.0 und 5.6.1 wurden in Beta- und experimentellen Builds einiger großer Anbieter ausgeliefert, und CVE-2024-3094 wurde mit dem Schweregrad 10 eingestuft.
  • Die binäre Backdoor wird durch Missbrauch von GLIBCs IFUNC und des cpuid-Aufrufpfads geladen und versucht danach, mit OpenSSL/libcrypto verbundene Funktionen zu hooken, um Verbindungen auf infizierten Maschinen zu überwachen.
  • Der Schadcode prüft, ob /usr/bin/sshd läuft, sowie eine Kill-Switch-Umgebungsvariable, und erschwert Analyse und Erkennung durch trie-basierte String-Verarbeitung, dynamische Symbolauflösung und Runtime-Patching von rtdl-audit.

Überblick über den Vorfall und den Wirkungsbereich

  • Am 29. März 2024 wurde über eine Nachricht auf der Openwall-OSS-security-Mailingliste die Entdeckung der XZ-Backdoor öffentlich gemacht.
  • XZ ist ein Komprimierungswerkzeug, das in viele große Linux-Distributionen integriert ist.
  • Der Kern des Risikos besteht darin, dass das kompromittierte liblzma auf einigen systemd-basierten Distributionen mit dem OpenSSH-Serverprozess sshd verbunden werden konnte.
    • Ubuntu, Debian und RedHat/Fedora Linux patchen OpenSSH so, dass systemd-Funktionen genutzt werden und dadurch eine Abhängigkeit von dieser Bibliothek entsteht.
    • Arch Linux und Gentoo gelten als nicht betroffen.
  • Das wahrscheinliche Endziel der Angreifer war es, eine Remote-Code-Execution-Funktion in sshd einzubauen, die andere nicht nutzen konnten.
  • Anders als bei anderen Supply-Chain-Angriffen, die sich auf einen einzelnen bösartigen Patch, ein gefälschtes Paket oder ein Typosquatting-Paket konzentrieren, kommt dieser Vorfall einer mehrstufigen Operation gleich, die beinahe weltweit SSH-Server kompromittiert hätte.

Wie die Backdoor eingeschleust wurde

  • Die liblzma-Backdoor wurde auf zwei Ebenen eingeschleust, indem sowohl der Build-Prozess als auch Testdateien genutzt wurden.
    • Der Quellcode der Build-Infrastruktur, der das Endpaket erzeugt, wurde durch das Hinzufügen von build-to-host.m4 verändert.
    • In Testfalldateien verborgene Skripte und Binärkomponenten wurden während des Builds extrahiert.
  • Der Infektionsablauf drehte sich um drei Dateien.
    • build-to-host.m4: ein Build-Skript, das das Skript der nächsten Stufe extrahiert
    • bad-3-corrupt_lzma2.xz: eine Testdatei mit verstecktem Shell-Skript
    • good-large_compressed.lzma: eine Testdatei mit verstecktem bösartigem Binärobjekt
  • Die extrahierte bösartige Binärkomponente wurde während der Kompilierung mit der legitimen Bibliothek gelinkt und konnte so in Linux-Repositories gelangen.
  • Große Anbieter verteilten diese bösartige Komponente in Beta- und experimentellen Builds.
  • Der Kompromittierung von XZ Utils wurde CVE-2024-3094 zugewiesen, mit dem maximalen Schweregrad 10.

Wichtige Zeitleiste

    1. Januar 2024: Der neue Maintainer jiaT75 verlegt die XZ-Website auf GitHub Pages.
    1. Februar 2024: build-to-host.m4 wird zu .gitignore hinzugefügt.
    1. Februar 2024: Zwei „Testdateien“ mit Stufen des bösartigen Skripts werden hinzugefügt.
    1. Februar 2024: XZ 5.6.0 wird veröffentlicht.
    1. Februar 2024: Ein Commit in CMakeLists.txt wird eingefügt, der die Landlock-Sicherheitsfunktion behindert.
    1. März 2024: Die Backdoor verursacht Probleme mit Valgrind.
    1. März 2024: Die beiden Testdateien werden aktualisiert, die CRC-Funktion wird geändert und das Valgrind-Problem wird „behoben“.
    1. März 2024: XZ 5.6.1 wird veröffentlicht.
    1. März 2024: Der Bug wird entdeckt und Debian sowie RedHat werden informiert.
    1. März 2024: Debian setzt XZ 5.6.1 auf Version 5.4.5-0.2 zurück.
    1. März 2024: Die öffentliche Mail wird auf der OSS-security-Mailingliste veröffentlicht.
    1. März 2024: RedHat bestätigt, dass XZ mit Backdoor in Fedora Rawhide und Fedora Linux 40 beta ausgeliefert wurde.
    1. März 2024: Debian stoppt Builds und beginnt mit dem Rebuild-Verfahren.
    1. April 2024: Der Hauptentwickler von XZ erkennt den Backdoor-Vorfall an.

Die 3 Stufen der Infektionskette

  • Stufe 1: Modifiziertes build-to-host.m4

    • Die Release-Versionen im offiziellen GitHub-Repository von XZ enthielten zwar die bösartigen Testdateien, waren aber zunächst harmlos, weil diese Dateien keine Gelegenheit zur Ausführung hatten.
    • Der Schadcode, der die Infektion bootstrappt, scheint in den Releases enthalten gewesen zu sein, die von jiaT75 kontrolliert auf xz[.]tukaani.org bereitgestellt wurden.
    • Die meisten Distributionen nutzten diese URL, und die heruntergeladenen Releases enthielten die Datei build-to-host.m4 mit dem Schadcode.
    • build-to-host.m4 wird während des Build-Prozesses ausgeführt, repariert die „beschädigten“ Daten in bad-3-corrupt_lzma2.xz mit tr und dekomprimiert sie dann mit xz -d.
    • Das Ergebnis der Dekomprimierung enthält ein Shell-Skript, das später mit /bin/bash ausgeführt wird.
  • Stufe 2: Eingeschleustes Shell-Skript

    • Das durch die bösartige .m4-Datei eingeschleuste Skript prüft, ob es auf einer Linux-Maschine und innerhalb des beabsichtigten Build-Prozesses läuft.
    • Für die Ausführung der nächsten Stufe wird good-large_compressed.lzma verwendet.
    • Diese Datei ist regulär mit XZ komprimiert, enthält aber Junk-Daten in den dekomprimierten Daten.
    • Das Skript extrahiert die Daten, indem es eine head-Pipeline mit eval ausführt.
    • Jeder head-Befehl verwirft die nächsten 1024 Byte oder extrahiert die nächsten 2048 Byte beziehungsweise 724 Byte.
    • Insgesamt werden 33.492 Byte extrahiert.
    • tail behält die letzten 31.265 Byte der Datei und verwirft den Rest.
    • Danach wird mit tr eine einfache Ersetzung angewandt, um die Obfuskation aufzuheben, und ein zweiter XZ-Befehl dekomprimiert die transformierten Bytes als rohen lzma-Stream, bevor das Ergebnis an die Shell übergeben wird.
  • Stufe 3: Extraktion des Backdoor-Objekts

    • Das Shell-Skript der letzten Stufe prüft anhand mehrerer Bedingungen, ob es in der erwarteten Umgebung läuft.
    • Es prüft, ob das Projekt so konfiguriert ist, dass IFUNC verwendet wird.
    • Es prüft, ob mit GCC kompiliert wird.
    • Danach prüft es, ob bestimmte Dateien, die das Skript benötigt, im Projekt vorhanden sind.
    • Diese Stufe extrahiert eine Objektdatei, die an einem anderen Offset in good-large_compressed.lzma versteckt ist.
    • Das Extraktionsverfahren führt mehrere Befehle nacheinander aus und übergibt die Ausgabe jedes Befehls als Eingabe an den nächsten.
    • Das XZ-Werkzeug extrahiert good-large_compressed.lzma.
    • Verwendet werden eval $i und mehrere head-Aufrufe.
    • Mit einem benutzerdefinierten, RC4-ähnlichen Algorithmus werden die Binärdaten entschlüsselt.
    • Die entschlüsselte komprimierte Datei wird erneut mit XZ extrahiert.
    • Nach dem Entfernen einiger Bytes am Anfang wird das Ergebnis als liblzma_la-crc64-fast.o gespeichert.
    • Abschließend verändert das Skript in der Datei crc_x86_clmul.h von liblzma die Funktion is_arch_extension_supported.
    • Dabei wird der Aufruf __get_cpuid zu _get_cpuid geändert, also ein Unterstrich entfernt.
    • Durch diese Änderung kann das Backdoor-Objekt in die Bibliothek gelinkt werden.

Wie die binäre Backdoor geladen wird

  • Im ursprünglichen XZ-Code gibt es die speziellen Funktionen lzma_crc32 und lzma_crc64 zur CRC-Berechnung.
  • Beide Funktionen sind in der ELF-Symboltabelle als GLIBC-Typ IFUNC gespeichert.
    • IFUNC erlaubt dem dynamischen Linker, beim Laden einer Shared Library die zu verwendende Funktion dynamisch auszuwählen.
    • XZ nutzt dies, um nach Prüfung moderner Prozessorfunktionen wie CLMUL, SSSE3 und SSE4.1 zu entscheiden, ob optimierte CRC-Funktionen verwendet werden sollen.
  • Für die Prüfung der Prozessorfunktionen ist der cpuid-Befehl nötig, und dazu wird der von GLIBC bereitgestellte Wrapper __get_cpuid aufgerufen.
  • Indem das bösartige Skript __get_cpuid zu _get_cpuid ändert, wird der Codeaufruf mit dem _get_cpuid-Symbol in der Backdoor-Objektdatei verbunden.
  • Der anfängliche Backdoor-Code wird zweimal aufgerufen, weil lzma_crc32 und lzma_crc64 dieselbe modifizierte Funktion _get_cpuid verwenden.
    • Ein einfacher Zähler prüft, ob die Ausführung bereits erfolgt ist.
    • Wenn die IFUNC von lzma_crc64 _get_cpuid aufruft und der Zählerwert 1 ist, beginnt die Umleitung zum endgültigen Einstiegspunkt.

Laufzeitverhalten und Hooking-Ziele

  • Die Backdoor initialisiert Strukturen, die zentrale Informationen über den laufenden Prozess enthalten.
  • Über hartcodierte Offsets findet sie die Adresse der Global Offset Table(GOT) und darin den cpuid-Pointer.
  • Anschließend ersetzt sie den Pointer durch die Haupt-Schadfunktion und ruft die bösartige Funktion so auf, als würde cpuid aufgerufen.
  • Das Hauptziel besteht darin, bestimmte Funktionen zu hooken, um eingehende Verbindungen auf der infizierten Maschine überwachen zu können.
  • Die Zielfunktionen stehen mit libcrypto in Verbindung.
    • RSA_public_decrypt: wird verwendet, um mit einem privaten Schlüssel signierte Chiffretexte zu entschlüsseln
    • EVP_PKEY_set1_RSA: wird verwendet, um einen RSA-Schlüssel in einem bestimmten Kontext zu setzen
      • In neueren SSH-Server-Versionen kommt die Funktion nicht vor, wohl aber in eigenständigen Werkzeugen zur SSH-Schlüsselerzeugung.
    • RSA_get0_key: wird verwendet, um einen RSA-Schlüssel abzurufen
  • Der Hooking-Prozess erfordert Zugriff auf mehrere interne Strukturen und Manipulation prozessspezifischer Strukturen, wobei der Schadcode zugleich Prüfungen zur Analysevermeidung durchführt.

Prüfungen der Laufzeitumgebung und Techniken zur Analysevermeidung

  • Prüfung von sshd und Kill Switch

    • Die Backdoor parst zunächst den dynamischen Linker ld-linux, um Symboladressen dynamisch aufzulösen.
    • Sie prüft, ob die aktuelle Laufzeitumgebung die Kriterien erfüllt.
    • Sie prüft, ob der aktuelle Prozess /usr/bin/sshd ist.
    • Sie prüft, ob ein Kill Switch vorhanden ist.
    • Der Name des aktuellen Prozesses wird aus argv[0] extrahiert.
    • Alle Umgebungsvariablen des Prozesses werden geparst und mit Werten in einer internen String-Tabelle verglichen.
    • Gibt es eine passende Umgebungsvariable oder ist der Prozess nicht sshd, beendet der Schadcode seine Ausführung.
    • Die einzige Variable in der internen Tabelle, yolAbejyiejuvnup=Evjtgvsh5okmkAvj, fungiert in diesem Kontext als Kill Switch.
  • Trie-basierte String-Verarbeitung

    • Ein charakteristisches Merkmal der Backdoor ist die Verwendung einer einzigen Trie-Struktur für String-Operationen.
    • Statt Konstanten wie Funktionsnamen direkt oder per String-Hash zu vergleichen, prüft sie, ob das Ergebnis einer Trie-Abfrage einem bestimmten Konstantwert entspricht.
    • Der Magic-Wert eines ELF-Headers liefert im Trie 0x300 zurück.
    • Der Funktionsname system entspricht dem Rückgabewert 0x9F8.
    • Das Trie dient nicht nur Vergleichen, sondern auch dazu, Strings im Host-Binary zu finden.
    • Beispielsweise suchen Funktionen, die String-Pointer wie ssh-2.0 verwenden, den String im Host-Binary, damit im eigentlichen Backdoor-Code keine verdächtigen Daten zurückbleiben.
    • Die Implementierung verwendet 16-Byte-Bitmasken.
    • Jede Hälfte entspricht den Eingabebytebereichen 0x00-0x3F beziehungsweise 0x40-0x7F.
    • Trie-Blattknoten sind 2 Byte groß; 3 Bit dienen als Flags, der Rest ist für Werte oder die Position des nächsten Knotens reserviert.

Symbolauflösung und rtdl-audit-Hooking

  • Routinen zur Symbolauflösung

    • Die Backdoor enthält mindestens drei Routinen zur Symbolauflösung, um ELF-Symbolstrukturen zu finden.
    • Alle Funktionen zur Symbolauflösung nehmen als Eingabe einen im Trie nachzuschlagenden Schlüssel entgegen.
    • Eine Auflösungsfunktion iteriert durch alle Symbole, sucht nach dem Symbol mit dem gewünschten Schlüssel und gibt bei Erfolg die Elf64_Sym-Struktur zurück.
    • Diese Struktur wird anschließend verwendet, um interne Strukturen der Backdoor zu füllen und benötigte Funktionspointer zu speichern.
    • Das ähnelt den aus Windows-Bedrohungen bekannten API-Hashing-Routinen.
    • Die Backdoor sucht danach zahlreiche OpenSSL-libcrypto-Funktionen, die später in Kryptoroutinen verwendet werden.
    • Sie verfolgt, wie viele Funktionen gefunden und aufgelöst wurden, und entscheidet anhand dieses Werts, ob die Ausführung normal fortgesetzt oder abgebrochen wird.
  • Missbrauch von lzma_alloc durch einen Fake-Allocator

    • Ein weiterer Symbolauflöser missbraucht die liblzma-eigene Funktion lzma_alloc.
    • lzma_alloc hilft dabei, Speicher effizient zuzuweisen, indem entweder der Standard-Allocator malloc oder ein benutzerdefinierter Allocator verwendet wird.
    • In der XZ-Backdoor fungiert diese Funktion über einen Fake-Allocator wie ein weiterer Symbolauflöser.
    • Der Parameter, der eigentlich als „Allokationsgröße“ dient, wird tatsächlich als Symbolschlüssel innerhalb des Tries verwendet.
    • Dieser Trick soll die Analyse der Backdoor erschweren.
    • Die Backdoor löst Symbole zur Laufzeit dynamisch auf und ist nicht darauf beschränkt, entweder alle Symbole auf einmal oder nur bei Bedarf aufzulösen.
    • Zu den aufgelösten Zielen gehören normale OpenSSL-Funktionen ebenso wie Funktionen wie system, mit denen auf der Maschine Befehle ausgeführt werden können.
  • Runtime-Patching von rtdl-audit

    • Für das Hooking von Funktionen nutzt die Backdoor die rtdl-audit-Funktion des dynamischen Linkers.
    • Normalerweise erlaubt rtdl-audit Entwicklern, eine benutzerdefinierte Shared Library zu erstellen, um über Linker-Ereignisse wie Symbolauflösung informiert zu werden.
    • Die XZ-Backdoor erstellt jedoch keine separate Shared Library, sondern patcht zur Laufzeit die bereits im Speicher registrierte Standard-Schnittstelle, um die Symbolauflösungsroutine zu kapern.
    • Die bösartige audit_iface-Struktur, die in der globalen Variablen dl_audit im Speicherbereich des dynamischen Linkers abgelegt wird, enthält die Adresse des symbind64-Callbacks.
    • Wenn der dynamische Linker dieses Callback aufruft, gerät die gesamte Symbolinformation unter die Kontrolle der Backdoor, und für Zielfunktionen werden bösartige Adressen zurückgegeben, wodurch das Hooking erreicht wird.
    • Die Adressen von dl_audit und dl_naudit werden durch Disassemblierung der Funktionen dl_main und dl_audit_symbind_alt gewonnen.
    • Die Backdoor enthält einen internen minimalistischen Disassembler zur Befehlsdekodierung, der breit eingesetzt wird, wenn bestimmte Werte wie *audit-Adressen gefunden werden sollen.

Bestätigte Backdoor-Distributionen und Erkennungsinformationen

  • Quell-Distributionen mit Backdoor

    • xz-5.6.0
      • MD5: c518d573a716b2b2bc2413e6c9b5dbde
      • SHA1: e7bbec6f99b6b06c46420d4b6e5b6daa86948d3b
      • SHA256: 0f5c81f14171b74fcc9777d302304d964e63ffc2d7b634ef023a7249d9b5d875
    • xz-5.6.1
      • MD5: 5aeddab53ee2cbd694f901a080f84bf1
      • SHA1: 675fd58f48dba5eceaf8bfc259d0ea1aab7ad0a7
      • SHA256: 2398f4a8e53345325f44bdd9f0cc7401bd9025d736c6d43b372f4dea77bf75b8
  • Analysierte Hauptartefakte

    • bad-3-corrupt_lzma2.xz: 86fc2c94f8fa3938e3261d0b9eb4836be289f8ae
    • build-to-host.m4: b4dd2661a7c69e85f19216a6dbbb1664
    • good-large_compressed.lzma: 540c665dfcd4e5cfba5b72b4787fec4f
    • liblzma_la-crc64-fast.o: 212ffa0b24bb7d749532425a46764433
  • Bekannte Bibliotheken mit Backdoor

    • Debian Sid liblzma.so.5.6.0
      • MD5: 4f0cf1d2a2d44b75079b3ea5ed28fe54
      • SHA1: 72e8163734d586b6360b24167a3aff2a3c961efb
      • SHA256: 319feb5a9cddd81955d915b5632b4a5f8f9080281fb46e2f6d69d53f693c23ae
    • Debian Sid liblzma.so.5.6.1
      • MD5: 53d82bb511b71a5d4794cf2d8a2072c1
      • SHA1: 8a75968834fc11ba774d7bbdc566d272ff45476c
      • SHA256: 605861f833fc181c7cdcabd5577ddb8989bea332648a8f498b4eef89b8f85ad4
  • Erkennungsnamen

    • Kaspersky-Produkte erkennen mit dem Angriff verbundene bösartige Objekte als HEUR:Trojan.Script.XZ und Trojan.Shell.XZ.
    • Kaspersky Endpoint Security for Linux erkennt den Schadcode im Speicher des SSHD-Prozesses im Rahmen des Critical Areas Scan als MEM:Trojan.Linux.XZ.
    • Die bereitgestellte Yara-Regel ist die Regel liblzma_get_cpuid_function, die die bösartige get_cpuid-Funktion im Zusammenhang mit CVE-2024-3094 finden soll.

1 Kommentare

 
GN⁺ 2024-04-13
Meinungen auf Hacker News
  • Dieser Satz scheint das, was tatsächlich passiert ist, eher herunterzuspielen.
    Erschreckender als die technischen Aspekte der Backdoor ist das Ausmaß und Niveau des Social Engineerings. Die Backdoor war das Endprodukt; möglich wurde sie, weil das gesamte xz-Projekt zu diesem Zeitpunkt bereits über längere Zeit von böswilligen Akteuren, also „Jia Tan“ und seinem Umfeld, vereinnahmt worden war. Gegen den Maintainer wurde über mehr als ein Jahr psychologische Kriegsführung betrieben, ohne dass der Maintainer oder sonst jemand es bemerkte.
    Das klingt wie aus einem Spionageroman, und wenn so etwas möglich ist, fragt man sich, was gerade in anderen Projekten vor sich geht.
    Auch im Backdoor-Code selbst zeigt sich dieselbe Denkweise. Es ging nicht nur darum, harmlos zu wirken, sondern über Commit-Messages, Kommentare, Variablennamen, die Wahl von Befehlen usw. aktiv eine Erzählung darüber aufzubauen, was der Code oberflächlich betrachtet tut, während er in Wirklichkeit etwas völlig anderes macht. Die Struktur bringt jemanden, der den Code zuerst anschaut, dazu, zunächst am eigenen Verständnis zu zweifeln, dann einen Bug zu vermuten und erst viel später Böswilligkeit in Betracht zu ziehen.

    • Das ist wirklich kaum zu glauben. Es mag nach Verschwörungstheorie klingen, aber ich frage mich auch, ob es nicht eine psychologische Operation in der realen Welt gab, die dazu führte, dass der ursprüngliche Autor keine Zeit mehr hatte und die Eigentümerschaft schließlich an einen schlechten Akteur abgab.
      Ich hoffe, dass irgendwelche Nachrichtendienste diesen Fall gründlicher untersuchen.
    • Ich hoffe, dass man daraus eine Lehre zieht. In Wirklichkeit passiert sehr viel. Unter den staatlich finanzierten Stellen und Schwarzmarktorganisationen weltweit gibt es viele, deren Aufgabe es ist, Backdoors zu beschaffen, und sie sind gut finanziert. Das ist ihr Job.
      Es ist frustrierend zu sehen, wie in jedem HN-Thread zu Backdoors diese Möglichkeit als Paranoia oder Aluhut-Denken abgetan und bestritten wird. Man tut so, als passiere so etwas nicht, dabei ist dies nur ein konkreter Fall, der erwischt wurde, und es gibt unzählige, die noch nicht entdeckt wurden.
      In diesem Fall war die Entdeckung noch vergleichsweise einfach, weil es ein Open-Source-Projekt war, und trotzdem war es Glück. Wenn man nun an Closed-Source-Produkte denkt, reduziert sich das Einbringen einer Backdoor darauf, eine Organisation zu infiltrieren oder unter Druck zu setzen. So etwas passiert häufig. Niemand will es glauben, aber es ist üblich. Wer in einem Unternehmen für technische Infrastruktur gearbeitet hat, dürfte ein paar Geschichten dazu kennen. Wegen NDAs oder noch schlimmeren Gründen ist es schwer, darüber zu sprechen, aber es passiert tatsächlich.
    • Ich stimme völlig zu, dass der Code jemanden dazu bringt, am eigenen Verständnis zu zweifeln. Das Ausmaß an Manipulation, Sorgfalt, Geduld und Hartnäckigkeit, das hier hineingeflossen ist, ist erstaunlich.
      Es könnte das Ergebnis der Besessenheit einer einzelnen Person sein, oder die Arbeit einer privaten Sicherheitsfirma oder eines staatlichen Akteurs, der solche Dinge von neun bis fünf für mehrere Projekte betreibt.
  • Es ist verständlich, dass sich die Aufmerksamkeit bisher darauf konzentriert hat, ob die Backdoor funktioniert und wie sie ihr Ziel erreicht.
    Trotzdem würde ich gern eine tiefere Analyse der Fehler und der überkonstruierten Teile sehen. In Bryan Cantrils Interview [1] sagt Andrés, das wirke wie ein Backdoor-Bauteil von der Stange, das nicht unbedingt mit Kenntnis des konkreten Distributionswegs gebaut wurde, und deshalb gebe es viele dumme Stellen. Ein Beispiel war die Symboltabellenabfrage, die ihn zur Untersuchung brachte.
    Ebenso frage ich mich, warum mit RC4 48 Bytes herausgeschnitten wurden [2].
    Ich würde gern hören, wie es mit mehr Zeit oder einem besseren Team besser hätte gebaut werden können – oder wo die Täter noch größere Fehler gemacht haben.
    [1] https://youtu.be/jg5F9UupL6I?si=gvXsYFXgagkGOMd4
    [2] https://twitter.com/matthew_d_green/status/17744729080201014...

  • Wenn ich es richtig verstanden habe, wäre eine sinnvolle Härtungsmaßnahme, jeder dynamisch gelinkten Bibliothek ihre eigene GOT zu geben und die Tabelle nach Abschluss des dynamischen Linkens als read-only zu markieren. Mit anderen Worten: Man könnte dann nicht über dynamische Grenzen hinweg ifunc-Einträge auf der anderen Seite patchen.
    Das könnte die Supply-Chain-Sicherheit von Code verbessern, der irgendwo gelinkt, aber nicht ausgeführt wird.
    Darüber hinaus wäre es vielleicht besser, ifunc deklarativ zu implementieren, damit beim Linken nicht in jeder Bibliothek beliebiger Code ausgeführt werden kann. Wegen Abwärtskompatibilität dürfte das heute schwer umzusetzen sein, aber langfristig scheint eine schrittweise, hierarchische Einführung möglich. Zum Beispiel könnte man eine Bibliothek mit einem Feature-Bit „deklaratives Link-ifunc“ bauen, und der dynamische Linker würde die Ausführung verweigern, wenn nicht alle verknüpften Bibliotheken dasselbe Feature-Flag haben.

    • Aus einem anderen Blickwinkel ist das Build-System das Problem.
      Derzeit laufen bei den meisten Library-Builds extrem komplexe und undurchsichtige Skripte, die eine Turing-vollständige Umgebung verlangen. Das gibt Angreifern eine endlose Angriffsfläche und schafft Gelegenheiten, wenn der Build-Prozess kompromittiert wird.
      Ein Wechsel zu einem deklarativen Build-Prozess, bei dem der Ausführer nur eine eingeschränkte Zustandsmaschine ist, würde helfen. Auch die Anforderung, dass jeder Quellcode-Brocken reproduzierbar sein muss, wäre überlegenswert.
    • Ja und nein, aber überwiegend nein. So ein Ansatz würde zwar verhindern, ifunc einfach auf diese Weise zu nutzen, aber der entscheidende Punkt ist, dass der Autor dieser Backdoor beliebigen Code in eine Bibliothek einschleusen konnte, die in den Adressraum eines sensiblen Prozesses gelangt.
      Ab diesem Zeitpunkt sind alle Abwehrmaßnahmen wirkungslos. Wenn er will, kann er die GOT wieder beschreibbar mappen, und selbst wenn ein solches Verhalten als „verdächtig“ erkannt würde oder das Betriebssystem die Umstellung verhindern könnte, kann der eingeschleuste Code den Kontrollfluss auf hunderte andere Arten umdrehen. Beliebiges Lesen/Schreiben, Codeausführung, alles ist möglich. Gegen eine Kompromittierung auf dieser Stufe gibt es keine Security-Mitigation. Wenn er will, kann er private Schlüssel exfiltrieren und direkt an den Angreifer senden oder eine Shell starten. In dieser Phase Schutzmechanismen entwerfen zu wollen, ist vergebliche Mühe.
    • Die Tabelle nach Abschluss des dynamischen Linkens als read-only zu markieren, funktioniert leider nicht. Dynamisches Linken erfolgt lazy, es gibt also keinen Moment, in dem es „abgeschlossen“ ist.
      Der korrekte Funktionszeiger wird erst beim ersten Aufruf geladen und statt des Stubs in die Tabelle eingetragen, und dieser Zeitpunkt kann beliebig weit in der Zukunft liegen. In großen Library-Ökosystemen wie etwa bei gtk-Apps werden die meisten gelinkten Funktionen tatsächlich nie aufgerufen.
    • Wenn man für die Host-Architektur baut, kann man ifunc ohne Nachteile vollständig abschalten. Unter Gentoo ist es üblich, mit -march=native zu bauen, und mit -multiarch in den USE-Flags von glibc lässt sich ifunc einfach deaktivieren. Negative Auswirkungen habe ich nicht gesehen.
    • Gibt es Programmiersprachen, die das Importieren von Libraries sandboxen können?
  • Zu den ersten drei Phasen fügt dieser Artikel gegenüber dem, was in den letzten zwei Wochen bekannt wurde, nicht viel hinzu. Eher eine gute Zusammenfassung mit Flussdiagramm.
    Neu wirkt allerdings der Teil, in dem das Binary derart detailliert analysiert wurde.
    Wie ist der dort gezeigte Quellcode entstanden? Hat man einen Disassembler laufen lassen, verstanden, was der Code tut, und dann alle Namen durch sprechende Namen ersetzt? Für etwas, das in zwei Wochen geschafft wurde, wirkt das wie eine beachtliche Leistung.

    • Der Autor ist GReAT.
      Global Research & Analysis Team, Kaspersky Lab
      https://securelist.com/author/great/
      Da der Verfasser offenbar das Malware-Analyseteam von Kaspersky Lab ist, ist die Wahrscheinlichkeit hoch, dass sie Binary-Reverse-Engineering ziemlich gut beherrschen.
    • Das in den weißen Screenshots verwendete Tool ist der Decompiler IDA Pro.
      https://hex-rays.com/ida-pro/
  • Was mich wirklich interessiert: Wodurch genau entstand die anfängliche SSH-Verzögerung, die die Untersuchung von xz ausgelöst hat? Hat das jemand herausgefunden?

    • Pro Verbindung wird zwar eine zusätzliche ECC-Operation ausgeführt, aber auf einer modernen CPU sollte das keine 500 ms dauern.
      Laut den Leuten, die den Code reverse-engineert haben, muss die Befehlsnachricht auch an den SSH-Host-Key gebunden werden. Wenn der Host-Key also ein RSA-Schlüssel war, könnte pro Verbindung zusätzlich auch eine RSA-Entschlüsselung ausgeführt worden sein.
      Das dürfte als Ursache für die Verzögerung ausreichen.
    • Das könnte absichtlich so gewesen sein.
      Es ist eine einfache Möglichkeit, von außen zu erkennen, ob ein Server infiziert ist, ohne zuerst eine Code-Injection versuchen zu müssen.
  • Die Autoren kennen sich extrem tief mit den Interna von glibc aus. Das ist Wissen, das man nur hat, wenn man bis zum Hals im Quellcode steckt, und es gibt viele neue Techniken.
    Der Custom-ELF-Parser und der Disassembler sind so komplex, dass man sich kaum vorstellen kann, dass dieser Code früher nicht schon anderswo eingesetzt wurde oder künftig nicht wiederverwendet wird.
    Ich frage mich, ob dieser Vorfall die ernsthafte Untersuchung bekommt, die er verdient, aber ich glaube eher nicht.

  • Hat jemand den Backdoor-Bug analysiert, der letztlich den Valgrind-Fehler und die Verlangsamung von SSH sichtbar gemacht hat?

    • Es scheint ein eindeutig fehlerhafter Speicherschreibzugriff gewesen zu sein: https://www.mail-archive.com/valgrind-users@lists.sourceforg...
      Der Valgrind-„Fix“ bestand darin, ifunc zu deaktivieren, wodurch die Backdoor deaktiviert wurde und der Fehler verschwand.
      Die Verlangsamung kam meines Wissens von all den Symbol- und Instruktions-Lookups, die die Backdoor durchführte.
  • Als Wendung betrachtet: Wenn man den Aufwand bedenkt, den der Angreifer in Skripten und Code betrieben hat, um Erkennung zu vermeiden, könnte dieses ganze Projekt auch eine Ablenkung gewesen sein oder ein Fallback, während parallel mehrere Versuche liefen.
    Wie bleibt man solchen Dingen einen Schritt voraus? Beeinflusst es andere Teile des Systems, wenn sich die Community auf SSHD konzentriert? Andere technische oder soziale Aspekte?
    Aluhüte machen Spaß.

    • Ich bin nicht optimistisch. Kaum jemand auditiert tatsächlich den Inhalt der Flatpak-Binaries auf Flathub. Wurden sie wirklich aus dem Source gebaut? Es läuft darauf hinaus, dass der Autor behauptet, das beweisen zu können. Ein so ausgefeilter Auslieferungsmechanismus wie bei dieser Backdoor könnte gar nicht nötig sein.
    • Man könnte alles selbst schreiben und ein dediziertes Team aus verifizierten Entwicklern haben.
      Oder man kauft Closed Source von einem Anbieter wie Microsoft und hofft, dass dort die Ressourcen und der Wille vorhanden sind, den Code strenger zu prüfen.
      Und es gibt natürlich immer den Ansatz, ein gutes Security-Operations-Team zu haben, das ungewöhnliche Netzwerkaktivität und Versuche zur Rechteausweitung erkennt.
    • Als Methode, ähnlichen Backdoors einen Schritt voraus zu sein, denke ich daran, sshd-Traffic in einen spiped-Tunnel zu kapseln. Spiped wird aus dem Source kompiliert und statisch gelinkt; die letzte stabile Version ist von 2021.
    • Meine Aluhut-Idee ist, Open-Source-Contributors misstrauisch zu betrachten. Nicht, weil sie aus einem bestimmten Land kommen, und auch nicht, weil man sie offenbar nie persönlich getroffen hat.
      Aber Contributors, die außerhalb des Projekts, an dem sie arbeiten, keine Historie und keine Spuren haben, sollten künftig als Warnsignal gelten.
    • Ein Aluhut ist nicht nötig. In FOSS-Projekte werden schon Backdoors eingeschleust, seit bevor sie berühmt wurden; der Unterschied diesmal ist, dass es ein staatlich unterstützter Akteur tut.
      Frühere Gruppen wie GOBBLES, ADM, ac1db1tch3z und ~el8 haben so etwas ebenfalls gemacht, ebenso private „Sicherheitsforscher“ wie isec.pl.
      Problematisch ist es diesmal, weil staatliche Akteure den Unternehmenskapitalismus ausnutzen, der eine Ära geschaffen hat, in der Basisprojekte für wenig Geld am Leben gehalten werden. Böswillige Akteure verfügen über praktisch unbegrenzte Ressourcen, um ihre Ziele zu erreichen.
      Das hat letztlich die Nachfrage nach und die Entstehung von Organisationen wie NSO und Zerodium geschaffen.
      Davor hatten Exploits und Backdoors kaum Wert, und Hacker hofften auf Sponsoring oder Anstellung bei Firmen wie Qualys.
  • Ich habe einige Analysen von Google zu Zero-Day-Hacks gesehen, und die waren ebenfalls unrealistisch beeindruckend, aber dieser Hack dürfte zu den größten aller Zeiten gehören.

  • Ich habe gesehen, dass das xz-Repository wieder auf GitHub ist und Lasse sowie ein neuer Contributor aufräumen. Sie haben die ifunc-Unterstützung entfernt und Code zur Erzeugung der Testdateien ins Repository committet, damit Testdateien ohne Blob erstellt werden können. Es sieht so aus, als würden sie in eine gute Richtung arbeiten.