乐趣区

关于安全:PendingIntent重定向一种针对安卓系统和流行App的通用提权方法BlackHat-EU-2021议题详解上

1 简介

1.1 Intent

安卓零碎中,Intent 是在组件间传递的通信音讯,用于执行关上 Activity、发送播送、启动服务等动作,而 Intent 对象外部的字段则规定了 Intent 发送的目标组件,以及执行动作的具体内容,包含 action、category、data、clipdata、package、flag、extra、component 和 selector。

其中 component 和 selector 用于设置 Intent 的目标组件,规定 Intent 发送给谁。依照是否设置 component 和 selector,Intent 可划分为:

• 显式 Intent:具备 component 或者 selector 的 Intent
• 隐式 Intent:仅设置了 action 的 Intent,注册对应 action 的 Intent-filter 的组件能够接管到 Intent。

另外,还有一种非凡的空 Intent new Intent(),既没有设置 component,也没有设置 action,甚至没有设置任何字段。

1.2 PendingIntent

PendingIntent 能够看作 Intent 的高级版本,实现了一种委托受权发送 Intent 进行组件间通信的机制。

首先,App 能够应用 getActivity、getBroadcast、getService 等 API 向 Android 零碎申请一个 PendingIntent 对象,例如在函数 getActivity:

中,intent 参数形成了所⽣成 PendingIntent 对象的 base Intent,⽽在此特定的 getActivity 函数中,该 base Intent 应该⽤于关上 Activity,否则⽆意义。后⾯的 flags 参数决定了 PendingIntent 的⾏为,例如 FLAG_IMMUTABLE 就⽤于规定 base Intent 不能被改写。

接下来,这个 PendingIntent 对象能够发送给其余 App 应用,其余 App 调用 PendingIntent.send 时,就可能以 PendingIntent 源 App 的身份和权限发送 PendingIntent 中的 base Intent。其余 App 甚至还能够提供一个新的 Intent,对 base Intent 进行改写。

因而,App A 将 PendingIntent 交给 App B,就意味着将本人的身份与权限连同要做的事件委托给了 App B,这个事件由 PendingIntent 中的 base Intent 指定。

如果歹意 App 有能力获取上述通信过程中的 PendingIntent,就可能以源 App 的身份和权限发送批改后的 base Intent,造成非预期的平安结果,这就是 PendingIntent 面临的平安危险。

2 历史钻研

以往的钻研波及的理论破绽案例不多,一个驰名的例子是 Android 零碎 AccountManagerService 中的 BroadcastAnyWhere 破绽,波及到 Settings App、System Server 与 Authenticator App 的简单交互。

在上面 Step 2 中 AccountManagerService 通过 addAccount 回调函数提供给 AppB Authenticator 的 options bundle 对象中,蕴含了一个 PendingIntent,其 base Intent 为空 Intent:


因为这个播送 PendingIntent 由 system_server AccountManagerService(uid 1000)所创立,代表了零碎的身份和权限,且并未设置 base Intent 的其余字段。一般 Authenticator App 拿到当前,改写其 base Intent,例如设置一个 action

android.intent.action.BOOT_COMPLETED,最初调用 PendingIntent.send 以 uid 1000 的身份发送特权播送。

第二个案例来源于 CanSecWest2016 的分享,即时通信软件 LINE App 启动服务时透露了一个 PendingIntent 对象,且 base Intent 为空 Intent:

下面启动服务应用的隐式 Intent, 因而歹意 APP 能够注册一个 Intent-filter 为
jp.naver.android.npush.intent.action.SUBSCRIBE 的服务,而后获取下面的 PendingIntent,最初以 LINE App 的身份发送播送,造成伪造 LINE App 推送音讯的危害。

3 PendingIntent 应用场景

以往公开的钻研仅给出了两个无关不平安 PendingIntent 应用的罕见案例,均为携带空 Intent 的播送 PendingIntent,在 IPC 通信中透露给了歹意 App。然而,PendingIntent 在 Android 零碎的应用中又如此宽泛,在 IPC 通信中的应用仅为冰山一⻆。

PendingIntent 还能够宽泛存在于 SliceProviders、告诉 (Notifications)、媒体浏览服务(MediaBrowserServices)、窗口小部件(AppWidgets)、定时器管理器(AlarmManager) 当中,这就涉及了本议题要解决的第一个问题:Android 中这些宽泛应用的 PendingIntent 是否有可能被 App 获取,如何获取?

通过咱们钻研发现,安卓零碎中宽泛应用的 SliceProvider、告诉、窗口小部件、媒体浏览服务所应用的 PendingIntent,都有可能被歹意 APP 获取,这就极大地拓展了 PendingIntent 的攻击面。

3.1 SliceProvider

SliceProvider 是自 Android P 开始引入的一种应用程序间共享 UI 界面的机制,Slice 的出现者(SlicePresenter),能够通过 Slice URI 和 Android 零碎提供的 bindSlice 等 API 来拜访另一个 App 通过 SliceProvider 分享进去的 Slice。

简言之,Slice 就是可分享的 UI 界面,包含图标、文本和动作(SliceAction),Slice 通过 URI 来惟一标识。例如 Settings 中关上 NFC 开关的这个界面,就能够通过 SettingsSliceProvider 中

