Skip to content
KitploitKITPLOIT
HerramientasBlog
Log in
Enviar
HerramientasBlog
Enviar

¡Herramientas de Hacking, PenTest y Ciberseguridad para tu Arsenal de Seguridad!

Kitploit es un directorio de herramientas de hacking, ciberseguridad y pentesting. Descubre las últimas actualizaciones de proyectos para encontrar vulnerabilidades, analizar sistemas, automatizar pruebas y fortalecer tu seguridad.

FeedsContactoPrivacidad© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2022-0847 — Exploit de prueba de concepto y análisis detallado de la vulnerabilidad de escalada de privilegios CVE-2022-0847 (Dirty Pipe) del kernel de Linux, incluido un entorno Docker para pruebas y depuración. | Kitploit
Herramientas/GitHubGitHub/chenaotian/cve-2022-0847
Escalada de PrivilegiosAnálisis de VulnerabilidadesExplotaciónAprendizaje y EducaciónExplotación de BinariosLabs y Práctica
GitHubchenaotian/cve-2022-0847

CVE-2022-0847

Exploit de prueba de concepto y análisis detallado de la vulnerabilidad de escalada de privilegios CVE-2022-0847 (Dirty Pipe) del kernel de Linux, incluido un entorno Docker para pruebas y depuración.

Ver Repositorio
25767hace 4 añosRevisado por Kitploit

Más Populares

Ver todos →

Descubre las herramientas más usadas por nuestra comunidad.

Explora todas las herramientas

Explora nuestra colección de herramientas

Ver todas las herramientas →
Compartir

CVE-2022-0847 Dirty Pipe análisis de escalada de privilegios en Linux

[toc]

Este artículo se publicó originalmente en la cuenta pública de seguridad de Huawei, esta es la versión del blog (más completa)

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

Resumen de la vulnerabilidad

ID de vulnerabilidad: CVE-2022-0847 (alias: Dirty Pipe)

Producto vulnerable: kernel de Linux - syscall splice

Versiones afectadas: Linux 5.8 (introducido por el parche f6dd975583bd) ~ 5.16.11, 5.15.25, 5.10.102 (corregido)

Impacto: permite escribir hasta una página de contenido (suficiente) en cualquier archivo legible, pudiendo escalar privilegios localmente.

Configuración del entorno

Docker de análisis de la vulnerabilidad: chenaotian/cve-2022-0847 (si aún no se puede acceder, es porque aún no lo he subido)

Proporciona:

  • Kernel de Linux 5.13 compilado con la vulnerabilidad y con soporte de depuración
  • qemu, gdb, código fuente de Linux 5.13
  • exploit

Inicio:

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

Depuración:

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 de la vulnerabilidad

El principio básico de la vulnerabilidad es que al llamar a la función splice, se puede enviar un archivo a la pipe mediante "copia cero". A nivel de código, la copia cero consiste en usar directamente la página de caché del archivo (page cache) como página buf de la pipe. Sin embargo, aquí se introduce un error de inicialización de variable, lo que provoca que la página de caché del archivo sea tratada posteriormente en el canal pipe como una página de caché normal de la pipe, permitiendo su "reescritura" y, por lo tanto, su modificación. No obstante, en esta situación, el kernel no considera esta página de caché como "sucia" y no la vacía a disco en un corto período de tiempo (hasta el próximo reinicio, por ejemplo). Durante ese tiempo, todos los accesos a ese archivo utilizarán la página de caché modificada, logrando así una operación de "escritura arbitraria en cualquier archivo legible durante un breve período". Esto puede utilizarse para escalar privilegios localmente.

Punto de ocurrencia de la vulnerabilidad

Según el parche, el punto de ocurrencia está en la función copy_page_to_iter_pipe, donde se añadió la inicialización de buf->flags. Por lo tanto, se trata de una vulnerabilidad de variable no inicializada.

image-20220308170149137

El punto de llamada de copy_page_to_iter_pipe se encuentra dentro de la syscall splice. La función splice (llamada al sistema) transporta el contenido de un archivo a la tubería mediante un método de "copia cero". Esto tiene un mejor rendimiento que enviar directamente el contenido del archivo a la tubería. Se explicará con más detalle a continuación.

Principio de pipe y pipe_write

Primero, para entender la vulnerabilidad "Dirty Pipe", hay que conocer la pipe. La pipe es un canal de comunicación proporcionado por el kernel, creado mediante las funciones pipe/pipe2, que devuelven dos descriptores de archivo: uno para enviar datos y otro para recibirlos, similar a dos extremos de una tubería. No se entrará en más detalles.

image-20220309124007780

Brevemente, en la implementación del kernel, el espacio de caché de la pipe tiene normalmente una longitud total de 65536 bytes, gestionado en páginas: 16 páginas en total (4096 bytes cada una). Las páginas no son contiguas, sino que se gestionan mediante un array, formando una lista circular. Se mantienen dos punteros de lista: uno para escribir (pipe->head) y otro para leer (pipe->tail). Aquí se analiza principalmente la función 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 la caché de la pipe no está vacía, intenta continuar escribiendo desde la última página actual
		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] Clave: si el flag PIPE_BUF_FLAG_CAN_MERGE está presente, significa que la página permite continuar escribiendo.
             * Si la longitud a escribir no cruza el límite de la página, se continúa escribiendo; de lo contrario, se usa una nueva página */
			ret = pipe_buf_confirm(pipe, buf);
			···
			ret = copy_page_from_iter(buf->page, offset, chars, from);
			···
			}
			buf->len += ret;
			···
		}
	}

	for (;;) {//[3] Si no se puede continuar en la página anterior, se usa una nueva página
		··· ···
		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] Solicitar una nueva página
				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);

			/* Insert it into the buffer array */
			buf = &pipe->bufs[head & mask];
			buf->page = page;//[5] Colocar la nueva página en el array de páginas
			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] Establecer flag, por defecto PIPE_BUF_FLAG_CAN_MERGE
			pipe->tmp_page = NULL;

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

			··· ···
		}
        ··· ···
    }
	··· ···
	return ret;
}
Descargar herramienta