Was ist eine Backdoor? Wir erstellen eine mit Node.js
19. März 2020
0 Min. LesezeitEine Backdoor in unserem Code, die OS-Injection ausführen kann, ist eines der schlimmsten Szenarien überhaupt. Aktuell sind auf npm mehr als 1,2 Millionen öffentliche Pakete verfügbar. In den vergangenen drei Jahren sind unsere Abhängigkeiten zum perfekten Ziel für Cyberkriminelle geworden. Wir haben viele neue Angriffe beobachtet, die gestartet wurden, etwa Typosquatting-Angriffe oder den Vorfall mit event-stream. Sie zeigen, wie anfällig unser Ökosystem sein kann, wenn wir keine stärkere Community aufbauen. In diesem Beitrag zeige ich Ihnen, wie wir einige Techniken kombinieren und so eine bösartige Backdoor in das Ökosystem einschleusen können.
Was ist eine Backdoor?
In der Cybersicherheit bezeichnet eine Backdoor jede Methode, mit der autorisierte oder nicht autorisierte Nutzer normale Sicherheitsmaßnahmen umgehen und sich weitreichende Benutzerrechte (auch Root-Zugriff genannt) auf einem Computersystem, Netzwerk oder in einer Softwareanwendung verschaffen können. Sobald sie Zugriff haben, können Cyberkriminelle über eine Backdoor persönliche und Finanzdaten stehlen, zusätzliche Malware installieren und Geräte kapern.
Jede Backdoor besteht aus zwei wesentlichen Komponenten: der Malware, die auf dem Opfergerät eingeschleust und ausgeführt wird, und einem offenen Kommunikationskanal, über den der Angreifer Befehle senden und den Remote-Host steuern kann.
Nach der Installation einer Backdoor müssen bestimmte Befehle gesendet werden, damit sie auf dem Zielcomputer ausgeführt werden. Diese Befehle können vertrauliche Informationen wie Umgebungsvariablen oder Datenbankabfragen exfiltrieren. Außerdem können sie andere Prozesse auf dem Computer oder im Netzwerk verändern – abhängig von den Ausführungsberechtigungen der infizierten Node-Anwendung.
Für eine vereinfachte Version dieses Angriffs verwenden wir die Core-Bibliothek child_process zur Codeausführung und einen HTTP-Server als Kommunikationskanal. In diesem Fall empfehle ich Express, da es das am weitesten verbreitete Framework ist. Der Ansatz lässt sich jedoch auch auf andere Frameworks übertragen.
Vergessen Sie nicht, Ihre Projekte auf bekannte Backdoors zu testen!
Wie kann uns child_process dabei helfen?
Mit dem Node.js-Core-Modul child_process können wir untergeordnete Prozesse ausführen. Dabei führen Sie einen Befehl aus (diese Eingabe nennen wir stdin), etwa pwd oder ping snyk.io, und verarbeiten anschließend die Antwort (diese Ausgabe nennen wir stdout) sowie mögliche Fehler (diese nennen wir stderr) in Ihrem Hauptprogramm.
Es gibt mehrere Möglichkeiten, untergeordnete Prozesse auszuführen. Für diesen Angriff ist exec die einfachste. Damit wird nach Abschluss des Prozesses ein Callback mit stdout und stderr ausgeführt, etwa bei cat passwords.txt. Beachten Sie, dass exec für lang laufende Aufgaben wie ping snyk.io nicht die beste Wahl ist.
Wie verbinden wir diesen exec-Aufruf mit dem HTTP-Server?
Ich habe ein einfaches, harmlos wirkendes Middleware-Paket entwickelt, das alle Nutzer, die nicht Chrome verwenden, auf eine andere URL wie browsehappy.com weiterleitet. Die bösartige Payload füge ich in die Middleware ein.
Der erwartete Code im Paket sieht etwa so aus:
Das Opfer muss also lediglich die Bibliothek browser-redirect installieren und wie eine gewöhnliche Middleware in die Express-App einbinden:
Beachten Sie: In diesem Fall bleibt Ihre Anwendung selbst dann verwundbar, wenn Sie Helmet verwenden.
So implementieren Sie die bösartige Payload
Die Implementierung ist ganz einfach:
Wie funktioniert die Backdoor? Sie müssen drei Herausforderungen verstehen:
Sie benötigen eine Möglichkeit, sich zu authentifizieren, damit andere Cyberkriminelle Ihre Backdoors nicht selbst verwenden können. In diesem Fall verwenden wir einen MD5-Hash (das Wort
p@ssw0rd1234ergibt diesen Hash:c4fbb68607bcbb25407e0362dab0b2ea). Fügen Sie diesen Hash als Wert Ihresknock_kock-Headers für die Authentifizierungsprüfung ein.Sie benötigen eine Möglichkeit, Server mit dem bösartigen Code zu identifizieren. Da wir keine Metriken erfassen wollten, fügen wir der Serverantwort einen zusätzlichen Header hinzu:
Content-Sec-Policy– er sieht demContent-security-policy-Header sehr ähnlich, ist aber nicht derselbe. Auch hier nutzen wir den Typosquatting-Angriff aus. Jetzt können wir unsere Ziele mit dieser Abfrage auf Shodan finden:/search?query=Content-Sec-Policy%3A+default-src+%27self%27Mit dem Query-Parameter ?cmd können wir über jede Route Befehle auf dem infizierten Server ausführen – zum Beispiel
victim.com/?cmd=whoamioder?cmd=cat .env– und erhalten alle Informationen im JSON-Format.
Da die bösartige Payload nun bereit ist, müssen wir eine geeignete Methode finden, das bösartige Paket zu verbreiten.
Verbreitungswege
Der erste Schritt besteht darin, das bösartige Paket im Internet zu veröffentlichen. Ich habe das Paket gerade mit npm install browser-redirect@1.0.2 auf npm veröffentlicht. Auf GitHub ist der bösartige Code jedoch nicht zu sehen – siehe Master Branch und Release 1.0.2. Der Grund dafür ist, dass npm keinen Abgleich mit GitHub oder anderen Versionskontroll-Repositories durchführt.
Vorerst ist die Wahrscheinlichkeit gering, dass sich diese Backdoor im Ökosystem verbreitet, da das bösartige Paket erst beworben und von anderen installiert werden muss.
Eine weitere Möglichkeit zur Verbreitung besteht darin, das bösartige Modul als Abhängigkeit in andere Pakete aufzunehmen. Hat der Angreifer Veröffentlichungsberechtigungen für andere wichtige Pakete, kann er eine neue Version mit dem bösartigen Paket als direkter Abhängigkeit veröffentlichen (lesen Sie die Nachbetrachtung zum Vorfall mit event-stream). Alternativ kann er versuchen, einen Pull Request mit bösartigen Ressourcen in der Lockfile zu einem Projekt beizutragen, wie in der Untersuchung zur Lockfile-Sicherheit beschrieben: Abhängigkeit in der package-lock-Datei.
Ein weiterer wichtiger Faktor ist, ob die Angreifer Zugriff auf Zugangsdaten (Benutzername und Passwort) eines relevanten Maintainers erhalten können. Ist das der Fall, können sie problemlos neue Versionen beliebter Pakete veröffentlichen, wie es in der Vergangenheit bei eslint geschehen ist.
Selbst wenn der Maintainer für die Authentifizierung und Veröffentlichung die Zwei-Faktor-Authentifizierung (2FA) verwendet, besteht weiterhin ein Risiko. Entscheidet sich ein Maintainer für CI, um neue Versionen bereitzustellen, muss die 2FA für Veröffentlichungen deaktiviert werden. Kann der Angreifer also ein gültiges npm-Token für CI stehlen – etwa aus weitergegebenen oder öffentlich zugänglichen Logs oder durch Datenlecks –, kann er neue Releases mit bösartigem Code veröffentlichen.
Beachten Sie, dass npm eine neue API veröffentlicht hat (private Betaversion), die anzeigt, ob ein Paket von einer TOR-IP-Adresse aus veröffentlicht und ob dabei 2FA verwendet wurde.
Außerdem können Angreifer die bösartige Payload so anpassen, dass sie als Preinstall- oder Postinstall-Skript in beliebigen npm-Paketen ausgeführt wird. Standardmäßig verfügen npm-Pakete über einen Lifecycle-Hook, mit dem sich zu verschiedenen Zeitpunkten Code auf Ihrem Computer ausführen lässt. Das Browser-Testpaket Puppeteer nutzt diesen Lifecycle-Hook beispielsweise, um Chromium auf dem Hostcomputer zu installieren. Ryan Dahl hat diese Sicherheitslücken bereits auf der JSConf EU 2018 erläutert. Node.js muss abgesichert werden, um diesen und viele weitere Angriffsvektoren zu verhindern.
Denken Sie daran:
78 % der Schwachstellen stecken in indirekten Abhängigkeiten, was ihre Behebung komplex macht.
Die Zahl der Schwachstellen in Anwendungsbibliotheken ist innerhalb von zwei Jahren um 88 % gestiegen.
81 % sind der Meinung, dass Entwickler für die Sicherheit verantwortlich sein sollten, doch sie sind dafür nicht ausreichend gerüstet.
Quelle: The State of Open Source Security – 2019. Lesen Sie unseren neuen Bericht zum Thema Open-Source-Sicherheit – 2020
Wie lässt sich dieser Angriff abwehren?
Es ist nicht immer einfach, unsere Abhängigkeiten im Blick zu behalten. Doch diese Tipps können Ihnen dabei helfen:
Verwenden Sie bekannte und gut gepflegte Bibliotheken.
Engagieren Sie sich in der Community und unterstützen Sie Maintainer, indem Sie Code beitragen oder Projekte und ihre Maintainer finanziell fördern.
Verwenden Sie NQP, um neue Pakete für Ihr Projekt zu bewerten.
Nutzen Sie Snyk, um über neue Schwachstellen auf dem Laufenden zu bleiben und Ihre Projekte zu überwachen.
Prüfen Sie den Code Ihrer npm-Abhängigkeiten direkt in npm und nicht nur auf GitHub, Bitbucket oder anderen Versionskontrollsystemen.
Lehren aus früheren Vorfällen
Erstellen Sie noch heute kostenlos ein Snyk-Konto und testen Sie Ihre Projekte auf bekannte Backdoors.
Starten Sie mit Capture the Flag
Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Herausforderungen lösen.
