1 Introduction

1.1 Intent

In the Android system, an Intent is a communication message passed between components, which is used to perform actions such as opening an Activity, sending a broadcast, and starting a service. The fields inside the Intent object specify the destination component sent by the Intent and the specific content of the execution action. Including action, category, data, clipdata, package, flag, extra, component and selector.

The component and selector are used to set the purpose component of the Intent and specify to whom the Intent is sent. According to whether to set component and selector, Intent can be divided into:

• Explicit Intent: Intent with component or selector
• Implicit Intent: Only the Intent of the action is set, and the component that registers the Intent-filter corresponding to the action can receive the Intent.

In addition, there is a special kind of empty Intent new Intent(), which neither sets the component nor the action, nor even sets any fields.

1.2 PendingIntent

PendingIntent can be regarded as an advanced version of Intent, which implements a mechanism for delegating authorization to send Intent for inter-component communication.

First, the App can apply for a PendingIntent object to the Android system using APIs such as getActivity, getBroadcast, and getService, for example, in the function getActivity:

, the intent parameter constitutes the base Intent of the generated PendingIntent object, and in this specific getActivity function, the base Intent should be used to open the Activity, otherwise it is meaningless. The following flags parameter determines the behavior of the PendingIntent, for example FLAG_IMMUTABLE is used to specify that the base Intent cannot be overwritten.

Next, this PendingIntent object can be sent to other apps for use. When other apps call PendingIntent.send, they can send the base Intent in the PendingIntent with the identity and permissions of the PendingIntent source app. Other apps can even provide a new Intent that rewrites the base Intent.

Therefore, when App A hands the PendingIntent to App B, it means that it entrusts its own identity and permissions together with the things to be done to App B, which is specified by the base Intent in the PendingIntent.

If the malicious App has the ability to obtain the PendingIntent in the above communication process, it may send the modified base Intent with the identity and authority of the source App, resulting in unexpected security consequences. This is the security risk faced by the PendingIntent.

2 Historical research

There are not many actual vulnerability cases involved in previous research. A well-known example is the BroadcastAnyWhere vulnerability in the AccountManagerService of the Android system, which involves complex interactions between Settings App, System Server and Authenticator App.

In the following Step 2, the options bundle object provided by AccountManagerService to AppB Authenticator through the addAccount callback function contains a PendingIntent whose base Intent is an empty Intent:


Since this broadcast PendingIntent is created by system_server AccountManagerService (uid 1000), it represents the identity and authority of the system, and other fields of base Intent are not set. After getting the ordinary Authenticator App, rewrite its base Intent, such as setting an action

android.intent.action.BOOT_COMPLETED , and finally call PendingIntent.send to send the privileged broadcast as uid 1000.

The second case comes from the sharing of CanSecWest2016. When the instant messaging software LINE App starts the service, a PendingIntent object is leaked, and the base Intent is an empty Intent:

The implicit Intent used by the startup service above, so a malicious APP can register an Intent-filter as
jp.naver.android.npush.intent.action.SUBSCRIBE service, then obtain the above PendingIntent, and finally send the broadcast as the identity of the LINE App, causing the harm of fake LINE App push messages.

3 PendingIntent usage scenarios

Previously published research only gave two rare cases about the use of unsafe PendingIntents, both of which were broadcast PendingIntents carrying empty Intents, which were leaked to malicious apps in IPC communication. However, PendingIntent is so widely used in the Android system, and its use in IPC communication is only an iceberg.

PendingIntent can also widely exist in SliceProviders, Notifications, MediaBrowserServices, Widgets (AppWidgets), Timer Managers (AlarmManager), which touches on the first problem to be solved in this topic: it possible for the widely used PendingIntent in Android to be acquired by the App, and how?

After our research, we found that the PendingIntent used by SliceProvider, notifications, widgets, and media browsing services widely used in the Android system may all be acquired by malicious APPs, which greatly expands the attack surface of PendingIntent.

3.1 SliceProvider

SliceProvider is a mechanism for sharing UI interface between applications introduced since Android P. The Slice Presenter (SlicePresenter) can access the Slice shared by another App through SliceProvider through APIs such as Slice URI and bindSlice provided by the Android system. .

In short, Slice is a shareable UI interface, including icons, text and actions (SliceAction), and Slice is uniquely identified by URI. For example, the interface of opening the NFC switch in Settings can be accessed through SettingsSliceProvider

content://android.settings.slices/action/toggle_nfc This URI is shared with other applications. Users can operate the NFC switch in other application interfaces without opening Settings. as the picture shows.

