Own your Android! Yet Another Universal Root CVE-2015-3636 (中文翻译) (1)
2016-08-07 01:21
507 查看
摘要
近几年来,由于linux内核漏洞极少,并且不同的供应商也在设备上做了防范措施,想要在安卓上找到一个可以广泛使用的root方法已经变得愈加困难。在这篇文章里,我们将要展示我们的一种可以广泛应用的root方案。相关的漏洞是 CVE-2015-3636,一个典型的linux内核UAF(use-after-free)漏洞,我们将深入讨论这个漏洞。由于内核allocator(分配器)的分离分配,利用这样一个UAF漏洞是十分困难的。我们将会展示如何利用这个内核UAF漏洞在大多数市面上的安卓4.3即以上版本的设备上进行提权,其中包含世界上第一个64位的root示例。简短的说,我们将会展示一种通用的方式来利用linux内核的UAF漏洞,也就是说,对于所有厂商的产品都有效。所有现在的内核防范措施比如PXN都可以被绕过。更重要的是,我们独特的、没有被文档记录的针对内核UAF漏洞的攻击技术具有稳定和准确的特征。
漏洞分析
漏洞是由Keen Team的Wen Xu和wush通过自己定制的PC linux系统调用fuzzer工具Trinity发现的。我们将他移植到了android的ARM linux上。漏洞在最新的linux内核源码中已经被修复并且分配了CVE编号为CVE-2015-3636.漏洞位于linux内核的base部分,这保证了它可以用于通用root。当有人试图通过已经由socket(AF_INET, SOCK_DGRAM, IP-PROTO_ICMP)创建的socket文件描述符来调用connect的时候,这一段内核代码将处理用户的请求。
并且如果sa_family == AF_UNSPEC,那么内核将会调用由协议类型确定的disconnect过程。对于一个PING(ICMP)套接字来说,disconnect过程即如下
我们可以看到对于一个PING(ICMP)套接字来说,内核最终会调用sk->prot->unhash(sk),也就是下图中的ping_unhash()。
正如在源代码中所展示的一样,如果sock对象(ICMP sock)sk已经被hash了,那么它将会试图删除其在内核hlist当中存储的sk_nulls_node。如下图所示。
我们可以想到在n(sk->sk_nulls_node)被删除以后,n->pprev将变为LIST_POISON2,而这个值是一个常数。实际上在android32位和64诶的内核里,这个值均为0x200200。这个虚拟地址可以被攻击者映射到用户空间。
然而,当第二次调用connect的时候将会发生一些神奇的事情。在socket对象从hlist当中删除后,它仍然是被hash的,因为它是否被hash是由sk->sk_node来决定的,而在第一次connection当中,没有被改变。
因此,内核将会进入if语句,然后会再次试图删除sk->sk_nulls_node。当内核执行了 *pprev = next,它将会crash,因为现在pprev的值为0x200200,而如果这个虚拟地址没有被映射进用户空间,那么一个严重的页错误将会在内核中发生,并且导致严重的后果。0x200200应该在第二次ICMP套接字连接之前被映射进用户空间来避免crash。然而,这样的一个本地DOS(拒绝服务)还不是这个漏洞的全貌。
简单看一看下图中的代码
在hlist_nulss_del被调用之后,我们可以发现sock_put(sk)非常值得怀疑。
每当内核进入if语句的时候,它都会为内核中sock对象的引用计数减一。而最重要的是,它会检查引用计数是否为0。如果为0,sock对象将会被free掉。这意味着如果有人试图第二次connect这样一个sock对象的时候,引用计数将会变为0,然后内核就会释放(free)它。但是用户程序中的文件描述符依然联系在对应的内核中的sock对象上,这导致了典型的UAF漏洞。
POC(Proof-of-Concept)
这是一段CVE-2015-3636的PoC。int sockfd = sock(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); struct sockaddr addr = { .sa_family = AF_INET}; int ret = connect(sockfd, &addr, sizeof(addr)); struct sockaddr _addr = { .sa_family = AF_UNSPEC}; ret = connect(sockfd, &_addr, sizeof(_addr)) ret = connect(sockfd, &_addr, sizeof(_addr));
connect必须用AF_INET、sa_family首先调用来创建一个sk(那个有漏洞sock对象),在内核中被hash,否则那个if将根本不会到达。
注意一下,这个POC知在android设备上有效。允许创建PING套接字的group id范围在/proc/sys/net/ipv4/ping_group_rang中被设置。在android设备上,默认一个普通用户就由权利创建PING套接字,而在PC linux上,正常情况下没有任何人有权利创建它们。
相关文章推荐
- Own your Android! Yet Another Universal Root CVE-2015-3636 (中文翻译) (2)
- Own your Android! Yet Another Universal Root CVE-2015-3636 (中文翻译) (3)
- Own your Android! Yet Another Universal Root(二)
- Own your Android! Yet Another Universal Root(一)
- 【Android ROOT】Recovery v2.5.1.2各项选项中文翻译
- Android 最新漏洞CVE-2015-3636
- Android Camare中文翻译
- android ViewTreeObserver中文翻译学习
- [中文翻译] Android中文翻译组:Android 4.0 r1开发者指南——Data Storage - Data Backup
- Android中文翻译组 - 简介
- Android开发SDK中文翻译连载
- Android中文翻译组 - 简介
- android官网 100%的中文翻译版
- CVE-2015-1328 Ubuntu 12.04, 14.04, 14.10, 15.04 overlayfs Local Root
- Android中文翻译组
- 有关Android:XXX一些属性的中文翻译
- Applying Styles and Themes - 应用Style和Theme - Android官方文档中文翻译
- Applying Styles and Themes - 应用Style和Theme - Android官方文档中文翻译
- Android-Universal-Image-Loader文档翻译