热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

uaf(二进制漏洞)

雷锋网编者按:8月16日,第三届中国互联网安全领袖峰会(CSS2017)在北京国家会议中心召开。作为九大分会场之一的腾讯安全探索论坛(TSec)以“安全新探索”为主题,云集了国际知


雷锋编者按。com:8月16日,第三届中国互联网安全领袖峰会(CSS 2017)在北京国家会议中心举行。九大突围会场之一的腾讯安全探索论坛(TSec)以“新安全探索”为主题,汇聚了国际知名厂商和顶尖高校的资深安全专家,共同探讨全球信息安全领域的前沿技术、研究成果和未来趋势。腾讯安全科恩实验室的Simple Belt和Shendi分享了面对安卓内核中UAF漏洞数量不断减少、利用难度逐渐增加的现状,如何稳定高效地利用这些漏洞完成操作系统权限提升。


简单带:大家下午好!我是腾讯安全科恩实验室的简单带,我和我的同事沈迪将与大家分享“利用安卓内核中的UAF漏洞”。


今天的分享主要分为四个部分。首先,我来介绍一些前段时间出现的典型安卓内核漏洞。其次,需要从利用方面分析UAF这种特定类型漏洞的特点,这涉及到系统组件的基础知识,让大家了解后续内容。之后交给神迪,神迪具体分析perf子系统中发现的UAF漏洞的具体利用过程。最后,分享我们的总结和思考。


首先介绍安卓内核漏洞的简史。


为什么要攻击安卓内核?


安卓系统被视为一个整体。在最早的系统中,不同的应用程序和uid被用来隔离应用程序。后来发现这并不能阻止攻击,于是产生了加密文件系统等安全措施。


大多数措施的实现都依赖于安卓的内核。攻击内核本身非常有帮助。在Windows系统中,攻击内核可以直接达到提升实力的目的。在安卓系统中,你也可以绕过系统中设置的限制。对于坏人来说,他们可以达到他们不可告人的目的。


根据时间线和我个人的理解,列出了有代表性的内核漏洞。当然不包括我们今天要讲的漏洞。




2013年11月,CVE-2013-6282是我们朋友写的最早的漏洞。这是一个逻辑问题。当我们去年攻击特斯拉时,我们惊讶地发现这个漏洞仍然存在。当时特斯拉自信车辆无法攻破,所以他们没有在内核做更多的防御。bug被举报修复后,特斯拉在内核上做了非常激进的更新修复。大胆漏洞是常见的安卓根漏洞。


2014年,美国两个天才少年发现了towelroot,这是一个引起巨大反响的万能根。这种类型的漏洞在当时是比较新的,利用这种漏洞的方法也很有新意,引起了不小的轰动。


2015年5月,我们找到了CVE-2015-3636。


2016年8月,我们使用了CVE-2015-1805。


然后就是非常著名的Dirty COW,这也是一个逻辑问题。


2017年4月,谷歌研究人员发现的wifi Firmware漏洞是一个非常创新的漏洞。


我之前提到过几个有代表性的漏洞,6282是业务逻辑问题;1805年是跨境访问;353和3636都是UAF漏洞。今天,我们主要研究和讨论UAF漏洞。




hsjdyj和UAF的漏洞需要先Free后用,成功利用这个漏洞有几个步骤不能省略。一是如何依次触发免费和使用。这似乎比较简单。以2015-3636为例。使用和免费的时机是非常可控的。我们可以为所欲为,更好地控制自由空间。


336漏洞的出现很好,但在很多情况下,可能会面临种族的问题。在这种情况下,如何稳定控制免费使用的顺序,稳定触发使用是一个难题。不同的漏洞需要不同的技能来应对。我们已经能够阐明定时问题,然后如何改变内核的控制能力以及如何控制代码执行。有不同的方法来控制自由空间,不同的洞和不同的方法。


这里涉及到的最重要的是Linux内核的内存管理。我们生动地展示了利用UAF漏洞的方法。堆上有四个ABCD对象。这是一种相对简单的表示方法。为了能够稳定有效地丢弃目标对象,并填充我们想要的内容,我们需要对内核存储管理有更深入的了解,这也涉及到Linux内核的堆管理器。




