中国科学家故事20字:【转】漏洞 — zergRush (补充)
来源:百度文库 编辑:偶看新闻 时间:2024/05/01 17:45:54
漏洞 — zergRush (补充)
分类: 移动安全 2011-10-13 15:20 694人阅读 评论(0) 收藏 举报没看到上文的参见一下
http://blog.csdn.net/tomken_zhang/article/details/6866260
上文中还没有来细细分析漏洞的出处及利用过程,现在又有所收获,特记录下来。
上文说到,向 vold 发送了一段 SOCKET 数据,然后 vold 崩溃了。 崩溃的愿意是栈溢出,究竟在哪溢出的呢,其实在 zergRush.c 中说了一些,文件的头部就写到 libsysutils root exploit,意思是这个库有个漏洞,恰恰被 vold 进程使用,而这个进程是 root 用户能力。
找到 libsysutils 代码,在 \android2.32\system\core\libsysutils\src 这个位置,文件不是太多,我是追查了好处才定位到一个函数有问题,具体过程不说了,比较痛苦和迂回。(经验少啊!)
FrameworkListener.cpp 文件
>> onDataAvailable 收到 Socket 数据。
>> 只读 255 的 buffer
>> dispatchCommand 分配数据
view plainprint?
- void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
- FrameworkCommandCollection::iterator i;
- int argc = 0;
- char *argv[FrameworkListener::CMD_ARGS_MAX];
- char tmp[255];
- char *p = data;
- char *q = tmp;
- bool esc = false;
- bool quote = false;
- int k;
- memset(argv, 0, sizeof(argv));
- memset(tmp, 0, sizeof(tmp));
- while(*p) {
- if (*p == '\\') {
- if (esc) {
- *q++ = '\\';
- esc = false;
- } else
- esc = true;
- p++;
- continue;
- } else if (esc) {
- if (*p == '"')
- *q++ = '"';
- else if (*p == '\\')
- *q++ = '\\';
- else {
- cli->sendMsg(500, "Unsupported escape sequence", false);
- goto out;
- }
- p++;
- esc = false;
- continue;
- }
- if (*p == '"') {
- if (quote)
- quote = false;
- else
- quote = true;
- p++;
- continue;
- }
- *q = *p++;
- if (!quote && *q == ' ') {
- *q = '\0';
- argv[argc++] = strdup(tmp);
- memset(tmp, 0, sizeof(tmp));
- q = tmp;
- continue;
- }
- q++;
- }
- argv[argc++] = strdup(tmp);
- #if 0
- for (k = 0; k < argc; k++) {
- SLOGD("arg[%d] = '%s'", k, argv[k]);
- }
- #endif
- if (quote) {
- cli->sendMsg(500, "Unclosed quotes error", false);
- goto out;
- }
- for (i = mCommands->begin(); i != mCommands->end(); ++i) {
- FrameworkCommand *c = *i;
- if (!strcmp(argv[0], c->getCommand())) {
- if (c->runCommand(cli, argc, argv)) {
- SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
- }
- goto out;
- }
- }
- cli->sendMsg(500, "Command not recognized", false);
- out:
- int j;
- for (j = 0; j < argc; j++)
- free(argv[j]);
- return;
- }
溢出发生在栈变量 argv[FrameworkListener::CMD_ARGS_MAX] 上,
FrameworkListener::CMD_ARGS_MAX = 16 在我的看的源代码中。
view plainprint?
- *q = *p++;
- if (!quote && *q == ' ') {
- *q = '\0';
- argv[argc++] = strdup(tmp);
- memset(tmp, 0, sizeof(tmp));
- q = tmp;
- continue;
- }
- q++;
这里是通过判断传来的数据是否有空格来进行 argc++ 的,而最大的下标明显是 16, 如果我们特意传送超过 16 个空格分割的字符串,就溢出了。
为了验证一下,把这段代码放到 PC 上写个函数,编译一下,得出结果,确实溢出。
回头看看 zergRush.c 吧
在 do_fault 函数中。 确实定义了一个 255 的 buf,和接受的缓冲一样长,通过一堆 strcat 函数,放入相关字段,
还有一个循环,
for(i=3; i < buffsz+1; i++)
strcat(buf, " ZZZZ");
放了更多个
然后又放了一些“地址” ,其实这些地址是一个 shellcode ,目的是覆盖寄存器 lr 被 Push 到栈数据空间。最后完成整个提权动作。
顺便提一下栈溢出原理
当一个函数进入到另一个函数的时候(典型情况),程序会把函数的参数,及一些环境(寄存器,包括反回地址 LR 寄存器)入到栈空间保存。
同时新函数执行的时候会把函数栈变量也放到栈空间上,大概如下:
view plainprint?
- void func(int a, int b) {
- int var;
- return;
- }
- int main() {
- func(1, 2)
- do_somting();
- return;
- }
当调用 func 的时候,
栈是这样的:
>>>>> 2 (就是 b 的值)
>>>>> 1 (就是 a 的值)
>>>>> var 的值
>>>>> 该函数时要 push 的通用寄存器 比如 r0
>>>>> lr 反回地址,其实指向的应该是 do_somting 的地址
当 var 的赋值溢出的时候,就会覆盖到下面的一些寄存器,如果替换得当,就完成了程序的非正常流程的运行。
以上大概就是这样子,具体情况实际上更为复杂,本人也不明白,另外 PC 与手机的还不相同。仅作参考!