Skip to content
KitploitKITPLOIT
StrumentiBlog
Log in
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

FeedContattoPrivacy© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
Strumenti/GitHubGitHub/chenaotian/cve-2022-0847
Escalation di PrivilegiAnalisi delle VulnerabilitàExploitApprendimento e FormazioneBinary ExploitationLab e Pratica
GitHubchenaotian/cve-2022-0847

CVE-2022-0847

Exploit proof-of-concept e analisi dettagliata della vulnerabilità CVE-2022-0847 (Dirty Pipe) di escalation dei privilegi del kernel Linux, incluso un ambiente Docker per test e debug.

Vedi Repository
257674 anni faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

Analisi dell'elevazione dei privilegi nel kernel Linux CVE-2022-0847 Dirty Pipe

[toc]

Questo articolo è stato pubblicato per la prima volta sul account pubblico WeChat di Huawei Security, questa è la versione blog (più completa)

Link originale: https://mp.weixin.qq.com/s/6VhWBOzJ7uu80nzFxe5jpg

Introduzione alla vulnerabilità

ID vulnerabilità: CVE-2022-0847 (alias: Dirty Pipe)

Prodotto affetto: kernel Linux - syscall splice

Versioni interessate: Linux 5.8 patch f6dd975583bd introdotta ~ riparata in 5.16.11, 5.15.25, 5.10.102

Danno: possibilità di scrivere fino a una pagina di contenuto (sufficiente) su qualsiasi file leggibile, consentendo l'elevazione locale dei privilegi.

Configurazione dell'ambiente