在安卓系统中,我们称之为公共堆管理器SLUB,它取代了之前常见的SLAB。在管理结构上,SLUB是简化版,U表示不引用。Qued是一个队列。作为一个堆管理器,必须总有一个队列,当你申请的时候可以从这里取。它取消了单独队列的结构,使得完全空闲的SLUB被完全释放。它存在于每cpu的平板中,它的发布和应用过程会非常快。为了实现兼容性,将Linux的管理抽象到kmem层。之前的内核代码和内核驱动不需要修改。如果自己编译Linux内核,只需要选择什么样的堆管理就可以了。

器就可以直接使用,其它代码都不用更改。

首先看一下 SLUB 的堆块长什么样子。Linux 内核当中物理内存的页面管理是通过 buddy 进行的。要符合物理页面管理的原则。在 SLUB 当中,都是二的 N 次方组成页组成的。它实际上是巧妙的利用了物理页面描述服的联合,实现了管理。我分配好给这个堆块的这些页,第一个页面的描述符上就会记录堆块中可使用的第一个对象。这就是空闲对象列表的头部。在空闲对象的头部,又会有一个指针,指到下一个空闲对象。

这个东西没有额外的元数据,所有的元数据只存在于原有的结构体当中,存在于你分配给这个堆块的页面当中。这也带来了一些特性,使得它可以帮助我们对特定的漏洞进行利用。

前面提到了 cpu_slub 的概念,分配和释放都是快速的过程。当前分配的对象在于 cpu 绑定 slub 上面,就会进入快速分配的流程。不管怎么样,对于使用堆管理器的用户来讲,肯定会得到空闲的 slub 对象供使用。具体怎么操作,就由 slub 的堆管理器进行。

为什么要设定 cpu_slub,大部分情况下在一个调度周期内会有频繁的对象分配操作。释放也是这样的情况,目前的对象就是隶属于当前的 cpu_slub,这就带来了另外一个非常好的特性。当前 cpu 上释放的对象,我马上要申请的,肯定申请到刚刚释放的对象,这对于填充是非常好的特性。这个特性在其它的漏洞利用当中也会使用到。同时,释放也存在 slow path,这是不可避免的情况。

这里对 SLUB 的特性进行了归纳。按照对象的大小会做一个合并,这会对漏洞利用带来一些问题,你可能不知道这样的堆块当中放的还有其他什么对象。

接下来看两个漏洞的案例,这两个案例充分利用了 slub 堆管理器的特性。

首先是 CVE-2015-1805。

iovec 是数据内核中传递数据的结构。这个漏洞本身是 overrun,牵涉到我们在内核当中如何申请可控的overrun 数组。在安卓当中,很多 API 是被禁用的。最终我们找到 sendmmsg 的调用,你可以得到内容完全可控的数组。它的坏处是放完以后就被销毁掉了。

这个对象本身的生命周期不够长。看似这不是很好的对象,实际上可以回想起之前的一点,在 slub 中一个对象被释放之后,仅仅是在对象的头部写入了指针,这个指针指向下一个可以使用的对象。

2015-1805 的代码路径当中,如果 iov 是 0,根本就不会被处理。如果说喷射的够快,漏洞利用过程够快,被释放掉的 iov 本身还是空的对象,或者又被另一个 iov 填上,根本不会对漏洞造成任何影响。我们只需要控制填进去的第一个 iov 的长度是 0,它就会被忽略掉。即便被释放,这个结果还是有效的 iov。

第二个漏洞,应该是 2016-6187。通过这个方法,把一个品相非常差的漏洞,越界写一个字符节的 0,变成可能导致代码执行的情况。最后也是通过 freelist 指针的特性。

接下来的时间交给申迪,由他分析一下在 perf 子系统中发现的漏洞利用。

申迪:下面给大家介绍我在去年发现的两个 perf 系统的 UAF。在安卓手机上有很多用户有一键 root 的需求。一些 UAF 漏洞的品相并不是特别好,但我至少要写到达到 90% 的成功率。我主要介绍两个在去年年初发现,年底报给 Google 的漏洞。

