欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]kernel pwn -- UAF

[原创]kernel pwn -- UAF

简介

众所周知,UAF的全称是Use After Free,是一种释放后重用漏洞;之前一直是在用户态下对这个漏洞进行利用学习的,最近想要体验一下在内核环境中利用此漏洞进行提权操作....
用户态的常规UAF可以看这篇文章.....
这里我利用的CISCN2017 babydriver来进行学习的,环境我已经放到github上面了,需要的可以自行下载....

前置知识

权限

在Linux当中每个进程都有它自己的权限,而标示着权限的那些信息,比如uid,gid等都是被放在一个叫cred的结构体当中的,也就是说每个进程中都有一个cred结构,如果我们能够修改某个进程的cred,那么我们就可以修改这个进程的权限了....
这里展示版本为4.4.72的cred结构体的源码:

struct cred {

    atomic_t    usage;

#ifdef CONFIG_DEBUG_CREDENTIALS

    atomic_t    subscribers;    /* number of processes subscribed */

    void        *put_addr;

    unsigned    magic;

#define CRED_MAGIC  0x43736564

#define CRED_MAGIC_DEAD 0x44656144

#endif

    kuid_t      uid;        /* real UID of the task */

    kgid_t      gid;        /* real GID of the task */

    kuid_t      suid;       /* saved UID of the task */

    kgid_t      sgid;       /* saved GID of the task */

    kuid_t      euid;       /* effective UID of the task */

    kgid_t      egid;       /* effective GID of the task */

    kuid_t      fsuid;      /* UID for VFS ops */

    kgid_t      fsgid;      /* GID for VFS ops */

    unsigned    securebits; /* SUID-less security management */

    kernel_cap_t    cap_inheritable; /* caps our children can inherit */

    kernel_cap_t    cap_permitted;  /* caps we're permitted */

    kernel_cap_t    cap_effective;  /* caps we can actually use */

    kernel_cap_t    cap_bset;   /* capability bounding set */

    kernel_cap_t    cap_ambient;    /* Ambient capability set */

#ifdef CONFIG_KEYS

    unsigned char   jit_keyring;    /* default keyring to attach requested * keys to */

    struct key __rcu *session_keyring; /* keyring inherited over fork */

    struct key  *process_keyring; /* keyring private to this process */

    struct key  *thread_keyring; /* keyring private to this thread */

    struct key  *request_key_auth; /* assumed request_key authority */

#endif

#ifdef CONFIG_SECURITY

    void        *security;  /* subjective LSM security */

#endif

    struct user_struct *user;   /* real user ID subscription */

    struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */

    struct group_info *group_info;  /* supplementary groups for euid/fsgid */

    struct rcu_head rcu;        /* RCU deletion hook */

};

当我们是root权限的时候,我们的uid和gid都是等于0的,另外此版本的cred的大小是0xa8;

SLAB && SLUB

SLAB是一种内存管理机制,为了提高效率,SLAB要求系统暂时保留已经释放的内核对象空间,以便下次申请时不需要再次初始化和分配;但是,SLAB机制对内核对象的类型十分挑剔,只有类型和大小都完全一致的对象才能重用其空间;这就好比是装过鸡的笼子是不允许再去关兔子了,哪怕鸡和兔子的大小一样;
但是,和SLAB相比,SLUB对对象类型就没有限制,两个对象只要大小差不多就可以重用同一块内存,而不在乎类型是否相同;也就是说这次申请的空间的大小和上次释放的空间大小一样,那么这两个空间的地址会是一样的;SLUB机制就允许装过鸡的笼子再装兔子,只要大小ok就好.....
其实SLUB机制和堆分配机制是比较一样的,只是更加复杂一些....

题目分析

现在具体分析一下题目:
首先在驱动中有一个结构体,保存着一个字符串的内容和长度:

struct babydev_struct{

    char *device_buf;

    size_t device_buf_len;

};


然后我们来看看主要的函数:
babyopen:

申请一块大小为0x40字节的空间,然后将地址存储在全局变量babydev_struct.device_buf上,并更新babydev_struct.device_buf_len

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功