Vulnerabilità root nel kernel Linux e negazione del servizio in systemd

I ricercatori di sicurezza di Qualys hanno rivelato i dettagli di due vulnerabilità che colpiscono il kernel Linux e il gestore di sistema systemd. Una vulnerabilità nel kernel (CVE-2021-33909) consente a un utente locale di ottenere l'esecuzione di codice con diritti di root attraverso la manipolazione di directory altamente nidificate.

Il pericolo della vulnerabilità è aggravato dal fatto che i ricercatori sono stati in grado di preparare exploit funzionanti che funzionano su Ubuntu 20.04/20.10/21.04, Debian 11 e Fedora 34 nella configurazione predefinita. Va notato che altre distribuzioni non sono state testate, ma teoricamente sono anch'esse soggette al problema e possono essere attaccate. Si prevede che il codice completo dell'exploit sarà pubblicato dopo che il problema sarà stato eliminato ovunque, ma per ora è disponibile solo un prototipo con funzionalità limitate, che causa il crash del sistema. Il problema è presente da luglio 2014 e interessa le versioni del kernel a partire dalla 3.16. La correzione della vulnerabilità è stata coordinata con la comunità e accettata nel kernel il 19 luglio. Le principali distribuzioni hanno già generato aggiornamenti ai propri pacchetti kernel (Debian, Ubuntu, Fedora, RHEL, SUSE, Arch).

La vulnerabilità è causata dal mancato controllo del risultato di una conversione da size_t a int prima di eseguire operazioni nel codice seq_file, che crea file da una sequenza di record. Il mancato controllo potrebbe comportare scritture fuori dai limiti nel buffer durante la creazione, il montaggio e l'eliminazione di una struttura di directory molto nidificata (dimensione del percorso maggiore di 1 GB). Di conseguenza, un utente malintenzionato può ottenere una stringa di 10 byte "//deleted" scritta con un offset di "-2 GB - 10 byte" che punta all'area immediatamente precedente al buffer allocato.

L'exploit preparato richiede 5 GB di memoria e 1 milione di inode gratuiti per funzionare. L'exploit funziona chiamando mkdir() per creare una gerarchia di circa un milione di sottodirectory per raggiungere una dimensione del percorso del file superiore a 1 GB. Questa directory viene montata tramite bind-mount in uno spazio dei nomi utente separato, dopodiché viene eseguita la funzione rmdir() per rimuoverla. Parallelamente viene creato un thread che carica un piccolo programma eBPF, il quale viene bloccato nella fase successiva al controllo dello pseudocodice eBPF, ma prima della sua compilazione JIT.

Nello spazio dei nomi dell'id utente non privilegiato, viene aperto il file /proc/self/mountinfo e viene letto il percorso lungo della directory montata su bind, con il risultato che la stringa "//deleted" viene scritta nell'area prima dell'inizio del buffer. La posizione per scrivere la riga viene scelta in modo tale da sovrascrivere l'istruzione nel programma eBPF già testato ma non ancora compilato.

Successivamente, a livello di programma eBPF, la scrittura incontrollata fuori dal buffer viene trasformata in capacità controllata di leggere e scrivere su altre strutture del kernel attraverso la manipolazione delle strutture btf e map_push_elem. Di conseguenza, l'exploit determina la posizione del buffer modprobe_path[] nella memoria del kernel e sovrascrive al suo interno il percorso "/sbin/modprobe", che consente di avviare l'avvio di qualsiasi file eseguibile con diritti di root in caso di request_module(), che viene eseguita, ad esempio, durante la creazione del socket netlink.

I ricercatori forniscono diverse soluzioni alternative che sono efficaci solo per un exploit specifico, ma non eliminano il problema stesso. Si consiglia di impostare "/proc/sys/kernel/unprivileged_userns_clone" su 0 per disabilitare il montaggio delle directory in uno spazio dei nomi ID utente separato e "/proc/sys/kernel/unprivileged_bpf_disabled" su 1 per disabilitare il caricamento dei programmi eBPF nel kernel.

È interessante notare che, analizzando un attacco alternativo che prevedeva l’uso del meccanismo FUSE invece del bind-mound per montare una directory di grandi dimensioni, i ricercatori si sono imbattuti in un’altra vulnerabilità (CVE-2021-33910) che colpisce il gestore di sistema systemd. Si è scoperto che quando si tenta di montare una directory con una dimensione del percorso superiore a 8 MB tramite FUSE, il processo di inizializzazione del controllo (PID1) esaurisce la memoria dello stack e si blocca, mettendo il sistema in uno stato di "panico".

Il problema è che systemd traccia e analizza il contenuto di /proc/self/mountinfo ed elabora ogni punto di montaggio nella funzione unit_name_path_escape(), che esegue un'operazione strdupa() che inserisce i dati nello stack anziché nella memoria allocata dinamicamente . Poiché la dimensione massima dello stack è limitata tramite RLIMIT_STACK, l'elaborazione di un percorso troppo grande verso il punto di montaggio provoca l'arresto anomalo del processo PID1 e l'arresto del sistema. Per un attacco, è possibile utilizzare il modulo FUSE più semplice in combinazione con l'utilizzo di una directory altamente nidificata come punto di montaggio, la cui dimensione del percorso supera gli 8 MB.

Il problema si presenta da systemd 220 (aprile 2015), è già stato risolto nel repository principale di systemd e risolto nelle distribuzioni (Debian, Ubuntu, Fedora, RHEL, SUSE, Arch). In particolare, nella versione 248 di systemd l'exploit non funziona a causa di un bug nel codice di systemd che causa il fallimento dell'elaborazione di /proc/self/mountinfo. È anche interessante notare che nel 2018 si è verificata una situazione simile e durante il tentativo di scrivere un exploit per la vulnerabilità CVE-2018-14634 nel kernel Linux, i ricercatori Qualys si sono imbattuti in tre vulnerabilità critiche in systemd.

Fonte: opennet.ru

Aggiungi un commento