第一个是 CVE-2016-6787,它是通过 Race触发的漏洞,内核立即崩溃。上周我在 BlackHat 讲了绕过三星 KNOX 的防护机制。

第二个漏洞是 CVE-2017-0403,这是今年才修复的漏洞。这个漏洞有它自己的难点。

在讲漏洞之前,先讲一下 perf 是什么东西,它是系统调用,任何安卓都可以调这个系统调用,攻击内核。这个系统调用有很多问题,我也发现不止两个问题,这边两个是比较好利用的,单独拿出来讲一下。这个系统调用的参数比较复杂,其中一个是你怎么定义你想生成的统计事件,你想定义代码执行的指定周期,或者是真正调用进入内核的时候又调用了哪些调用,它包含了千奇百怪的 perf 事件,可能会进入到分支。

这个系统调用,不管中间发生了什么,最后总会生成 perf_event。每个都不是孤立的,有可能是一组形式出现的,每个 groun 都有一个 leader,每个进程里有多个组,又有大的容器包括这个组。每个进程里有两个 perf_event_context,把作为的 group leader 串联起来,这 list 把组内的串联起来,这三个内核对象有一个比较复杂的连接的关系,其实就是因为这些关系搞得很复杂,系统调用里出了一些 UAF 的问题。

Googl 在 2016 年下半年觉得这个系统调用太危险,直接封掉了。去年年初,这个调用还可以被其它的调用调到,我利用这两个漏洞完成了手机上的 root。

第一个漏洞的问题主要是由于系统调用里的 move_group。

如果 group leader 是软件的,你要插入一个硬件的,这个时候会挪动大量列表相连的关系。首先会把 group leader 从指针上提取出来,把每个 event 粘出来。这两个操作完成之后,又看到红框里的代码,减了 1,这个减 1 没有考虑到并发操作,把一个组摘除了两遍。正常情况下,只减 1,并发操作就要减 2,被多减了一个,引用减到 0,导致触发释放。

主线程先创建一个 group leader,线程 1 触发 move_group操作。右边出现了崩溃,实际是因为 perf_event context 被提前释放。你的进程在第二次进入调度的时候,进入调度器会调入一行,周期执行完了会换出,换出之后再被进程调度器换入。

这个时候就会触发操作。关键是线程调度是很频繁的,基本不是肉眼可观测的。漏洞一旦触发,内核立即就崩溃了。实际上它不是立即崩溃,实际上有一个微笑的操作,线程已经被换出,换入的时候又崩溃了。假如是一个立即的崩溃,对我来说就是毫无意义。这个时候就要集中解决一个问题,怎么让内核不立即崩溃,给我争取到足够的时间去喷堆。

在讲这个问题之前,要先讲一下 Linux 内核的调度知识,包括很多线程,每个线程不可能同时执行。真正执行的是一个,其它都是等待执行。它执行一段时间之后,会有几种情况。有一种情况就是以后再也不需要执行,它就会被杀掉。如果该想继续执行,配合的时间片已经被用尽了,这个时候就被线程调度器切换出去。这种时候就会进入到 interruptible 或者是 uninterruptible。

futex 这个调用可以帮助我们完成真正的睡眠。一旦线程进入睡眠的状态,是不会被任何人主动唤醒。这对我们来说是最理想的状态。

有了这个函数的帮助,整个调用逻辑就变成这样的,从左到右,从触发漏洞,到喷堆、代码执行控制完整的流程图。还是主线程创建 group leader,直接调 queue_me。线程1和线程2都同时触发 perf_event 的工作。调了 queue_me 之后,三个线程全部睡眠掉了。这个时候我需要再建另外一个新进程,帮助我完成喷堆。喷堆并不是很难,1024 的对象,你直接喷堆,直接喷物理页面,也是可以的。可能需要十几秒的时间,把堆喷满。这个时候我可以唤醒进程,或者直接杀掉进程,这都无所谓。线程调度器会调 sched_in。disable 可以指向你想控制的任何一个地址。你可以执行内核任意代码,把权限提到 root。

另外一个 2017-0403 漏洞。最后一条是被释放的对象,每个方块都可以代表 0X10 的字节,它没有任何指针,你怎么控制 PC 做代码执行呢?

