Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2022-0847 — Exploit de preuve de concept et analyse détaillée de la vulnérabilité d'élévation de privilèges du noyau Linux CVE-2022-0847 (Dirty Pipe), incluant un environnement Docker pour les tests et le débogage. | Kitploit
Outils/GitHubGitHub/chenaotian/cve-2022-0847
Escalade de PrivilègesAnalyse des VulnérabilitésExploitationApprentissage et ÉducationExploitation de BinairesLabs et Pratique
GitHubchenaotian/cve-2022-0847

CVE-2022-0847

Exploit de preuve de concept et analyse détaillée de la vulnérabilité d'élévation de privilèges du noyau Linux CVE-2022-0847 (Dirty Pipe), incluant un environnement Docker pour les tests et le débogage.

Voir le dépôt
25766il y a 4 ansVérifié par Kitploit

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

CVE-2022-0847 Dirty Pipe analyse d'élévation de privilèges du noyau Linux

[toc]

Cet article a été initialement publié sur le compte public de sécurité Huawei, voici la version blog (plus complète)

Lien original : https://mp.weixin.qq.com/s/6VhWBOzJ7uu80nzFxe5jpg

Présentation de la vulnérabilité

ID de vulnérabilité : CVE-2022-0847 (alias : Dirty Pipe)

Produit vulnérable : noyau Linux - syscall splice

Versions concernées : Linux 5.8 (introduite par le patch f6dd975583bd ) ~ 5.16.11, 5.15.25, 5.10.102 (corrigées)

Impact : écrire au plus une page (4096 octets) dans n'importe quel fichier lisible (c'est suffisant), permettant une élévation de privilèges locale.

Configuration de l'environnement

Docker d'analyse de la vulnérabilité : chenaotian/cve-2022-0847 (si inaccessible, c'est que je ne l'ai pas encore téléchargé)

Fournit :

  • Noyau Linux 5.13 compilé avec la vulnérabilité et débogable
  • qemu, gdb, code source du noyau Linux 5.13
  • exploit

Démarrage :

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

Débogage :

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]

Principe de la vulnérabilité

Le principe succinct de la vulnérabilité est que l'appel système splice peut envoyer un fichier dans un tube (pipe) via un mécanisme de "zéro copie". Au niveau du code, la copie zéro correspond à l'utilisation directe de la page de cache du fichier (page cache) comme page buf du tube. Cependant, cela introduit une vulnérabilité de variable non initialisée, qui permet à la page de cache du fichier d'être ensuite traitée comme une page de cache de tube ordinaire dans le canal du tube, et donc d'être "réécrite" et modifiée. Or, dans ce cas, le noyau ne marque pas cette page de cache comme "sale" (dirty) ; pendant un court laps de temps (jusqu'au prochain redémarrage ou équivalent), elle n'est pas rafraîchie sur le disque. Pendant ce temps, tous les accès à ce fichier utiliseront la page de cache modifiée, réalisant ainsi une opération "écrire arbitrairement dans un fichier lisible pendant un court instant". Cela permet une élévation de privilèges locale.

Point d'apparition de la vulnérabilité

D'après le correctif, le point vulnérable se situe dans la fonction copy_page_to_iter_pipe, où une initialisation de buf->flags a été ajoutée. Il s'agit donc d'une vulnérabilité de variable non initialisée.

image-20220308170149137

Le point d'appel de copy_page_to_iter_pipe se trouve dans l'appel système splice. La fonction splice (appel système) transmet le contenu d'un fichier vers un tube via une méthode de "zéro copie". Cela offre de meilleures performances que la transmission directe du contenu du fichier dans le tube. Détails ci-dessous.

Principe du tube (pipe) et pipe_write

Tout d'abord, la vulnérabilité est également appelée "Dirty Pipe". Il est nécessaire de comprendre le tube (pipe). Le tube est un canal de communication fourni par le noyau, créé via les fonctions pipe/pipe2. Il renvoie deux descripteurs de fichier : un pour envoyer des données, l'autre pour les recevoir, comme les deux extrémités d'un tube. Pas de détails superflus ici.

image-20220309124007780

Expliquons brièvement l'implémentation dans le noyau. En général, l'espace cache du tube fait 65536 octets, géré sous forme de pages, soit 16 pages (4096 octets chacune). Les pages ne sont pas contiguës mais gérées via un tableau, formant une liste circulaire. Deux pointeurs de liste sont maintenus : un pour l'écriture (pipe->head) et un pour la lecture (pipe->tail). Analysons principalement la fonction 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] si le cache du tube n'est pas vide, essayer de "continuer" l'écriture à partir de la dernière page courante
		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] clé : si le drapeau PIPE_BUF_FLAG_CAN_MERGE est présent, la page permet l'écriture continue
             * si la longueur d'écriture ne dépasse pas une page, écrire à la suite, sinon créer une nouvelle page */
			ret = pipe_buf_confirm(pipe, buf);
			···
			ret = copy_page_from_iter(buf->page, offset, chars, from);
			···
			}
			buf->len += ret;
			···
		}
	}

	for (;;) {//[3] si on ne peut pas écrire à la suite de la page précédente, créer une nouvelle page
		··· ···
		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] allouer une nouvelle page
				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);

			/* Insérer dans le tableau de tampons */
			buf = &pipe->bufs[head & mask];
			buf->page = page;//[5] placer la page nouvellement allouée dans le tableau de pages
			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] définir le drapeau ; par défaut PIPE_BUF_FLAG_CAN_MERGE
			pipe->tmp_page = NULL;

			copied = copy_page_from_iter(page, 0, PAGE_SIZE, from); 
            //[7] opération de copie
			··· ···
			ret += copied;
			buf->offset = 0;
			buf->len = copied;

			··· ···
		}
        ··· ···
    }
	··· ···
	return ret;
}
  1. Si le tube (pipe) n'est pas vide (head==tail indique un tube vide), alors il y a des données non lues ; on obtient le pointeur head, c'est-à-dire la page la plus récente pour l'écriture, on examine ses champs len, offset (pour trouver la fin des données). On essaie alors d'écrire à la suite dans la page courante.
  2. On vérifie si la page courante porte le drapeau PIPE_BUF_FLAG_CAN_MERGE ; s'il est absent, l'écriture continue n'est pas autorisée. Ou si la concaténation des données à écrire avec les données existantes dépasse une page (c'est-à-dire que l'écriture traverse une limite de page) ; si elle traverse, on ne peut pas écrire à la suite.
  3. Si on ne peut pas écrire à la suite de la page précédente, on crée une nouvelle page.
  4. alloc_page alloue une nouvelle page.
  5. La nouvelle page est placée en tête du tableau (peut remplacer une page existante), initialisée.
  6. buf->flag est initialisé par défaut à PIPE_BUF_FLAG_CAN_MERGE, car par défaut la page est autorisée à être réécrite.
  7. Copie des données à écrire ; si pas terminé, répéter les opérations ci-dessus.
Télécharger l’outil