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 进行改写。
图:PendingIntent 面临的安全风险
因此, 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:
图:BroadcastAnyWhere 漏洞
由于这个广播 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 开关进行操作。如图所示。
图:NFC 设置 Slice
Slice 中的动作 SliceAction,实质是通过 PendingIntent 实现的。
如图,按照 SliceProvider 的设计,作为 SlicePresenter 的 App 可以通过调用系统 APISliceVIewManager.bindSlice 去 bind 一个特定 URI 的 SliceProvider,或者直接使用更加底层的 SliceProvider call 函数去获得一个 Slice,进而获得 Slice 中的 PendingIntent,文章具体描述了使用 call 函数获取 SliceProvider 中 Slice PendingIntent 的方法,从 Slice 对象中获取 PendingIntent 需要层层剥丝抽茧:
图:SliceProvider 架构概览
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,获得媒体内容层次结构的表示,如播放列表、媒体库等等,并获得有关播放状态的回调信息。
图:MediaBrowserService 架构概览
3.4 AppWidgets
AppWidgets 就是可以在 Android 桌面上添加的窗口小部件。按照开发者文档,AppWidgets 上可以在其他应用(如桌面 Launcher)中显示,并接受周期性更新的迷你程序视图。
AppWidget 可以通过 AppWidgetProvider 发布,容纳 AppWidiget 的应用称为 AppWidgetHost。
AppWidgetHost 通过安卓系统提供的 AppWidgetFramewor
访问(bind)AppWidgetProvider,并接受有关的 AppWidget 的变化信息,如图所示。
图:AppWidgets 架构概览
用户可以在桌面中看到的窗口小部件,实质是通过 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/2014/11/14/broadAnywhere-bug-17356824.html
[2]https://www.slideshare.net/CanSecWest/csw2016-chaykin-havingfunwithsecuremessengersandandroidwear
[3]https://mp.weixin.qq.com/s/SAhXsCHvAct_2SxCXd2w0Q
[4] http://soot-oss.github.io/soot/
[5]https://developer.android.com/about/versions/12/behavior-changes-12#pending-intent-mutability
作者简介
heeeeen 安全架构师
毕业于北京航空航天大学,擅长 Android 框架与 APP 漏洞挖掘,多次获得 Google 安全致谢
获取更多精彩内容,请扫码关注[OPPO 数智技术]公众号
版权声明: 本文为 InfoQ 作者【OPPO数智技术】的原创文章。
原文链接:【http://xie.infoq.cn/article/5f9fafb3da770ddc316f2f1ef】。文章转载请联系作者。
评论