Docker per analisi vulnerabilità: chenaotian/cve-2022-0847 (se non ancora accessibile significa che non l'ho ancora caricato)

Fornisce:

  • Kernel compilato vulnerabile e debuggabile 5.13
  • qemu, gdb, sorgenti del kernel Linux 5.13
  • exp

Avvio:

cd ~/cve-2022-0847
gcc exp.c -o exp --static && cp exp ./rootfs && cd rootfs
find . | cpio -o --format=newc > ../rootfs.img
cd ../ 
./boot.sh

Debug:

gdb ./vmlinux
target remote :10086
directory /root/linux-5.13
b do_splice
b copy_page_to_iter_pipe 
b pipe_write
ignore 3 15
...
p *(struct pipe_inode_info *) pipe
p (struct pipe_buffer)pipe->bufs[0]

Principio della vulnerabilità

Il principio sintetico della vulnerabilità è che chiamando la funzione splice, è possibile inviare un file a una pipe in modalità "zero-copy". A livello di codice, la zero-copy consiste nell'utilizzare direttamente la cache di pagina del file (page cache) come pagina buf della pipe. Tuttavia, qui è stata introdotta una vulnerabilità di variabile non inizializzata, che consente di modificare successivamente la pagina della cache del file attraverso il canale pipe trattandola come una normale pagina pipe, permettendo così la sovrascrittura. In questa situazione, il kernel non considera questa pagina cache come "sporca" e non la scrive su disco per un breve periodo (fino al prossimo riavvio). Durante questo intervallo, tutti gli accessi a quel file utilizzeranno la pagina cache alterata, consentendo un'operazione di "scrittura arbitraria su qualsiasi file leggibile per un breve periodo". Ciò può portare all'elevazione locale dei privilegi.

Punto di occorrenza della vulnerabilità

Secondo la patch, il punto di occorrenza è nella funzione copy_page_to_iter_pipe, con l'aggiunta dell'inizializzazione di buf->flags. Quindi si tratta di una vulnerabilità di variabile non inizializzata.

image-20220308170149137

Il punto di chiamata di copy_page_to_iter_pipe si trova all'interno della chiamata di sistema splice. La funzione splice (chiamata di sistema) utilizza un metodo "zero-copy" per inviare il contenuto del file a una pipe, con prestazioni migliori rispetto al tradizionale invio diretto del contenuto del file. I dettagli verranno spiegati più avanti.

Principio della pipe e pipe_write

Innanzitutto, l'alias della vulnerabilità è "dirty pipe", quindi è utile comprendere la pipe. La pipe è un canale di comunicazione fornito dal kernel, creato tramite la funzione pipe/pipe2, che restituisce due descrittori di file: uno per inviare dati e l'altro per riceverli, simile a un tubo con due estremità. I dettagli d'uso non verranno approfonditi.

image-20220309124007780

Spiegazione breve dell'implementazione nel kernel: di solito, lo spazio totale della cache pipe è di 65536 byte, gestito in pagine, per un totale di 16 pagine (4096 byte ciascuna). Le pagine non sono contigue ma gestite tramite un array, formando una lista circolare. Vengono mantenuti due puntatori di lista: uno per scrivere (pipe->head) e uno per leggere (pipe->tail). Analizziamo principalmente la funzione pipe_write:

linux-5.13\fs\pipe.c : 400 : pipe_write

static ssize_t
pipe_write(struct kiocb *iocb, struct iov_iter *from)
{
	struct file *filp = iocb->ki_filp;
	struct pipe_inode_info *pipe = filp->private_data;
	unsigned int head;
	ssize_t ret = 0;
	size_t total_len = iov_iter_count(from);
	ssize_t chars;
	bool was_empty = false;
	bool wake_next_writer = false;

	··· ···
    ··· ···
	head = pipe->head;
	was_empty = pipe_empty(head, pipe->tail);
	chars = total_len & (PAGE_SIZE-1);
	if (chars && !was_empty) { 
        //[1] Se la cache pipe non è vuota, prova a scrivere "continuando" dall'ultima pagina corrente
		unsigned int mask = pipe->ring_size - 1;
		struct pipe_buffer *buf = &pipe->bufs[(head - 1) & mask];
		int offset = buf->offset + buf->len; 

		if ((buf->flags & PIPE_BUF_FLAG_CAN_MERGE) &&
		    offset + chars <= PAGE_SIZE) { 
            /*[2] Chiave: se il flag PIPE_BUF_FLAG_CAN_MERGE è presente, la pagina consente la scrittura continua
             *Se la lunghezza da scrivere non supera la pagina, scrive in coda; altrimenti inizia una nuova pagina */
			ret = pipe_buf_confirm(pipe, buf);
			···
			ret = copy_page_from_iter(buf->page, offset, chars, from);
			···
			}
			buf->len += ret;
			···
		}
	}

	for (;;) {//[3] Se non si può continuare dall'ultima pagina, inizia una nuova pagina
		··· ···
		head = pipe->head;
		if (!pipe_full(head, pipe->tail, pipe->max_usage)) {
			unsigned int mask = pipe->ring_size - 1;
			struct pipe_buffer *buf = &pipe->bufs[head & mask];
			struct page *page = pipe->tmp_page;
			int copied;

			if (!page) {//[4] Alloca una nuova pagina
				page = alloc_page(GFP_HIGHUSER | __GFP_ACCOUNT);
				if (unlikely(!page)) {
					ret = ret ? : -ENOMEM;
					break;
				}
				pipe->tmp_page = page;
			}

			spin_lock_irq(&pipe->rd_wait.lock);

			head = pipe->head;
			··· ···
			pipe->head = head + 1;
			spin_unlock_irq(&pipe->rd_wait.lock);

			/* Inserisce nell'array dei buffer */
			buf = &pipe->bufs[head & mask];
			buf->page = page;//[5] Inserisce la nuova pagina nell'array di pagine
			buf->ops = &anon_pipe_buf_ops;
			buf->offset = 0;
			buf->len = 0;
			if (is_packetized(filp))
				buf->flags = PIPE_BUF_FLAG_PACKET;
			else
				buf->flags = PIPE_BUF_FLAG_CAN_MERGE;
            	//[6] Imposta il flag, per default PIPE_BUF_FLAG_CAN_MERGE
			pipe->tmp_page = NULL;

			copied = copy_page_from_iter(page, 0, PAGE_SIZE, from); 
            //[7] Operazione di copia
			··· ···
			ret += copied;
			buf->offset = 0;
			buf->len = copied;

			··· ···
		}
        ··· ···
    }
	··· ···
	return ret;
}
  1. Se la pipe corrente non è vuota (head==tail indica pipe vuota), significa che ci sono dati non ancora letti. Ottiene il puntatore head, cioè l'ultima pagina usata per scrivere, ne esamina len e offset (per trovare la fine dei dati). Quindi tenta di continuare a scrivere nella pagina corrente.
  2. Controlla se la pagina corrente ha il flag PIPE_BUF_FLAG_CAN_MERGE: se non presente, non consente la scrittura continua. Inoltre, se la concatenazione dei dati eccede una pagina (operazione di scrittura oltre i limiti di pagina), non può continuare.
  3. Se non può continuare dall'ultima pagina, inizia una nuova pagina.
  4. alloc_page alloca una nuova pagina.
  5. Posiziona la nuova pagina all'inizio dell'array (potrebbe sostituire una pagina esistente), inizializza i valori.
  6. buf->flag viene inizializzato per default a PIPE_BUF_FLAG_CAN_MERGE, perché per default la pagina consente la scrittura continua.
  7. Copia i dati scritti; se non finito, ripete le operazioni sopra.
Scarica lo strumento