浅析VOLD_ASEC漏洞

来源:互联网 发布:r统计软件说明 编辑:程序博客网 时间:2024/05/21 22:48

0x1 漏洞描述

  这个漏洞没有被CVE库收录,而是被默默修补掉了.通过查看AOSP changelog(4.4.2 – 4.4.3)当中的内容可以得知这是一个vold进程中asec模块由于没有校验用户传递路径而导致的问题.它可以让vold为我们mount任意目录,如果该目录原本存在,将被新的目录覆盖掉.由于vold进程是以root权限运行的,它的功能和潜在的安全漏洞都成为令人关注的目标.


0x2 原理分析

  Vold守护进程是Android系统上用于管理和控制外部存储设备的后台进程.比如插入SD卡时,vold会处理这一事件,先将SD卡挂载到相应的路径(/mnt/sdcard),当SD卡被用户取出后,vold就会卸载目标卷.


/*问题代码摘自AOSP4.4.2/system/vold/VolumeManager.cpp当中的createAsec函数http://androidxref.com/4.4.2_r2/xref/system/vold/VolumeManager.cpp*/





如代码所示,使用了snprintf函数,其中没有对用户所传递的id进行任何校验.也就是意味着如果路径以”../../PATH”这样的方式传递,将可以遍历任意路径.比如如果id的值为../../data/local/tmp/xxxx,那么在/data/local/tmp/目录下会创建xxxx.asec文件.



  这段代码的意思就是如果挂载点已经存在,并且没有错误抛出,vold就会正确挂载该路径.但是如果挂载点已经存在并且是一个指向另一目录的符号链接呢?它将会被新的目录所覆盖.所以说vold可以为我们重复挂载任何一个目录.那么也就是意味着我们可以完全控制自己指定的目录,并且向目录写入文件来覆盖系统目录.


0x3 如何利用

  大致思路是把/sbin目录重新mount,替换掉/sbin/adbd文件,并且当系统进程adbd重新被init进程启动的时候,我们就可以控制adbd进程以root权限执行任意代码,之后以root权限放一个带s位的su到系统目录下,这样就完成了利用.这里需要注意的是需要以个特殊的adbd文件,因为默认的adbd启动之后会自己降权.我们只要把adb.c当中的should_drop_privileges函数直接返回0,再重新编译就可以获得这个特殊adbd文件.


具体过程:

1. 创建一个指向/sbin目录的符号链接/data/local/tmp/xxxx

2. 使用vdcvold进程传递触发漏洞的消息,vold进程会在/data/app-sec/xxxx路径下创建一个文件夹,并且将它mount/mnt/asec/xxxx.所以我们要传递刚才新建的/sbin的符号链接,这样/sbin目录就会被重新覆盖成一个空分区.

3. 把adb.c当中的should_drop_privileges函数直接返回0,再重新编译.

4. 为/data/local/tmp/adbd建立/sbin/adbd的符号链接

5. 杀死adbd进程,init进程将其重新启动,/data/local/tmp/adbd以root权限运行.


0x4 POC

ln -s  /sbin /data/local/tmp/test1vdc asec create ../../data/local/tmp/test1 4 ext4 none 2000 falseln -s  /data/local/tmp/adbd /sbin/adbdchmod 755 /data/local/tmp/adbdecho 'kill adbd by yourself,then you get a root shell'

0x5 漏洞修复

bool VolumeManager::isLegalAsecId(const char *id) const {size_t i;size_t len = strlen(id);if (len == 0) {return false;}if ((id[0] == '.') || (id[len - 1] == '.')) {return false;}for (i = 0; i < len; i++) {if (id[i] == '.') {// i=0 is guaranteed never to have a dot. See above.if (id[i-1] == '.') return false;continue;}if (id[i] == '_' || id[i] == '-') continue;if (id[i] >= 'a' && id[i] <= 'z') continue;if (id[i] >= 'A' && id[i] <= 'Z') continue;if (id[i] >= '0' && id[i] <= '9') continue;return false;}return true;}





0 0
原创粉丝点击