以用户隐衷平安为核心,用责任兑付信赖,OPPO 成立子午互联网安全实验室(ZIWU Cyber Security Lab)。实验室以“爱护用户的平安与隐衷,为品牌注入平安基因”为使命,继续关注并发力于业务平安、红蓝反抗、IoT 平安、Android 平安、数据和隐衷爱护等畛域。
本篇文章源自 OPPO 子午互联网安全实验室。
1 不平安 PendingIntent 的通用利用办法
1.1 不平安 PendingIntent 的特色
至此,咱们曾经解决了本议题的第一个问题,通过钻研表明,Android 零碎中应用的 PendingIntent 大都 能够被三方 App 获取。
获取形式包含 bind SliceProvider、监听告诉、连贯媒体浏览器服务或者 bind 包容 窗口小部件的 AppWidgetsProvider。
于是,引入议题钻研的第二个关键问题: 如果这些 PendigIntent 不平安,如何利用能力造成平安危害?
首先,咱们须要分别什么样的 PendingIntent 是不平安的。后面形容的公开破绽案例,均为劫持 base Intent 为空 Intent 的播送 PendingIntent,阐明如下 empty base Intent 构建的 PendingIntent 确定存在平安问题。
Android 12 之前的开发者文档也对 base Intent 为隐式 Intent 的 PendingIntent 提出了平安正告,但却没 有明确告知到底存在何种危害。而且在 AOSP 代码和风行 App 当中,如下的代码模式宽泛存在。这不禁让 咱们考虑,Implicit base Intent 构建的 PendingIntent 是否真正存在问题? 唯有找到一种确定的针对这 种 PendingIntent 的破绽利用办法,能力真正证实平安问题的存在。
1.2 深刻 Intent fillIn 改写机制
寻找利用办法之前,须要深刻摸索 PendingIntent 的改写机制,这决定了其余 App 取得 PendingIntent 以 后,如何对 base Intent 进行改写。这个机制由 Intent.fillIn 函数提供:
在上述代码中,this 对象指向以后 Intent,other 为其余 Intent。如果以后 Intent 中的成员变量为空,则可 以被 other 中相应的成员变量笼罩。比拟非凡的是 Intent 中的 component 和 selector 成员,即便以后 Intent 中的 component 和 selector 为空,也不能被 other 所改写,除非 PendingIntent
设置了 FILL_IN_COMPONENT
或者 FILL_IN_SELECTOR 标记。
1.3 PendingIntent 重定向攻打
因而在获取 PendingIntent 之后,其 base Intent 的 action、category、data、clidpdata、package、flag、extra 等成员都是有可能改写的,而 component 和 selector 无奈改写,如图所示。特地地,对于 base Intent 为隐式 Intent 的这种状况,action 曾经被设置了,因而也无奈被改写,攻击者无奈如后面安 卓零碎 broadcastAnyWhere 破绽那样,通过劫持 PendingIntent、在 base Intent 中从新增加 action,隐式关上一个受爱护的组件。
图 Intent 成员
这里就来到了问题解决的关键点,因为 package 能够指定,回想到以前在 Intent Bridge 破绽中的利用方 法,咱们能够通过设置 intent 中的 flag 来奇妙地解决这个问题。Intent 提供了无关长期受权的标记:
- FLAG_GRANT_READ_URI_PERMISSION:Intent 携带此标记时,Intent 的接收者将取得 Intent 所携 带 data URI 以及 clipdata URI 中的读权限
- FLAG_GRANT_WRITE_URI_PERMISSION:Intent 携带此标记时,Intent 的接收者将取得 Intent 所携 带 data URI 以及 clipdata URI 中的写权限
简言之,歹意 App 对 PendingIntent 进行了指向歹意 App 本人的重定向,通过对 PendingIntent base Intent 的局部批改(批改包名、受权标记和 data/clipdata),使其以受益 App 的权限关上歹意 App 本身,这样歹意 App 在被关上的霎时即取得对受益 App 公有数据的读写权限。具体的利用办法如图所示:
图 PendingIntent 重定向攻打
步骤如下:
1、受益 App 通过 getActivity 构建 PendingIntent,在告诉、SliceProvider、窗口小部件中应用,假设其 base Intent 为隐式 Intent;
2、攻打 App 通过后面探讨的各种渠道获取受益 App 的 PendingIntent;
3、攻打 App 批改 PendingIntent 中的 base Intent,因为是隐式 Intent,因而 action、component 和 selector 都不能批改。但能够做如下批改:
- 批改 data 或者 clidpdata,使其 URI 指向受益 App 的公有 ContentProvider;
- 批改 package,指向攻打 App;
- 增加 FLAG_GRANT_READ_URI_PERMISSION 和 FLAG_GRANT_WRITE_URI_PERMISSION 标记。
同时攻打 App 申明一个 Activity 反对隐式启动,其 Intent-filter 与 base Intent 中的 action 统一。
4、攻打 App 调用 PendingIntent.send;
5、因为这个 PendingIntent 代表了受益 App 的身份和权限,因而将以受益 App 的名义发送批改后的 base Intent,关上攻打 App 的 Activity;
6、在攻打 App Activity 被关上的霎时,即被受权拜访 base Intent 中携带的 URI,也就取得了对受益 App 公有 ContentProvider 的读写权限。
下面受益 App 的公有 ContentProvider,须要携带属性 grantUriPermission=true,不限于受益 App 自 己的 ContentProvider,也包含受益 App 有权限拜访的 ContentProvider。手机上一个常⻅的具备 grantUriPermission=true 属性的 ContentProvider 就是代表通讯录的 Contacts Provider,只有受 害 App 具备 READ_CONTACTS 权限,呈现这样一个 PendingIntent 破绽后将导致通讯录泄露。
这样,咱们通过上述 6 个步骤,就能够胜利实现对隐式 Intent 构建 PendingIntent 的破绽利用,读写受益 App 的公有数据,这也就解决了本钻研提出的第二个关键问题: 通过隐式 Intent 构建的 PendingIntent 可蒙受通用的重定向提权攻打,也是不平安的。
因为这里应用了 grantUri 的技巧,因而并不适用于 broadcast PendingIntent,因为播送接收器是不能够 被 grantUri 的。另外,从 Android 5.0 当前,Service 不能隐式启动,因而也很难看到 base Intent 为隐式 Intent 的 service PendingIntent。所以,这里的 PendingIntent 重定向攻打次要实用于 Activity PendingIntent。
2 安卓零碎中的实在案例
令人诧异的是,在 Android 12 之前的 AOSP 代码以及风行 App 中,隐式 Intent 构建的 ActivityPendingIntent 宽泛存在,以下是咱们发现的典型案例,可能导致手机的敏感信息泄露,甚至以受益 app 的权限执行任意代码。这些破绽案例均已被厂商所修复。
图 不平安 PendingIntent 典型案例
2.1 CVE-2020-0188
不平安的 PendingIntent 存在于 AOSP SettingsSliceProvider 中,
一旦 SettingsSliceProvider 被 blind,
在返回的 Slice 中将携带一个不做任何操作的 noOpIntentPendingIntent:
攻打 App 通过 bind SettingsSliceProvider 获取 PendingIntent,批改 base Intent 并以 Settings 的权限发送,期待本人的 Activity 被关上,就能够实现 Settings 某些公有 Content Provider 的读写。如图所示:
图 CVE-202-0188 POC
2.2 CVE-2020-0389
不平安的 PendingIntent 存在于
AOSP SystemUI RecordingService 当中,为用户录屏保留胜利后发送的告诉所应用。
歹意 App 能够实现一个 NotificiationListener
Service,批改 base Intent,将其 clipdata 指向 ContactsProvider :
因为 SystemUI 具备 READ_CONTACTS 权限,因而歹意 App 被关上时,即可胜利读取通讯录。
2.3 A-166126300
不平安的 PendingIntent 存在 AOSP BluetoothMediaBrowserService 中
歹意 App 能够连贯 BluetoothMediaBrowserService,通过 MediaBrowserCompat.ConnectionCallback 获取 PendingIntent。
因为 BluetoothMediaBrowserService 存在于具备通讯录权限 Bluetooth 利用中,因而通过 PendingIntent 重定向攻打可读取通讯录
2.4 某风行 App
某具备通讯录权限的风行 App 实现了窗口小部件,用户点击窗口小部件的按钮实现跳转,但这个跳转是通过隐式 Intent 构建 PendingIntent 实现的。
对窗口小部件所属的 AppWidgetProvider 进行 bind,通过反射逐次获取 RemoteViews->mActions->mResponse->mPendingIntent,最终能够拿到上述不平安的 PendingIntent,进而如法炮制,读取通讯录。
2.5 CVE-2020-0294
这些不平安的 PendingIntent 存在安卓零碎服务中,对于某些 bind 服务,零碎提供了 PendingIntent,跳转到服务的治理界面。
这些 PendingIntent 能够间接通过零碎 APIActivityManager.getRunningServiceControlPanel 取得,前面进行 PendingIntent 重定向,读取 Settings 中的爱护 ContentProvider。
2.6 危害
上述多个案例均可造成通讯录这类集体敏感信息泄露,但实际上,因为 PendingIntent 重定向攻打还具备写数据的能力,因而可能造成更大的危害。
例如,很多 App 都具备热更新性能,个别将 dex/jar/apk/so 等文件放在本人的公有目录中,如果这些公有目录能够被 grantUriPermission=true 的 ContentProvider 所援用,就能够利用 PendingIntent 重定向攻打去改写热更新文件,将攻击者本人的代码注入到其中,实现以受益 App 的权限执行任意代码。
对于 CVE-2020-0188 和 CVE-2020-0294 这类源于零碎 uid 的 PendingIntent,因为在 UriGrantsManagerService 当中进行了限度,因而在原生零碎中的危害很无限,只能读取特定的几个 Content Provider。
然而因为 Android 零碎的定制化,上述限度可能在 OEM 厂商中被突破,造成更大的危害。
Google 对安卓零碎中这类破绽的修复,起初是将 base Intent 设置为显式 Intent,指定明确的组件。起初均应用 FLAG_IMMUTABLE 修复,当应用这个 flag 时,PendingIntent 的 base Intent 将无奈通过 Intent.fillIn 函数改写,例如
3 自动化剖析
基于对不平安 PendingIntent 特色的把握,咱们编写了一个自动化扫描工具 PendingIntentScan,该工具基于 Soot[4]这一 Java 动态剖析框架对 apk 进行数据流动态剖析,其体系结构如图所示。
图 PendingIntentScan 原理
首先,应用 Soot 将 apk 的字节码转换为 Jimple 模式的 IR,而后搜查一系列生成 PendingIntent 的 API,并挑选出没有应用 FLAG_IMMUTABLE 的:
而后,通过 Soot 提供的 ForwardFlowAnalysis 对 PendingIntent 的 Intent 参数进行查看,查看是否调用下列函数。如果都没有应用,则认为 PendingIntent 是不平安的:
这个工具目前开源在
https://github.com/h0rd7/Pend…,能够迅速发现 apk 中存在的不平安 PendingIntent,成果如下。
4 安卓 12 平安变更
针对咱们的研究成果,Google 安卓平安团队对 AOSP 代码进行了全面排查,简直修复了所有的不平安 PendingIntent。大部分的修复应用了 PendingIntent.FLAG_IMMUTABLE,小局部的修复将 base Intent 设置为显式 Intent。
而在 Android 12 大版本中,安卓系统对 PendingIntent 的行为进行了重大平安变更,引入了一个新的 flag:PendingIntent.FLAG_MUTABLE,示意 base Intent 能够改写。这与原有的 FLAG_IMMUTABLE 独特形容 PendingIntent 的可变性。
对于 Target S+ 的 App,Android 零碎要求开发者必须明确指定 PendingIntent 的可变性,FLAG_IMMUTABLE 和 FLAG_MUTABLE 必须应用其一,否则零碎会抛出异样。这就要求开发者对本人 PendingIntent 的应用有清晰的了解,晓得 PendingIntent 是否会在未来被改写。
Google 也对开发者提出了具体的平安编码倡议:
- 尽可能应用 FLAG_IMMUTABLE 来生成不可改写的 PendingIntent;
- 如果应用 FLAG_MUTABLE 来生成可改写的 PendingIntent,base Intent 肯定要应用显式 Intent,明确指定 Intent 的组件。
同时 AndroidStuido IDE 中也引入了一个新的 lint 查看插件 PendingIntentMutableFlagDetector,用于查看 PendingIntent 是否应用了 FLAG_IMMUTABLE。
5 论断
本议题解决了 PendingIntent 的获取问题,明确了不平安 PendingIntent 的特色,提出了无关不平安 PendingIntent 的重定向攻打利用办法,从而揭示了安卓零碎和风行 app 无关 PendingIntent 应用的一种通用平安⻛险。Google 针对议题形容的破绽均已进行了修复,并在 Android 12 中引入了缓解此问题的重大平安变更,对开发者提出了具体的平安编码倡议。
开发者在应用 FLAG_IMMUTABLE 构建 PendingIntent 时应分外小心,除了要应用显式 Intent 以外,还要保障 base Intent 其余没有填充的字段不会造成平安影响。例如上面存在问题的代码源于一个实在 app 的案例。这个 PendingIntent 曾经设置了显式 Intent,在告诉中应用,用于启动外部不导出的 MainActivity
在 MainActivity 中,
能够对 EXTRA_REDIRECT_INTENT 进行解决,最初调用 startActivity:
这样,劫持 PendingIntent 依然能够设置 EXTRA_REDIRECT_INTENT,通过 startActivity 去关上利用的任意爱护组件。
因而,每一个没有应用 FLAG_IMMUTABLE 的 PendingIntent 均应该认真审查,这是咱们对开发者的最初平安忠告。
6、参考
[1]http://retme.net/index.php/20…
[2]https://www.slideshare.net/Ca…
[3]https://mp.weixin.qq.com/s/SA…
[4] http://soot-oss.github.io/soot/
[5]https://developer.android.com…
作者简介
heeeeen 平安架构师
毕业于北京航空航天大学,现工作于 OPPO 子午互联网安全实验室,善于 Android 框架与 APP 破绽开掘,屡次取得 Google 平安致谢
获取更多精彩内容,请扫码关注 [OPPO 数智技术] 公众号