The action in Slice, SliceAction, is actually implemented through PendingIntent.

As shown in the figure, according to the design of SliceProvider, an App as a SlicePresenter can bind a SliceProvider with a specific URI by calling the system APISliceVIewManager.bindSlice, or directly use the lower-level SliceProvider call function to obtain a Slice, and then obtain the PendingIntent in the Slice. The article is specific Describes the method of using the call function to obtain the Slice PendingIntent in the SliceProvider. Obtaining the PendingIntent from the Slice object requires layer by layer peeling and cocooning:

3.2 Notifications

Notifications are widely used in the Android system. They are used to prompt users in the status bar. They are used by almost every app and are the most common place for Android developers to use PendingIntent. The following is the sample code for sending notifications.

A contentIntent PendingIntent is set for the notification through the setContentIntent method, so that when the user clicks the body of the notification, the PendingIntent is triggered and jumps to AlertDetails. In addition to the contentIntent, other buttons can also be set in the notification, which can be set through the actionIntent. The following notification example shows various PendingIntents in the notification. In addition, the notification may also include another deleteIntent PendingIntent, which is triggered when the notification is deleted by the user.

For the acquisition of PendingIntent in the notification, the Android system provides the notification listener service NotificationListenerService.

Any third-party App can implement this service to monitor notifications.

After the user's authorization, the notification monitoring service can obtain the notification object, and then obtain the PendingIntent in the object. As follows, the notification and its content Intent PendingIntent can be obtained in the onNotificationPosted callback function.

3.3 MediaBrowserService

The media browser service MediaBrowserService is related to music playback, allowing other apps to discover, browse media content and control playback. Media browsing services may also use PendingIntent as a callback. Then other apps can implement the media browser MediaBrowser to connect to the MediaBrowserService, and then get the PendingIntent.

The implementation architecture of MediaBrowser and MediaBrowserService is shown in the figure. As a client, MediaBrowser implements the functions of UI, media control and media browsing, connects to MediaBrowserService, obtains the representation of media content hierarchy, such as playlist, media library, etc., and obtains callback information about playback status.

3.4 AppWidgets

AppWidgets are widgets that can be added to the Android desktop. According to the developer documentation, AppWidgets can be displayed in other applications (such as the desktop Launcher) and receive a periodically updated mini-program view.

AppWidget can be published through AppWidgetProvider, and the application that accommodates AppWidget is called AppWidgetHost.

AppWidgetHost through the AppWidgetFramewor provided by the Android system
Access (bind) AppWidgetProvider, and accept the change information about the AppWidget, as shown.

The widgets that users can see on the desktop are essentially implemented through RemoteViews. RemoteView transfers the View that belongs to the AppWidgetProvider application across processes and displays it in the AppWidgetHost application. Note that RemoteView has the following API for PendingIntent, which is used to set the behavior of the button after it is clicked.

By implementing AppWidgetHost, access AppWidgets in AppWidgetProvider, get RemoteView, and then it is possible to get PendingIntent in RemoteView.

RemoteViews can be obtained through the following AIDL interfaces in AppWidgetServiceImpl

But getting the PendingIntent after getting the RemoteViews is a lot of trouble, because RemoteViews does not provide a public API to get the PendingIntent. But after analysis, we found that the hidden member variable mPendingIntent can be obtained successively through reflection in the following order.

So far, we have solved the first problem of this topic. After research, it is shown that most of the PendingIntent used in the Android system can be obtained by three-party apps. The acquisition methods include bind SliceProvider, monitor notifications, connect to the media browser service, or bind to accommodate the small window. The widget's AppWidgetsProvider.

Note: This article is a compilation of technical documents published by OPPO Security Meridian Lab at the Blackhat EU 2021 conference topic: Re-route Your Intent for Privilege Escalation: A Universal Way to Exploit Android PendingIntents in High-profile and SystemApps.

I would like to thank OPPO Security and Meridian Lab for their strong support in publishing the topic! I would like to thank former colleagues Chen Wenbo and Wu Daoyuan from the Chinese University of Hong Kong for their contributions to this topic!

In the next article, we will continue to explore the second key question: If these PendigIntents are not safe, how can they be used to cause security hazards? stay tuned!

4. Reference

[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

About the Author

heeeeen security architect

Graduated from Beijing University of Aeronautics and Astronautics, he is good at Android framework and APP vulnerability mining, and has received many thanks from Google for security.

For more exciting content, please scan the code and follow the [OPPO Digital Intelligence Technology] public account


OPPO数智技术
612 声望950 粉丝