Android提权漏洞分析——rageagainstthecage

Android adb setuid提权漏洞由Sebastian Krahmer在2010年公布,并发布利用工具RageAgainstTheCage (rageagainstthecage-arm5.bin)。该工具被广泛用于SuperOneClick、z4root等root工具和Trojan.Android.Rootcager、DreamDroid等恶意代码中。

该工具支持Gingerbreak 2.2.X及更低版本的系统。


漏洞原理:

adb启动时最初拥有root权限,在运行过程中需要降成shell权限。如下所示,adb源码中对于setgid()和setuid()没有检查返回值,导致降权失败后继续运行。

于是利用linux对shell进程存在数量限制的特点,产生大量僵尸进程来造成降权失败,这样继续运行的adb进程就拥有root权限。

从漏洞修补后的adb源码中我们可以看出,增加了对返回值的检查。


漏洞修补前的adb源码:

int adb_main(int is_daemon) 
{ 
      ...... 
      property_get("ro.secure", value, ""); 
      if (strcmp(value, "1") == 0) { 
            secure = 1; 
      ...... 
      } 
     if (secure) { 
           ...... 
           setgid(AID_SHELL); 
           setuid(AID_SHELL); 
           ...... 
      } 
}

漏洞修补后的adb源码:

int adb_main(int is_daemon) 
{ 
      ...... 
      property_get("ro.secure", value, ""); 
      if (strcmp(value, "1") == 0) { 
            secure = 1; 
      ...... 
      } 
     if (secure) { 
           ...... 
           if(setgid(AID_SHELL) != 0){
	  exit(1);
           }; 
           if(setuid(AID_SHELL) != 0){
	  exit(1);
           }; 
           ...... 
      } 
 }

The Android Exploid Crew小组后来发布了一份PoC代码:rageagainstthecage.c[1],我们对此进行分析。


各函数功能:

函数 die(23):反馈错误信息

函数 find_adb(29):在当前进程空间中查找adb进程,并返回其进程号

函数 restart_adb(51):杀死adb进程

函数 wait_for_root_adb(57):循环检测adb进程是否重启(此处kill(-1, 9); (68)不太理解,推测应该是结束所有僵尸进程),重启的adb进程应该就具有root权限


从main函数中我们可以看出漏洞利用具体方法:

main函数首先检测系统对shell进程数量是否存在上限(RLIMIT_NPROC),如果存在则查找adb进程。此处利用匿名管道(pepe[2])进行同步,fork()的父进程在read()处阻塞,而子进程无限循环fork()产生新的子进程,新的子进程直接exit(0)形成大量僵尸进程,占用shell进程号。直到达到进程号上限,fork()将失败,这时调用write()使得父进程解除阻塞重启adb进程。最后调用wait_for_root_adb等待新的adb启动即可(adb属于系统服务,如果终止会被系统自动重启)。



参考文献

[1]http://www.claudxiao.net/2011/04/android-adb-setuid/

[2]http://blog.csdn.net/andone_lsl/article/details/8661088(流程图可以帮助理解)



你可能感兴趣的:(android,应用逆向分析)