free 之后你能锁 use 的部分就是红色的两个框,是 0X10 的单位,可以写两个指针的地址。A 是对象地址本身,第二个是 A+0X20 的位置。你可以用内核的其它对象去喷对,在 0X20 这个位置正好有一个 buffer,把它的地址覆盖成 A 地址本身,你真正写的是地址 A 本身,通过覆盖地址 A 本身的方法把 UAF写成堆溢出,再覆盖其它对象,这个时候就比较好写。如果不能控制 PC 指针,UAF 并不好写。

总结

演讲后,科恩实验室在接受雷锋网采访时提到,Google 是非常重视安全的公司,在他们每月发的安全公告里面有很多安全漏洞,但绝大部分安全漏洞的利用场景非常困难,甚至是无法利用的,而其中真正威胁用户手机的漏洞是比较少的。

智能手机刚刚兴起时,众人对安全问题考虑不多。而随着攻击途径和攻击方向的增加,安全问题会被越来越重视。越来越多的人用新的方法去挖掘漏洞,其数量会变得越来越少。一旦发现新的攻击方法、新的漏洞模式,可能就会有一波漏洞攻击方法被爆发出来。随着慢慢被重视,攻击路径被堵住。

因此,面对越来越健壮的 Android 内核,攻击面急剧缩紧,只剩下一部分系统调用可供攻击。在这其中,品相好的漏洞相对于品相不好的漏洞并不多。

但科恩实验室的简单的皮带告诉雷锋网,一般来说只要是漏洞都需要被修补,事实上品相好的漏洞通常会更快修补,因为被利用的危险更大。这就是为什么优秀的安全研究团队,比如 project zero,常常输出“高质量”的漏洞,也就是能够输出漏洞和利用思路甚至是完整的利用代码。漏洞的品相好坏有时候也很难判断,除非写出具体的利用代码。

当然,这个其实不是安卓的特例。漏洞和很多东西一样,比如玉石原石类,都有一个“品相”。漏洞的品相取决于很多因素,比如漏洞所在的攻击面是否容易访问到、漏洞的触发是否容易和稳定,等等。所以有无法利用的漏洞是很正常的。

申迪也总结了面对无法利用的漏洞做法,首先要确定核心问题到底是什么,是不是真的不能利用,还是有其它办法。也可以借助内核中的其它特性,或者参考过往的案例,毕竟有些思想是共通的,可以帮助你有些想法。

即使最后真的发现无解,也可以丢开一段时间。他回忆起自己写 2014-0403 那个漏洞,也是丢开了 1、2个月,突然想到一个方法写出来的。

最后,不要盲目报告一些无法利用漏洞,没有人觉得你真的厉害。


推荐阅读
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • C#多线程解决界面卡死问题的完美解决方案
    当界面需要在程序运行中不断更新数据时,使用多线程可以解决界面卡死的问题。一个主线程创建界面,使用一个子线程执行程序并更新主界面,可以避免卡死现象。本文分享了一个例子,供大家参考。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • 【工具篇】抓包中的王牌工具—Fiddler (1环境搭建)
    本文介绍了抓包工具Fiddler的概述,包括其功能、选择原因和安装方法。Fiddler是一款免费且功能强大的抓包工具,可用于网络代理、接口测试、安全测试和WEB调试等。安装配置简单,上手快速,适合新手使用。详细的安装地址为https://www.telerik.com/download/fiddl。 ... [详细]
  • python3 nmap函数简介及使用方法
    本文介绍了python3 nmap函数的简介及使用方法,python-nmap是一个使用nmap进行端口扫描的python库,它可以生成nmap扫描报告,并帮助系统管理员进行自动化扫描任务和生成报告。同时,它也支持nmap脚本输出。文章详细介绍了python-nmap的几个py文件的功能和用途,包括__init__.py、nmap.py和test.py。__init__.py主要导入基本信息,nmap.py用于调用nmap的功能进行扫描,test.py用于测试是否可以利用nmap的扫描功能。 ... [详细]
author-avatar
最陌生的挣扎2502893263
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有