0x0 漏洞信息
https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2011-3874
0x1 漏洞描述
漏洞的本质是"use after free".具有root权限的vold进程使用了libsysutils.so,其中某个函数存在栈溢出的问题,因此可以控制root身份的vold执行system(),借以提权.
0x2 代码分析
漏洞存在于/system/core/libsysutils/src/FrameworkListener.cpp的FrameworkListener::dispatchCommand方法
#define CMD_ARGS_MAX 16
void FrameworkListener::dispatchCommand(SocketClient *cli, char *data)
{
FrameworkCommandCollection::iterator i;
int argc = 0;
//在栈上分配了一个固定大小的数组argv
char *argv[FrameworkListener::CMD_ARGS_MAX];
char tmp[255];
char *p = data;
char *q = tmp;
bool esc = false;
bool quote = false;
int k;
//省略无关代码
.....
if (!quote && *q == ' ')
{
*q = '\0';
//填充数组的时候没有检测是否越界
argv[argc++] = strdup(tmp);
memset(tmp, 0, sizeof(tmp));
q = tmp;
continue;
}
}
onDataAvailable方法监听socket输入,接收数据包后以'\0'为分隔符,将buffer内容分段传给dispatchCommand函数做进一步处理.dispatchCommand将接受的字符串以空格分割,调用strdup函数在堆中生成复制,把堆中地址保存到argv数组.但在argv数组越界,与tmp发生重叠的情况下,假设有一条命令带有17个参数,
"cmd x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 x15 x16 \x78\x56\x34\x12"
argv[0] == "cmd";
argv[1] == "x1";
argv[2] == "x2";
argv[3] == "x3";
argv[4] == "x4";
argv[5] == "x5";
argv[6] == "x6";
argv[7] == "x7";
argv[8] == "x8";
argv[9] == "x9";
argv[10] == "x10";
argv[11] == "x11";
argv[12] == "x12";
argv[13] == "x13";
argv[14] == "x14";
argv[15] == "x15";
argv[16] == 0x12345678;
argv[17] == "\x78\x56\x34\x12";
argv数组大小只有16项,argv[16]实际上是tmp数组的前4个字节,而最后一个参数是"\x78\x56\x34\x12",它被解析出来后缓存到tmp里,这样tmp的前4字节就成了0x78,0x56, 0x34,0x12 ,因此argv[16]==0x12345678.之后,argv[16]被free,即执行了free(0x12345678).我们可以任意控制参数内容,即可实现:free(任意地址).
0x3 如何利用
可以通过free来攻击虚函数.zergRush攻击的思路是先free对象C,这片堆空间恢复成空闲状态,再重新占用对象地址,进而覆盖vtable实现控制.
for (i = mCommands->begin(); i != mCommands->end(); ++i)
{
FrameworkCommand *c = *i;
if (!strcmp(argv[0], c->getCommand()))
{
//runCommand函数是虚函数,先想办法得到c的地址填入argv[17],在free时free掉c
if (c->runCommand(cli, argc, argv))
{
SLOGW("Handler ‘%s‘ error (%s)", c->getCommand(), strerror(errno));
}
goto out;
}
}
之后调用c->runCommand前将c的堆空间内容控制住,若这时向dispatchCommand传入新的命令,则在第一次strdup时有可能申请的堆空间就是刚刚c的空间,若构造好参数则控制了堆中内容,也就控制了虚表.这时程序执行到c->runCommand时就劫持了控制流.
0x4 Poc
/* android 2.2/2.3 libsysutils root exploit use-after-free
*
* Exploited by rewriting a FrameworkCommand object making the runCommand
* point to our first ROP gadget.
*
* Copyright (c) 2011, The Revolutionary development team.
*
* Before using, insert empty formatted sdcard. USE IT AT YOUR OWN RISK,
* THIS PROGRAM MIGHT NOT WORK OR MAKES YOUR DEVICE USELESS/BRICKED. SO BE
* WARNED! I AM NOT RESPONSIBLE FOR ANY DAMAGE IT MIGHT CAUSE!
*
* It only works if called from adb shell since we need group log.
*
* Compile:
* agcc zergRush.c -o zergRush -ldiskconfig -lcutils
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <errno.h>