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

2019-08-03 约 119 字 预计阅读 1 分钟

声明:本文 【CVE-2018-9539特权Android服务中的Use-After-Free】 由作者 mmmiy1**** 于 2019-08-03 09:14:00 首发 先知社区 曾经 浏览数 102 次

感谢 mmmiy1**** 的辛苦付出!

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 对象

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

    1. 同时:

      • 运行多个线程,通过Descrambler对象执行解密。
      • 将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

关键词:[‘安全技术’, ‘漏洞分析’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now