首页
社区
课程
招聘
[原创]Linux Kernel Exploit 内核漏洞学习(3)-Bypass-Smep
发表于: 2019-7-30 13:35 7151

[原创]Linux Kernel Exploit 内核漏洞学习(3)-Bypass-Smep

2019-7-30 13:35
7151

smep的全称是Supervisor Mode Execution Protection,它是内核的一种保护机制,作用是当CPU处于ring0模式的时候,如果执行了用户空间的代码就会触发页错误,很明现这个保护机制就是为了防止ret2usr攻击的....
这里为了演示如何绕过这个保护机制,我仍然使用的是CISCN2017 babydriver,这道题基本分析和利用UAF的方法原理我已经在kernel pwn--UAF这篇文章中做了解释,在这里就不再阐述了,环境也是放在github上面的,需要的可以自行下载学习....

ptmx设备是tty设备的一种,open函数被tty核心调用, 当一个用户对这个tty驱动被分配的设备节点调用opentty核心使用一个指向分配给这个设备的tty_struct结构的指针调用它,也就是说我们在调用了open函数了之后会创建一个tty_struct结构体,然而最关键的是这个tty_struct也是通过kmalloc申请出来的一个堆空间,下面是关于tty_struct结构体申请的一部分源码:

其中kzalloc:

而正是这个kmalloc的原因,根据前面介绍的slub分配机制,我们这里仍然可以利用UAF漏洞去修改这个结构体....
这个tty_struct结构体的大小是0x2e0,源码如下:

而在tty_struct结构体中有一个非常棒的结构体tty_operations,其源码如下:

可以看到这个里面全是我们最喜欢的函数指针....
当我们往上面所open的文件中进行write操作就会调用其中相对应的int (*write)(struct tty_struct * tty,const unsigned char *buf, int count);函数....

现在我们来说一下系统是怎么知道这个Smep保护机制是开启的还是关闭的....
在系统当中有一个CR4寄存器,它的值判断是否开启smep保护的关键,当CR4寄存器的第20位是1的时候,保护开启;是0到时候,保护关闭:
CR4
举一个例子:
当CR4的值为0x1407f0的时候,smep保护开启:

当CR4的值为0x6f0的时候,smep保护开启:

但是该寄存器的值无法通过gdb直接查看,只能通过kernel crash时产生的信息查看,不过我们仍然是可以通过mov指令去修改这个寄存器的值的:

因为此题没有开kaslr保护,所以简化了我们一些步骤,但是在此方法中是我们前面的UAF,ROPret2usr的综合利用,下面是基本思路:

poc.c:

编译:

运行:
root

这道题其实最关键的是要熟悉内核的执行流程,了解一些关键的结构体以及他们的分配方式;
最后这里说一下找mov_cr4_rdi_pop_rbp_ret等这些gadget的小技巧,如果使用ropper或ROPgadget工具太慢的时候,可以先试试用objdump去找看能不能找到:

cr4

swapgs
但是使用这个方法的时候要注意看这些指令的地址是不是连续的,可不可以用;用这个方法不一定可以找到iretq,还是需要用ropper工具去找,但是大多数情况应该都可以找到的:
iretq

struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx)
{
    struct tty_struct *tty;

    tty = kzalloc(sizeof(*tty), GFP_KERNEL);
    if (!tty)
        return NULL;

    kref_init(&tty->kref);
    tty->magic = TTY_MAGIC;
    tty_ldisc_init(tty);
    tty->session = NULL;
    tty->pgrp = NULL;
    mutex_init(&tty->legacy_mutex);
    mutex_init(&tty->throttle_mutex);
    init_rwsem(&tty->termios_rwsem);
    mutex_init(&tty->winsize_mutex);
    init_ldsem(&tty->ldisc_sem);
    init_waitqueue_head(&tty->write_wait);
    init_waitqueue_head(&tty->read_wait);
    INIT_WORK(&tty->hangup_work, do_tty_hangup);
    mutex_init(&tty->atomic_write_lock);
    spin_lock_init(&tty->ctrl_lock);
    spin_lock_init(&tty->flow_lock);
    INIT_LIST_HEAD(&tty->tty_files);
    INIT_WORK(&tty->SAK_work, do_SAK_work);

    tty->driver = driver;
    tty->ops = driver->ops;
    tty->index = idx;
    tty_line_name(driver, idx, tty->name);
    tty->dev = tty_get_device(tty);

    return tty;
}
static inline void *kzalloc(size_t size, gfp_t flags)
{
    return kmalloc(size, flags | __GFP_ZERO);
}

[培训]科锐逆向工程师培训第53期2025年7月8日开班!

收藏
免费 3
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回