From fcfa9a37f00cb64f91f922a44bedeb9090103d8f Mon Sep 17 00:00:00 2001 From: Vikas Gupta Date: Tue, 25 Oct 2022 21:51:18 +0530 Subject: [PATCH 1/2] Content for pendingintent --- .../0x05h-Testing-Platform-Interaction.md | 113 +++++++++++++++++- 1 file changed, 108 insertions(+), 5 deletions(-) diff --git a/Document/0x05h-Testing-Platform-Interaction.md b/Document/0x05h-Testing-Platform-Interaction.md index cfdda1f7da..2f61de7146 100644 --- a/Document/0x05h-Testing-Platform-Interaction.md +++ b/Document/0x05h-Testing-Platform-Interaction.md @@ -312,7 +312,7 @@ requested permissions: install permissions: com.google.android.c2dm.permission.RECEIVE: granted=true android.permission.USE_CREDENTIALS: granted=true - com.google.android.providers.gsf.permission.READ_GSERVICES: granted=true + com.google.android.providers.gsf.permission.READ_GSERVICES: granted=true ... ``` @@ -558,7 +558,7 @@ As we mentioned before, [handling page navigation](https://developer.android.com - This is not called for `javascript:` or `blob:` URLs, or for assets accessed via `file:///android_asset/` or `file:///android_res/` URLs. In the case of redirects, this is only called for the initial resource URL, not any subsequent redirect URLs. - When Safe Browsing is enabled, these URLs still undergo Safe Browsing checks but the developer can allow the URL with `setSafeBrowsingWhitelist` or even ignore the warning via the `onSafeBrowsingHit` callback. - + As you can see there are a lot of points to consider when testing the security of WebViews that have a WebViewClient configured, so be sure to carefully read and understand all of them by checking the [`WebViewClient` Documentation](https://developer.android.com/reference/android/webkit/WebViewClient "WebViewClient"). While the default value of `EnableSafeBrowsing` is `true`, some applications might opt to disable it. To verify that SafeBrowsing is enabled, inspect the AndroidManifest.xml file and make sure that the configuration below is not present: @@ -876,7 +876,7 @@ In this case we've crafted the deep link including arbitrary parameters (`?messa - File: `WebViewActivity.kt` - Class: `com.mstg.deeplinkdemo.WebViewActivity` - Method: `onCreate` - + > Sometimes you can even take advantage of other applications that you know interact with your target app. You can reverse engineer the app, (e.g. to extract all strings and filter those which include the target deep links, `deeplinkdemo:///load.html` in the previous case), or use them as triggers, while hooking the app as previously discussed. ## Testing for Sensitive Functionality Exposure Through IPC (MSTG-PLATFORM-4) @@ -1346,6 +1346,109 @@ Intent { act=theBroadcast flg=0x400010 (has extras) } 144: act=theBroadcast flg=0x400010 (has extras) ``` +## Testing for Vulnerable Implementation of PendingIntent (MSTG-PLATFORM-4) + +### Overview + +Often while dealing with complex flows during app development, there are situations where an app A wants another app B to perform a certain action in the future, on app A's behalf. Trying to implement this by only using `Intent`s leads to various security problems, like having multiple exported components. To handle this use case in a secure manner, Android exposes [`PendingIntent`](https://developer.android.com/reference/android/app/PendingIntent "PendingIntent") API. + +`PendingIntent` are most commonly used in case of [notification](https://developer.android.com/develop/ui/views/notifications "notification"), [app widgets](https://developer.android.com/develop/ui/views/appwidgets/advanced#user-interaction "app widgets"), [media browser services](https://developer.android.com/guide/topics/media-apps/audio-app/building-a-mediabrowserservice "media browser services") etc. In case of notifications, `PendingIntent` is used in declaring an intent to be executed when a user performs an action with an app's notification. Notification requires a callback into the application, to trigger an action whenever user clicks the notification. + +Internally, a `PendingIntent` object wraps a normal `Intent` object (referred as base intent), which will eventually be used for invoking an action. For example, the base intent specifies to start an activity A in an application. The receiving application of the `PendingIntent`, will unwrap and get this base intent, and invoke the activity A, by calling `PendingIntent.send()` function. + +A typical implementation for using `PendingIntent` is below: + +```java +Intent intent = new Intent(applicationContext, SomeActivity.class); // base intent + +// create a pending intent +PendingIntent pendingIntent = PendingIntent.getActivity(applicationContext, 0, intent, PendingIntent.FLAG_IMMUTABLE); + +// send the pending intent to another app +Intent anotherIntent = new Intent(); +anotherIntent.setClassName("other.app", "other.app.MainActivity"); +anotherIntent.putExtra("pendingIntent", pendingIntent); +startActivity(anotherIntent); +``` + +What makes a `PendingIntent` secure is that, it grants permission to a foreign application to use the contained `Intent` (the base intent) as if it was executed from your app's own process, unlike an ordinary `Intent`. Thus, an application can freely use them for creating callbacks, without a need to create exported activities. + +If not implemented properly, a malicious application can **hijack** a `PendingIntent`. For instance, in the notification example above, a malicious application with `android.permission.BIND_NOTIFICATION_LISTENER_SERVICE` can bind to the notification listener service and can fetch the pending intent. + +There are certain security pitfalls while implementing `PendingIntent`s, and are listed below: + +- **Mutable fields**: A `PendingIntent` can have mutable and unfilled fields, which can be filled by a malicious application. This can lead to leaking access to non-exported app components to malicious application. By using the flag [`PendingIntent.FLAG_IMMUTABLE`](https://developer.android.com/reference/android/app/PendingIntent#FLAG_IMMUTABLE "FLAG_IMMUTABLE"), makes the `PendingIntent` immutable and prevents any changes to the fields. Prior to Android 12 (API level 31) the `PendingIntent`s were mutable by default, while from Android 12 (API 31) onwards, it is changed to [immutable by default](https://developer.android.com/reference/android/app/PendingIntent#FLAG_MUTABLE "immutable by default"). This change prevents any accidental vulnerabilities. + +- **Use of implicit intent**: A malicious application can receive a `PendingIntent` and then update the base intent to target the component and package within the malicious app. As a mitigation, ensure to explicitly set the exact package, action and component that will receive the base intent. + +The most common case of attacking `PendingIntent` is when a malicious application is able to intercept + +For further details, check the Android documentation on [using a pending intent](https://developer.android.com/guide/components/intents-filters#PendingIntent "using a pending intent"). + +### Static Analysis + +To identify vulnerable implementations, static analysis can be performed by looking for API calls used for obtaining a `PendingIntent`. Such APIs are listed below: + +```java +PendingIntent getActivity(Context, int, Intent, int) +PendingIntent getActivity(Context, int, Intent, int, Bundle) +PendingIntent getActivities(Context, int, Intent, int, Bundle) +PendingIntent getActivities(Context, int, Intent, int) +PendingIntent getForegroundService(Context, int, Intent, int) +PendingIntent getService(Context, int, Intent, int) +``` + +Once any of the above function is spotted, check the implementation of the base intent and the `PendingIntent` for the security pitfalls listed above. + +For example, in [A-156959408](https://android.googlesource.com/platform/frameworks/base/+/6ae2bd0e59636254c32896f7f01379d1d704f42d "A-156959408")(CVE-2020-0389), the base intent is implicit and also the `PendingIntent` is mutable, thus making it exploitable. + +```java +private Notification createSaveNotification(Uri uri) { + Intent viewIntent = new Intent(Intent.ACTION_VIEW) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION) + .setDataAndType(uri, "video/mp4"); //Implicit Intent + +//... skip ... + + +Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID) + .setSmallIcon(R.drawable.ic_android) + .setContentTitle(getResources().getString(R.string.screenrecord_name)) + .setContentText(getResources().getString(R.string.screenrecord_save_message)) + .setContentIntent(PendingIntent.getActivity( + this, + REQUEST_CODE, + viewIntent, + Intent.FLAG_GRANT_READ_URI_PERMISSION)) // Mutable PendingIntent. + .addAction(shareAction) + .addAction(deleteAction) + .setAutoCancel(true); + +``` + +### Dynamic Analysis + +Frida can be used for hooking the APIs used for obtaining a `PendingIntent`. This information can be used in determining the call site, and which can be further used for performing static analysis at the call site, as described above. + +A Frida script hooking `PendingIntent.getActivity` function, may look like following: + +```javascript +var pendingIntent = Java.use('android.app.PendingIntent'); + +var getActivity_1 = pendingIntent.getActivity.overload("android.content.Context", "int", "android.content.Intent", "int"); + +getActivity_1.implementation = function(context, requestCode, intent, flags){ + console.log("[*] Calling PendingIntent.getActivity("+intent.getAction()+")"); + console.log("\t[-] Base Intent toString: " + intent.toString()); + console.log("\t[-] Base Intent getExtras: " + intent.getExtras()); + console.log("\t[-] Base Intent getFlags: " + intent.getFlags()); + return this.getActivity(context, requestCode, intent, flags); +} +``` + +This approach can be helpful when dealing with applications with large code base, where determining the control flow can be tricky sometimes. + + ## Testing JavaScript Execution in WebViews (MSTG-PLATFORM-5) ### Overview @@ -1578,7 +1681,7 @@ class BagOfPrimitives { // Serialization BagOfPrimitives obj = new BagOfPrimitives(); Gson gson = new Gson(); -String json = gson.toJson(obj); +String json = gson.toJson(obj); // ==> json is {"value1":1,"value2":"abc"} @@ -1850,7 +1953,7 @@ As a final note, always remember to properly check the API level that app is tar ### Dynamic Analysis -Abusing this kind of vulnerability on a dynamic manner can be pretty challenging and very specialized as it closely depends on the target Android version. For instance, for versions up to Android 7.0 (API level 24) you can use the following APKs as a proof of concept to identify the existence of the vulnerabilities. +Abusing this kind of vulnerability on a dynamic manner can be pretty challenging and very specialized as it closely depends on the target Android version. For instance, for versions up to Android 7.0 (API level 24) you can use the following APKs as a proof of concept to identify the existence of the vulnerabilities. - [Tapjacking POC](https://github.com/FSecureLABS/tapjacking-poc "Tapjacking POC"): This APK creates a simple overlay which sits on top of the testing application. - [Invisible Keyboard](https://github.com/DEVizzi/Invisible-Keyboard "Invisible Keyboard"): This APK creates multiple overlays on the keyboard to capture keystrokes. This is one of the exploit demonstrated in Cloak and Dagger attacks. From 3f00f3b2e76495e4cbfd377a3235da565a34e2cf Mon Sep 17 00:00:00 2001 From: cpholguera Date: Tue, 31 Jan 2023 09:55:22 +0100 Subject: [PATCH 2/2] moved theory to the top --- .../0x05h-Testing-Platform-Interaction.md | 80 ++++++++++--------- 1 file changed, 42 insertions(+), 38 deletions(-) diff --git a/Document/0x05h-Testing-Platform-Interaction.md b/Document/0x05h-Testing-Platform-Interaction.md index d8c5c8daa1..8adb85e479 100644 --- a/Document/0x05h-Testing-Platform-Interaction.md +++ b/Document/0x05h-Testing-Platform-Interaction.md @@ -233,6 +233,43 @@ The following is a list of Android IPC Mechanisms that may expose sensitive data - [Intents](https://developer.android.com/reference/android/content/Intent.html "IPCIntent") - [Content Providers](https://developer.android.com/reference/android/content/ContentProvider.html "IPCContentProviders") +#### Pending Intents + +Often while dealing with complex flows during app development, there are situations where an app A wants another app B to perform a certain action in the future, on app A's behalf. Trying to implement this by only using `Intent`s leads to various security problems, like having multiple exported components. To handle this use case in a secure manner, Android provides the [`PendingIntent`](https://developer.android.com/reference/android/app/PendingIntent "PendingIntent") API. + +`PendingIntent` are most commonly used for [notifications](https://developer.android.com/develop/ui/views/notifications "Android Notifications"), [app widgets](https://developer.android.com/develop/ui/views/appwidgets/advanced#user-interaction "app widgets"), [media browser services](https://developer.android.com/guide/topics/media-apps/audio-app/building-a-mediabrowserservice "media browser services"), etc. When used for notifications, `PendingIntent` is used to declare an intent to be executed when a user performs an action with an application's notification. The notification requires a callback to the application to trigger an action when the user clicks on it. + +Internally, a `PendingIntent` object wraps a normal `Intent` object (referred as base intent) that will eventually be used to invoke an action. For example, the base intent specifies that an activity A should be started in an application. The receiving application of the `PendingIntent`, will unwrap and retrieve this base intent and invoke the activity A by calling the `PendingIntent.send()` function. + +A typical implementation for using `PendingIntent` is below: + +```java +Intent intent = new Intent(applicationContext, SomeActivity.class); // base intent + +// create a pending intent +PendingIntent pendingIntent = PendingIntent.getActivity(applicationContext, 0, intent, PendingIntent.FLAG_IMMUTABLE); + +// send the pending intent to another app +Intent anotherIntent = new Intent(); +anotherIntent.setClassName("other.app", "other.app.MainActivity"); +anotherIntent.putExtra("pendingIntent", pendingIntent); +startActivity(anotherIntent); +``` + +What makes a `PendingIntent` secure is that, unlike a normal `Intent`, it grants permission to a foreign application to use the `Intent` (the base intent) it contains, as if it were being executed by your application's own process. This allows an application to freely use them to create callbacks without the need to create exported activities. + +If not implemented correctly, a malicious application can **hijack** a `PendingIntent`. For example, in the notification example above, a malicious application with `android.permission.BIND_NOTIFICATION_LISTENER_SERVICE` can bind to the notification listener service and retrieve the pending intent. + +There are certain security pitfalls when implementing `PendingIntent`s, which are listed below: + +- **Mutable fields**: A `PendingIntent` can have mutable and empty fields that can be filled by a malicious application. This can lead to a malicious application gaining access to non-exported application components. Using the [`PendingIntent.FLAG_IMMUTABLE` flag](https://developer.android.com/reference/android/app/PendingIntent#FLAG_IMMUTABLE "FLAG_IMMUTABLE") makes the `PendingIntent` immutable and prevents any changes to the fields. Prior to Android 12 (API level 31), the `PendingIntent` was mutable by default, while since Android 12 (API level 31) it is changed to [immutable by default](https://developer.android.com/reference/android/app/PendingIntent#FLAG_MUTABLE "immutable by default") to prevent accidental vulnerabilities. + +- **Use of implicit intent**: A malicious application can receive a `PendingIntent` and then update the base intent to target the component and package within the malicious application. As a mitigation, ensure that you explicitly specify the exact package, action and component that will receive the base intent. + +The most common case of `PendingIntent` attack is when a malicious application is able to intercept it. + +For further details, check the Android documentation on [using a pending intent](https://developer.android.com/guide/components/intents-filters#PendingIntent "using a pending intent"). + ### Object Persistence There are several ways to persist an object on Android: @@ -1448,40 +1485,7 @@ Intent { act=theBroadcast flg=0x400010 (has extras) } ### Overview -Often while dealing with complex flows during app development, there are situations where an app A wants another app B to perform a certain action in the future, on app A's behalf. Trying to implement this by only using `Intent`s leads to various security problems, like having multiple exported components. To handle this use case in a secure manner, Android exposes [`PendingIntent`](https://developer.android.com/reference/android/app/PendingIntent "PendingIntent") API. - -`PendingIntent` are most commonly used in case of [notification](https://developer.android.com/develop/ui/views/notifications "notification"), [app widgets](https://developer.android.com/develop/ui/views/appwidgets/advanced#user-interaction "app widgets"), [media browser services](https://developer.android.com/guide/topics/media-apps/audio-app/building-a-mediabrowserservice "media browser services") etc. In case of notifications, `PendingIntent` is used in declaring an intent to be executed when a user performs an action with an app's notification. Notification requires a callback into the application, to trigger an action whenever user clicks the notification. - -Internally, a `PendingIntent` object wraps a normal `Intent` object (referred as base intent), which will eventually be used for invoking an action. For example, the base intent specifies to start an activity A in an application. The receiving application of the `PendingIntent`, will unwrap and get this base intent, and invoke the activity A, by calling `PendingIntent.send()` function. - -A typical implementation for using `PendingIntent` is below: - -```java -Intent intent = new Intent(applicationContext, SomeActivity.class); // base intent - -// create a pending intent -PendingIntent pendingIntent = PendingIntent.getActivity(applicationContext, 0, intent, PendingIntent.FLAG_IMMUTABLE); - -// send the pending intent to another app -Intent anotherIntent = new Intent(); -anotherIntent.setClassName("other.app", "other.app.MainActivity"); -anotherIntent.putExtra("pendingIntent", pendingIntent); -startActivity(anotherIntent); -``` - -What makes a `PendingIntent` secure is that, it grants permission to a foreign application to use the contained `Intent` (the base intent) as if it was executed from your app's own process, unlike an ordinary `Intent`. Thus, an application can freely use them for creating callbacks, without a need to create exported activities. - -If not implemented properly, a malicious application can **hijack** a `PendingIntent`. For instance, in the notification example above, a malicious application with `android.permission.BIND_NOTIFICATION_LISTENER_SERVICE` can bind to the notification listener service and can fetch the pending intent. - -There are certain security pitfalls while implementing `PendingIntent`s, and are listed below: - -- **Mutable fields**: A `PendingIntent` can have mutable and unfilled fields, which can be filled by a malicious application. This can lead to leaking access to non-exported app components to malicious application. By using the flag [`PendingIntent.FLAG_IMMUTABLE`](https://developer.android.com/reference/android/app/PendingIntent#FLAG_IMMUTABLE "FLAG_IMMUTABLE"), makes the `PendingIntent` immutable and prevents any changes to the fields. Prior to Android 12 (API level 31) the `PendingIntent`s were mutable by default, while from Android 12 (API 31) onwards, it is changed to [immutable by default](https://developer.android.com/reference/android/app/PendingIntent#FLAG_MUTABLE "immutable by default"). This change prevents any accidental vulnerabilities. - -- **Use of implicit intent**: A malicious application can receive a `PendingIntent` and then update the base intent to target the component and package within the malicious app. As a mitigation, ensure to explicitly set the exact package, action and component that will receive the base intent. - -The most common case of attacking `PendingIntent` is when a malicious application is able to intercept - -For further details, check the Android documentation on [using a pending intent](https://developer.android.com/guide/components/intents-filters#PendingIntent "using a pending intent"). +When testing [Pending Intents](#pending-intents) you must ensure that they are immutable and that the app explicitly specifies the exact package, action, and component that will receive the base intent. ### Static Analysis @@ -1496,7 +1500,7 @@ PendingIntent getForegroundService(Context, int, Intent, int) PendingIntent getService(Context, int, Intent, int) ``` -Once any of the above function is spotted, check the implementation of the base intent and the `PendingIntent` for the security pitfalls listed above. +Once any of the above function is spotted, check the implementation of the base intent and the `PendingIntent` for the security pitfalls listed in the [Pending Intents](#pending-intents) section. For example, in [A-156959408](https://android.googlesource.com/platform/frameworks/base/+/6ae2bd0e59636254c32896f7f01379d1d704f42d "A-156959408")(CVE-2020-0389), the base intent is implicit and also the `PendingIntent` is mutable, thus making it exploitable. @@ -1526,9 +1530,9 @@ Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID) ### Dynamic Analysis -Frida can be used for hooking the APIs used for obtaining a `PendingIntent`. This information can be used in determining the call site, and which can be further used for performing static analysis at the call site, as described above. +Frida can be used to hook the APIs used to get a `PendingIntent`. This information can be used to determine the code location of the call, which can be further used to perform static analysis as described above. -A Frida script hooking `PendingIntent.getActivity` function, may look like following: +Here's an example of such a Frida script that can be used to hook the `PendingIntent.getActivity` function: ```javascript var pendingIntent = Java.use('android.app.PendingIntent'); @@ -1544,7 +1548,7 @@ getActivity_1.implementation = function(context, requestCode, intent, flags){ } ``` -This approach can be helpful when dealing with applications with large code base, where determining the control flow can be tricky sometimes. +This approach can be helpful when dealing with applications with large code bases, where determining the control flow can sometimes be tricky. ## Testing JavaScript Execution in WebViews (MSTG-PLATFORM-5)