content://android.settings.slices/action/toggle_nfc 这个 URI 共享给别的利用应用,用户不用关上 Settings,就能够在其余利用界面中对 NFC 开关进行操作。如图所示。

Slice 中的动作 SliceAction,本质是通过 PendingIntent 实现的。

如图,依照 SliceProvider 的设计,作为 SlicePresenter 的 App 能够通过调用零碎 APISliceVIewManager.bindSlice 去 bind 一个特定 URI 的 SliceProvider,或者间接应用更加底层的 SliceProvider call 函数去取得一个 Slice,进而取得 Slice 中的 PendingIntent,文章具体形容了应用 call 函数获取 SliceProvider 中 Slice PendingIntent 的办法,从 Slice 对象中获取 PendingIntent 须要层层剥丝抽茧:

3.2 Notifications

告诉在 Android 零碎中利用极为宽泛,用于在状态栏中对用户进行提醒,简直为每个 App 所应用,是安卓开发者最常应用 PendingIntent 的中央,如下为发送告诉的示例代码

通过 setContentIntent 办法对告诉设置了一个 contentIntent PendingIntent,使用户在点击告诉的注释时,触发 PendingIntent,跳转到 AlertDetails。除了 contentIntent 外,告诉中还能够设置其余按钮,通过 actionIntent 进行设置,上面的告诉示例表明了告诉中的各种 PendingIntent。另外,告诉还可能包含另外一个 deleteIntent PendingIntent,在被用户删除告诉时触发。

对于告诉中 PendingIntent 的获取,安卓零碎提供了告诉监听服务 NotificationListenerService,

任何三方 App 都能够实现该服务对告诉进行监听。

通过用户受权后,告诉监听服务就能够取得告诉对象,进而取得对象中的 PendingIntent。如下,能够在 onNotificationPosted 回调函数中获取告诉及其 content Intent PendingIntent。

3.3 MediaBrowserService

媒体浏览器服务 MediaBrowserService 与音乐播放无关,能够让其余 App 发现、浏览媒体内容并管制播放。媒体浏览服务中也可能应用 PendingIntent 来作为回调。那么其余 App 能够实现媒体浏览器 MediaBrowser 来连贯 MediaBrowserService,进而获取 PendingIntent。

MediaBrowser 与 MediaBrowserService 的实现架构如图所示。MediaBrowser 作为客户端,实现了 UI、媒体管制和媒体浏览的性能,连贯 MediaBrowserService,取得媒体内容层次结构的示意,如播放列表、媒体库等等,并取得无关播放状态的回调信息。

3.4 AppWidgets

AppWidgets 就是能够在 Android 桌面上增加的窗口小部件。依照开发者文档,AppWidgets 上能够在其余利用 (如桌面 Launcher) 中显示,并承受周期性更新的迷你程序视图。

AppWidget 能够通过 AppWidgetProvider 公布,包容 AppWidiget 的利用称为 AppWidgetHost。

AppWidgetHost 通过安卓零碎提供的 AppWidgetFramewor
拜访(bind)AppWidgetProvider,并承受无关的 AppWidget 的变动信息,如图所示。

用户能够在桌面中看到的窗口小部件,本质是通过 RemoteViews 实现。RemoteView 将本属于 AppWidgetProvider 利用中的 View,跨过程传输,在 AppWidgetHost 利用中显示。留神到 RemoteView 存在上面一个无关 PendingIntent 的 API,用来设置其中按钮被点击后的行为。

通过实现 AppWidgetHost,拜访 AppWidgetProvider 中的 AppWidgets,获取 RemoteView,进而有可能获取 RemoteView 中的 PendingIntent。

RemoteViews 能够通过 AppWidgetServiceImpl 中的下列 AIDL 接口拿到

然而拿到 RemoteViews 当前再获取 PendingIntent 却颇费周折,因为 RemoteViews 并未提供公开 API 来获取其中的 PendingIntent。但通过剖析,咱们发现能够通过反射,依照如下程序逐次获取暗藏的成员变量 mPendingIntent。

至此,咱们曾经解决了本议题的第一个问题,通过钻研表明,Android 零碎中应用的 PendingIntent 大都能够被三方 App 获取,获取形式包含 bind SliceProvider、监听告诉、连贯媒体浏览器服务或者 bind 包容窗口小部件的 AppWidgetsProvider。

注:本文是对 OPPO 平安子午实验室发表在 Blackhat EU 2021 会议议题:Re-route Your Intent forPrivilege Escalation: A Universal Way to Exploit Android PendingIntents in High-profile and SystemApps 的技术文稿整顿。

感激 OPPO 平安与子午实验室对议题发表的大力支持! 感激前共事陈文波和香港中文大学吴道远两位同作者对本议题的奉献!

下篇咱们将持续探讨第二个关键问题:如果这些 PendigIntent 不平安,如何利用能力造成平安危害?敬请关注!

4、参考

[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 平安架构师

毕业于北京航空航天大学,善于 Android 框架与 APP 破绽开掘,屡次取得 Google 平安致谢。

获取更多精彩内容,请扫码关注 [OPPO 数智技术] 公众号

退出移动版