CVE-2018-9539:特权Android服务中的Use-After-Free

isnull   ·   发表于 2019-8-3   ·   漏洞文章

0x00 前言

在[1]中,zimperium 发现了一个UAF,在Android 8.0版本、8.1版本和9版本中的ClearKey CAS的 descrambler存在提权漏洞,攻击者可利用该漏洞获取提升的权限,谷歌将其指定为CVE-2018-9539,并在2018年11月的补丁中对其进行了修补。本文很多基础知识以及对漏洞原理的分析引用自该篇文章。

0x01 基础知识

几个知识点

  1. Android 8.0之后, 为了简化系统更新,明确分离AOSP、供应商。Google 推出了Project Treble,重新设计了Android操作系统框架,重新设计的框架中,用HIDL指定了HAL和其他用户之间的接口。

  2. MediaCasService是Android其中的一个解扰码器。代码位于HAL,所以关于MediaCasService更多基础的知识大家可以看HAL相关的资料。

  3. MediaCasService 的Android服务允许应用程序解扰受保护的媒体流。和apps的通信主要通过两个对象:Cas,管理密钥,以及Descrambler,执行实际解扰操作。
    在MediaCasService API下,实际操作由plugin执行,plugin是服务加载的库,作者提供的POC[1]中,相关的插件是ClearKey插件,其库是libclearkeycasplugin.so。
    为了解数据,应用程序需要同时使用Cas对象和Descrambler对象。 Descrambler对象用于实际的解密操作,但为了做到这一点,它需要链接到带密钥的会话。为了管理会话并向其添加密钥,使用Cas对象。在内部,ClearKey插件管理ClearKeySessionLibrary中的会话,ClearKeySessionLibrary本质上是一个哈希表。键是会话ID,而值是会话对象本身。应用程序会收到会话ID,可用于引用服务中的会话对象。
    在创建会话并将密钥附加到其后,应用程序负责将其链接到Descrambler对象。 descrambler对象有一个名为mCASSession的成员,它是对其会话对象的引用,用于解密操作。虽然没有义务这样做,但一旦Descrambler会话与会话对象链接,应用程序就可以从会话库中删除该会话。在这种情况下,对会话对象的唯一引用将通过Descrambler的mCASSession。

  4. 一个重要的注意事项是对会话对象的引用是通过强指针(sp类)来保存的。因此,每个会话对象具有引用计数,并且一旦该引用计数达到零,则释放会话对象。引用可以通过会话库或通过Descrambler的mCASSession进行。

  5. 最后一个知识点:
    Binder IPC一个重要的方面是使用了共享内存。为了通过Binder共享内存,进程利用了Binder用来共享文件描述符的功能。文件描述符可以使用mmap映射到内存,并允许多个进程通过共享文件描述符来共享相同的内存区域。

0x02 漏洞分析

漏洞原理:
漏洞点在frameworks/av/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp


其中ClearKey的descramble方法使用mCASSession对引用的session进行解密,decrypt函数并没有使用强指针,因此使用的时候session的引用计数不会增加。这意味着mCASSession->decrypt可以与释放的session一起运行,直到会话对象引用计数减少至0。

为Descrambler设置不同的会话将释放原始会话对象(引用计数将减少至0),如果发生在mCASSession->decrypt 的同时,那么 decrypt将使用一个释放的session。
所以可通过race condition 触发 UAF。

0x03 POC

作者给出的POC[1]思路:在运行解密前,攻击者从会话库中删除对会话对象的引用,将Descrambler的mCASSession作为session唯一的引用。然后,想办法达到Descrambler->decrypt和setMediaCasSession同时运行的情况,导致race condition 触发 UAF。
作者在github上写到直到Android 8.1,尝试使用释放资源的互斥锁将返回错误。而从Android 9 开始,尝试使用已销毁的互斥锁会导致中止,从而导致进程崩溃:

frameworks/av/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp


PoC执行的流程:

  1. 初始化 Cas 和 Descrambler 对象



使用 Cas 对象创建两个会话:session1和session2。从会话库中引用。将session1链接到Descrambler对象,然后使用Cas对象将其从会话库中删除。现在,session1只有来自Descrambler对象的引用;引用数=1
创建session1和session2


    1. 同时:

    2. 运行多个线程,通过Descrambler对象执行解密。
    3. 将Descrambler对象的会话设置为session2。
    1. 如果在其中一个线程运行Descramble没有返回,则意味着PoC成功并且服务崩溃。如果没有,从第2步再次重试。

0X04 复现环境

我的复现环境如下,尝试了两种,一直在模拟器内复现、一种是刷机。

环境配置:Ubuntu18.08、pixel手机。

必须是复现成功了才来分析的,只不过没有保存成功的图。失败的图一大堆...

反正最终的结论是:

对于环境来说,稳定的Ubuntu版本,可以编译Android9的手机就行。

对于选择分析环境,race 属于对时序有要求的漏洞,这类漏洞,一般来说虚拟环境性能达不到,前后两个进程时序差太多也可能跑不起来,所以还是建议用真机做实验。如果一定要用模拟器做,给出如下两个建议1.在源码的setMediaCasSession函数里 设置sleep 。2.调高PoC程序优先级(没试过)。

race 的Exp 我以后尝试写吧。

0x05 补丁

让我们看看补丁


diff的代码感觉挺多的,主要是两个方面,

  • 把强指针sp\<clearkeycassession>改为了智能指针shared_ptrs。(shared_ptrs可以使多个指针指向同一个对象,并且同时使用计数操作。std::shared_ptr\<clearkeycassession>。)</clearkeycassession></clearkeycassession>

  • 使用 std::atomic。(原子操作简单来讲:针对原子类型操作要不一步完成,要么不做,不可能出现操作一半被切换CPU,这样防止由多线程指令交叉执行带来的可能错误[3])

  • 在descramble的代码里面增加了一行代码,descramble 用shared_ptr 指向session,std::atomic方式load的session。


    frameworks/av/drm/mediacas/plugins/clearkey/ClearKeyCasPlugin.cpp  这里面有两处加了std::atomic操作,分别是 std::atomic_store、std::atomic_load。

    0x06 结束语

    这是我第一篇分析文章,不正确或者有疑问的地方欢迎指出,希望能向大家多多学习。

    [1] https://blog.zimperium.com/cve-2018-9539-use-free-vulnerability-privileged-android-service/
    [2] https://source.android.com/devices/architecture/hidl
    [3] https://blog.csdn.net/liuxuejiang158blog/article/details/17413149


    转自先知社区

    打赏我,让我更有动力~

    0 Reply   |  Until 2019-8-3 | 655 View
    LoginCan Publish Content
    返回顶部 投诉反馈

    掌控者 © 2016. All Rights Reserved. 掌控者

    Powered by 掌控者 Version 2.1.3