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数智技术]公众号