Xzbot: Notizen, Honeypot und Exploit-Demo für die xz-Backdoor
(github.com/amlweems)- xzbot ist ein Repository zur Untersuchung der xz-Backdoor (CVE-2024-3094) und bietet zusammen ein Honeypot, einen ED448-Public-Key-Patch, das Backdoor-Payload-Format und eine Demo für Remote Code Execution.
- Das Honeypot wendet einen einfachen Patch auf OpenSSH an und protokolliert Verbindungsversuche mit einem Public-Key-
N-Wert, der zum Backdoor-Format passt, in densshd-Logs. - Der ED448-Patch ersetzt den von der Backdoor für Signaturprüfung und Payload-Entschlüsselung verwendeten hartkodierten Public Key durch einen vom Benutzer erzeugten Schlüssel, sodass sich die Backdoor triggern lässt.
- Die Backdoor-Payload steckt im
N-Wert des CA-Signaturschlüssels eines SSH-Zertifikats; sie erzeugt den Request-Typ mita * b + c, und Typ 2 führt einen nullterminierten Befehl mitsystem()aus. - Die Demo-CLI zeigt den Ablauf, wie nach einer Verbindung zu einem verwundbaren SSH-Server ein Befehl ausgeführt wird; ein erfolgreicher Exploit erzeugt keine Logs auf INFO-Level oder höher.
Umfang und Aufbau von xzbot
- xzbot ist ein Projekt zur Untersuchung der xz-Backdoor CVE-2024-3094.
- Es umfasst vier Bestandteile:
- honeypot: ein gefälschter verwundbarer Server zur Erkennung von Exploit-Versuchen
- ed448 patch: patcht
liblzma.so, damit ein eigener ED448-Public-Key verwendet wird - backdoor format: Dokumentation des Backdoor-Payload-Formats
- backdoor demo: eine CLI, die unter der Annahme, dass der ED448-Private-Key bekannt ist, RCE auslöst
Honeypot: Versuche per OpenSSH-Patch erkennen
- openssh.patch ist ein einfacher Patch für OpenSSH, der Verbindungsversuche mit einem Public-Key-N-Wert, der zum Backdoor-Format passt, protokolliert.
- Der Ablauf besteht darin,
openssh-portablezu klonen, den Patch anzuwenden und anschließendautoreconf,configureundmakeauszuführen. - Verbindungsversuche erscheinen in den
sshd-Logs alsxzbot: magic 1 [preauth]zusammen mit den Payload-Bytes.
ED448-Public-Key-Patch
- Die Backdoor verwendet einen hartkodierten ED448-Public-Key für die Signaturprüfung und die Payload-Entschlüsselung.
- Wenn dieser Public Key durch einen Schlüssel ersetzt wird, den der Benutzer besitzt, lässt sich die Backdoor triggern.
- Das Repository zeigt sowohl den ED448-Public-Key des Angreifers als auch einen alternativ erzeugten Public Key mit
seed=0. - Der erste Schritt ist die Bereitstellung des Shared Objects
liblzma.so.5.6.1, das die Backdoor enthält.- Als Beispielquelle wird ein Debian-Snapshot von
xz-utils 5.6.1-1genannt. - Nach der Installation von
pwntoolserzeugtpatch.py liblzma.so.5.6.1die Dateiliblzma.so.5.6.1.patch. - Anschließend wird
sshdmit dem modifizierten Shared Objectliblzma.so.5.6.1.patchausgeführt.
- Als Beispielquelle wird ein Debian-Snapshot von
- Unter assets gibt es ein Beispiel.
Format der Backdoor-Payload
- Die Backdoor kann beim Verbindungsaufbau mit einem SSH-Zertifikat getriggert werden, indem die Payload in den N-Wert des CA-Signaturschlüssels eingebettet wird.
- Diese Payload muss mit dem ED448-Key des Angreifers verschlüsselt und signiert werden.
- Die äußere Struktur besteht aus den folgenden Feldern:
a: 32 Bitb: 32 Bitc: 64 Bitciphertext: 240 Byte
- Der Request-Typ wird aus
a * b + cabgeleitet.- Ist der Wert größer als 3, überspringt die Backdoor die Verarbeitung.
- Typ 1: Zweck unbekannt und erwartet 0 Byte
- Typ 2: führt eine nullterminierte Payload mit
system()aus - Typ 3: Zweck unbekannt und erwartet 48 Byte Signaturdaten
ciphertextwird mit chacha20 verschlüsselt, wobei die ersten 32 Byte des ED448-Public-Keys als symmetrischer Schlüssel dienen.- Deshalb können Exploit-Versuche mit dem angegebenen 32-Byte-Schlüssel entschlüsselt werden.
- Im entschlüsselten
ciphertextbefinden sich eine 114-Byte-Signatur, 1-Bit-Felderxundy, eine Länge, eine Befehlszeichenkette und weitere Daten.- Wenn
xoderygesetzt ist, führt das in leicht unterschiedliche Codepfade.
- Wenn
- Die Signatur ist eine ED448-Signatur nach RFC-8032.
- Die Eingabe umfasst einen 32-Bit-Magic-Wert, ein 5-Byte-Feld vor dem Befehl, optional
lengthByte des Befehls und die ersten 32 Byte des SHA-256-Hashes des Server-Hostkeys.
- Die Eingabe umfasst einen 32-Bit-Magic-Wert, ein 5-Byte-Feld vor dem Befehl, optional
Exploit-Demo-CLI
- Die CLI wird mit Go installiert.
go install github.com/amlweems/xzbot@latest
xzbot -hzeigt drei zentrale Optionen:-addr: Adresse des SSH-Servers, Standardwert127.0.0.1:2222-seed: ED448-Seed, der zum xz-Backdoor-Key passen muss, Standardwert0-cmd: Befehl, der mitsystem()ausgeführt wird, Standardwertid > /tmp/.xz
- Das Beispiel verbindet sich mit einem verwundbaren SSH-Server auf
127.0.0.1:2222und führt den Befehlid > /tmp/.xzaus. - Wenn auf dem verwundbaren Server am Aufrufpunkt von
system()ein Watchpoint gesetzt wird, ist zu sehen, wie dersshd-Prozessid > /tmp/.xzausführt. - Nach der Ausführung zeigt das Beispiel, dass in
/tmp/.xzdie Ausgabeuid=0(root) gid=0(root) groups=0(root)steht.
Prozessbaum und Log-Eigenschaften
- Der Prozessbaum einer normalen SSH-Verbindung führt von
sshdzur Benutzersitzung und zur Shell. - Im Beispiel der Backdoor-Ausführung erscheinen nach
xzbot -cmd 'sleep 60'die Prozessesshd: root [priv],sshd: root [net],sh -c sleep 60undsleep 60. - Ein erfolgreicher Exploit erzeugt keine Log-Einträge auf INFO-Level oder höher.
1 Kommentare
Hacker-News-Kommentare
Ziemlich interessant ist, dass daraus keine Remote Code Execution wurde, die jeder missbrauchen kann, sondern dass der private Schlüssel des Angreifers erforderlich ist.
Ironischerweise wirkt es wie eine sehr sicherheitsbewusste Schwachstelle.
Hätte man ein großes Loch gelassen, durch das jeder hineinkommt, wäre es schnell entdeckt und geschlossen worden; und ohne Performance-Einbußen hätte sie möglicherweise lange unbemerkt überlebt, gerade weil sie nicht breit ausnutzbar war.
Die gesamte Mitarbeit an xz wirkt letztlich wie Vorarbeit, um diese Backdoor einzubauen; dazu wurde zum Beispiel sogar ein Test-Framework geschaffen, in dem sich ein bösartiger Payload verstecken ließ.
Vor der Arbeit an xz gab es auch Beiträge zu BSDs libarchive, wo dann eine Schwachstelle entstand.
Design und Ausführung waren extrem ausgefeilt, und dass ein Performance-Problem zur Entdeckung führte, wirkt fast wie reines Glück.
Falls ja, kann man ihn nicht einfach wahllos auf Server verteilen, und schon das Senden an einen einzelnen Host ist rechnerisch ziemlich aufwendig.
Dieser Vorfall ging mir das ganze Wochenende nicht aus dem Kopf.
Der Mechanismus ist faszinierend und eine beeindruckende Sammlung von Obfuskation; der Social-Engineering-Teil ist Open-Source-Maintainern beschämend vertraut.
Am interessantesten ist, dass als Angriffsvektor schlechte Testdaten gewählt wurden: Wenn man ein gutes Archiv vorbereitet, strukturell manipuliert und es dann als schlechte Daten für Fuzz-Tests verwendet, werden die übrigen Schritte enorm einfach.
Für später festgehalten: Solche Manipulationen sollten in Graphen binärer Muster sichtbar werden.
Die übrigen Techniken waren, sobald der Payload feststand, weitgehend gewöhnliche Obfuskation; der wirklich brillante Zug war aber, dass man nach demselben Muster unbemerkt „Patches“ oder sogar neue Backdoors in andere Testdateien hätte einfügen können.
Dass GitHub das Repository versteckt und entfernt hat, war überhaupt nicht hilfreich und behindert die Analyse dieses Vorfalls.
Dabei habe ich festgestellt, dass diese Abhängigkeit xz auffällig bevorzugt und, falls es nicht installiert ist, als Komfortfunktion sogar xz auf der Host-Maschine installiert.
Bei anderen Abhängigkeiten verhält sie sich nicht so, was etwas seltsam ist.
Solche Langzeitoperationen sind beängstigend, und bis tatsächlich etwas „Böses“ ausgeführt wird, kann man nicht wissen, was bösartig und was nur merkwürdig ist.
Besonders wenn es sich um eine Datei mit „binärem Müll“ handelt, die einen Testfehler belegen soll, ist das ein perfekter Ort, um bösartige Inhalte zu verstecken.
Es ist sehr beeindruckend, wie schnell die Community, insbesondere amlweems, Proof-of-Concept-Code umgesetzt und dokumentiert hat.
Wenn es keine zusätzlichen Schwachstellen in der Kryptofunktion oder beim Laden des Payloads gibt, hat das möglicherweise nicht allen anderen Angreifern eine Sicherheitslücke geöffnet, solange der Schlüssel nicht geknackt wird.
Der nächste Schritt wäre, eine Methode zur Erkennung verwundbarer Distributionen zu finden; das sieht nicht einfach aus. Außerdem könnte man upstream eine Möglichkeit einbauen, zu überwachen, ob jemand mit dem hartcodierten Schlüssel aktiv SSH-Server abscannt.
Ein Proof of Concept für die Originalversion würde den nicht veröffentlichten privaten Schlüssel des Angreifers erfordern.
Das Beste, was man tun kann, wäre feineres Benchmarking; aber bei einem beliebigen Internet-Host weiß man nicht, ob er langsam ist, weil er verwundbar ist, weil er weit entfernt ist oder weil der Rechner selbst langsam ist.
Man hat auch keinen Zugriff darauf, wie lange frühere Verbindungsversuche zu diesem Host gedauert haben, und Routing-Schwankungen kommen hinzu.
Ich frage mich, ob jemand diesen Proof of Concept schon gegen Tools zur Erkennung ungewöhnlichen Prozessverhaltens laufen ließ.
Produkte wie Carbon Black, AWS GuardDuty und Sysdig fallen darunter, und dieser Fall scheint ideal für diese Produktkategorie zu sein, um zu testen, ob jemand bei einer echten Ausrollung relativ schnell etwas bemerkt hätte.
GuardDuty schaut nicht wie EDR-Produkte à la CrowdStrike oder Carbon Black in Prozesse hinein, daher dürfte es schwer zu erkennen sein; Sysdig betrachtet Container und Cloud-Infrastruktur, daher scheint es schwierig, den Exploit selbst zu erwischen.
Allerdings besteht die Möglichkeit, nach einer Rechteausweitung bei den Folgeaktionen des Threat Actors Anomalien zu erkennen.
Am wahrscheinlichsten, den Exploit selbst zu erkennen, sind letztlich EDR-Lösungen, die Endpoint-Prozesse überwachen, oder eine Software-Supply-Chain-Bewertung, die Sicherheitsprobleme in upstream freier und Open-Source-Software überwacht.
Interessanterweise führt das zu einem größeren Sicherheitsthema.
Entwicklungsteams mögen es wegen Performance-Einbußen und Nutzererlebnisproblemen bei Isolationsmaßnahmen ungern, EDR auf Servern zu installieren, und sie mögen möglicherweise auch Richtlinien nicht, die die Nutzung freier und Open-Source-Software einschränken.
Dieser Exploit trifft mitten in eine organisatorische „Schwachstelle“, und je nach Position gibt es Argumente sowohl dafür, die Exponierung beizubehalten, als auch dafür, sie zu beheben.
Dort hieß es: „Eine Methode der Runtime-Erkennung besteht darin, zu überwachen, ob SSHD eine bösartige Bibliothek lädt. Solche Shared Libraries enthalten häufig die Version im Dateinamen.“
Der Blog enthält auch konkrete Erkennungsregeln, die ich bei anderen Sicherheitsanbietern nicht gesehen habe.
https://sysdig.com/blog/cve-2024-3094-detecting-the-sshd-bac...
Ich habe den Link unten falsch gelesen und lasse den ursprünglichen Inhalt der Dokumentation halber stehen.
Wenn man weiter unten im selben Mail-Thread schaut, hieß es, dass die Person, die die Backdoor committed hat, anscheinend kürzlich auch Kernel-Beiträge geleistet habe. Die Analyse im Original ist aber wirklich hervorragend, daher lohnt es sich, solche Texte zu lesen.
https://www.openwall.com/lists/oss-security/2024/03/29/10
Lasse selbst sagte auch, sie sei überhaupt nicht dringend und werde nicht in dieses Merge Window aufgenommen; kein vernünftiger Mensch stellt Lasse als böswilligen Akteur dar.
Dieser Fall hat absurd viele Ähnlichkeiten mit dem Audacity-Fall von vor einigen Jahren.
Cookie guy behauptete, er sei mit einem Messer angegriffen worden und die Bundespolizei sei in den Fall involviert gewesen; das deutet darauf hin, dass der Vorfall möglicherweise mit einem Akteur verbunden war, der weit größer ist als 4chan.
Damals dachten viele, es sei nur die Muse Group beteiligt gewesen, aber vielleicht war es auch ein russischer staatlicher Akteur.
Zuvor hatte er behauptet, Audacity enthalte viel Telemetrie und viele Backdoors, die er nach dem Fork im ersten Commit entfernt habe.
Vielleicht gibt es in Audacity tatsächlich eine Backdoor, also sollte man sich den Quellcode ansehen.
In letzter Zeit legen sie ihre Operationen mit APT29 zusammen, und ich würde cozy bear nicht aufwecken.
Mich würde interessieren, wie der echte Exploit das zur Laufzeit gemacht hat, ohne den Honeypot-
openssh.patchzur Compile-Zeit https://github.com/amlweems/xzbot/blob/main/openssh.patch.Die Kette war
opensshd -> systemd-Benachrichtigung -> xz als transitive Abhängigkeit; ich würde gern wissen, wieliblzma.so.5.6.1, nachdem es in den Speicher geladen war, bis zuopenssh_RSA_verifyzurückgegangen ist, um dort einen Hook oder Patch anzubringen.Wenn sie vor libcrypto geladen wird, registriert sie einen Symbol-Audit-Handler, vermutlich eine glibc-spezifische Funktion, und kann dadurch benachrichtigt werden, wenn die Symbole von libcrypto aufgelöst werden, um das GOT-Patching zu verzögern.
Ich frage mich, ob bekannt ist, ob dieser Exploit nur aktiv wurde, wenn eine SSH-Verbindung einging.
Die String-Liste auf GitHub enthält
DISPLAYundWAYLAND_DISPLAY.https://gist.github.com/q3k/af3d93b6a1f399de28fe194add452d01
Diese haben keinen offensichtlichen Bezug zu SSH, daher ist es möglich, dass er auch ohne Verbindung irgendetwas getan hat.
Das könnte wichtig sein für Leute, die den Code ausgeführt haben, aber annehmen, sicher zu sein, weil sie den SSH-Server nicht ins Internet exponiert haben.
Also ein Mechanismus, um Situationen zu vermeiden, in denen jemand ihn entdecken, reproduzieren oder debuggen will.
Wenn man es beim Verbinden mit einer nicht vertrauenswürdigen Maschine nicht deaktiviert, ist es auf Client-Seite eine häufige Sicherheitslücke.
Ich frage mich, ob die Aussage „erfolgreiche Ausnutzung erzeugt keinen Log-Eintrag“ bedeutet, dass ein Angreifer, wäre dieser Exploit nicht entdeckt worden, auf einem kompromittierten Host beliebige Befehle als root hätte ausführen können, ohne dass es für diese „Verbindung“ auch nur einen sshd-Log-Eintrag gegeben hätte.
Die Remote-Code-Ausführung passiert in der Verbindungsphase, bevor Logs geschrieben werden.
Ich frage mich, welche Anomalieerkennung das hätte finden können.
Ich frage mich, ob man diesen Angriff hätte erschweren können, wenn man die Testdateien in ein separates Repository ausgelagert hätte, sodass sie zur Build-Zeit nicht verfügbar gewesen wären.
Die Logik ist: Alles, was am Build beteiligt sein kann, muss für Menschen lesbar sein.
Man sollte diesen Angriff wie einen Flugzeugunfall behandeln und neue Regeln einführen, die die Wahrscheinlichkeit verringern, dass so etwas erneut gelingt.
Auch wenn man nicht jeden einzelnen Contributor überprüfen kann, sollten sich rauschende Testdaten leicht abtrennen lassen.