Insecure transmission of sensitive information in private Activity

  INFO  
Detection method   DAST         SENSITIVE INFO  

Description

An application puts sensitive information into an Intent to launch an internal Activity. This can lead to interception of information by external applications.

Interprocess communication (IPC) on Android is conducted using a special object—Intent. Parameters of Intent handlers are set in the main file of the application manifest—AndroidManifest.xml or, in case of dynamic BroadcastReceivers, in the application's code. If an implicit Intent is used, i.e. an Intent that does not specify a component; instead, it generally defines an action to be conducted, and lets the system determine which of the available components is best to run for that Intent. For example, if there is a need to display a place on a map, the implicit Intent object can request another application, which has such feature, to provide this information. Data in such messages could be compromised. Moreover, malicious applications could use mechanisms of delegation of process control, such as implicit calls to application components or objects like PendingIntent, for interception of control and fishing attacks.

The following object types are dangerous: ActivityServiceBroadcastReceiver and ContentProvider, because they are open to communication with other applications and don't belong to system Android calls (such as android.intent.action.MAIN).  BroadcastReceiver is, by default, open to interaction with other applications, so the interception of control or of an Intent with confidential information is possible.

Recommendations

Don't include sensitive information into parameters when using implicit Intents (when a user defines what application will handle a message).

Risks from using an Activity and corresponding countermeasures vary depending on the ways this Activity is used. We have classified 4 types of Activities based on how the Activity is used. To find out which type of Activity you are supposed to create, follow through the table and chart below.

 

Type of Activity

Description

Private activity

An activity that cannot be launched by another application, and therefore is the safest one.

Public activity

An activity that can be used by an unspecified large number of applications.

Partner activity

An activity that can only be used by specific applications created by trusted partner companies. There is a special list of such applications.

In-house activity

An activity that can only be used by other applications of the same developer.

 

Picture 1

Creating and using a private Activity

Private Activities are Activities which cannot be launched by the other applications and therefore it is the safest Activity.

When using Activities that are only used within the application (Private Activity), as long as you use explicit Intents to the class then you do not have to worry about accidently sending it to any other application. However, there is a risk that a third party application can read an Intent that is used to start the Activity. Therefore it is necessary to make sure that if you are putting sensitive information inside an Intent used to start an Activity that you take countermeasures to make sure that it cannot be read by a malicious third party.

Rules (creating a private Activity)

1. Do not specify taskAffinity.

2. Do not specify launchMode.

3. Explicitly set the exported attribute to false—exported="false".

4. Handle the received intent carefully and securely, even though the intent was sent from the same application.

5. Sensitive information can be sent since it is sending and receiving all within the same application.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.mobix.android.activity.privateactivity" >
        <application
                android:allowBackup="false"
                android:icon="@drawable/ic_launcher"
                android:label="@string/app_name" >
                <!-- Private activity -->
                <!-- *** 1 *** Do not specify taskAffinity -->
                <!-- *** 2 *** Do not specify launchMode -->
                <!-- *** 3 *** Explicitly set the exported attribute to false -->
                <activity
                        android:name=".PrivateActivity"
                        android:label="@string/app_name"
                        android:exported="false" />
                <!-- Public activity launched by launcher -->
                <activity
                        android:name=".PrivateUserActivity"
                        android:label="@string/app_name"
                        android:exported="true" >
                        <intent-filter>
                                <action android:name="android.intent.action.MAIN" />
                                <category android:name="android.intent.category.LAUNCHER" />
                        </intent-filter>
                </activity>
        </application>
</manifest>

PrivateActivity.java

package com.mobix.android.activity.privateactivity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class PrivateActivity extends Activity {
        @Override
        public void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.private_activity);
                // *** 4 *** Handle the received Intent carefully and securely, even though the Intent was sent from the same application.
                // See section "Secure Handling of the Input Data"
                String param = getIntent().getStringExtra("PARAM");
                Toast.makeText(this, String.format("Received param: %s", param), Toast.LENGTH_LONG).show();
        }
        public void onReturnResultClick(View view) {
                // *** 5 *** Sensitive information can be sent since it is sending and receiving all within the same application.
                Intent intent = new Intent();
                intent.putExtra("RESULT", "Sensitive Info");
                setResult(RESULT_OK, intent);
                finish();
        }
}

Rules (using a private Activity):

1. Do not set the FLAG_ACTIVITY_NEW_TASK flag for Intents to start an activity.

2. Use the explicit Intents with the class specified to call an activity in the same application.

3. Sensitive information can be sent only by putExtra() since the destination activity is in the same application.

4. Handle the received result data carefully and securely, even though the data comes from an Activity within the same application.

PrivateUserActivity.java

package com.mobix.android.activity.privateactivity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class PrivateUserActivity extends Activity {
         private static final int REQUEST_CODE = 1;
         @Override
         public void onCreate(Bundle savedInstanceState) {
                  super.onCreate(savedInstanceState);
                  setContentView(R.layout.user_activity);
         }
         public void onUseActivityClick(View view) {
                  // *** 1 *** Do not set the FLAG_ACTIVITY_NEW_TASK flag for intents to start an activity.
                  // *** 2 *** Use the explicit Intents with the class specified to call an activity in the same application
                  Intent intent = new Intent(this, PrivateActivity.class);
                  // *** 3 *** Sensitive information can be sent only by putExtra() since the destination activity is in the same application.
                  intent.putExtra("PARAM", "Sensitive Info");
                  startActivityForResult(intent, REQUEST_CODE);
         }
         @Override
         public void onActivityResult(int requestCode, int resultCode, Intent data) {
                  super.onActivityResult(requestCode, resultCode, data);
                  if(resultCode != RESULT_OK) return;
                  switch(requestCode) {
                           case REQUEST_CODE:
                                    String result = data.getStringExtra("RESULT");
                                    // *** 4 *** Handle the received Intent carefully and securely, even though the Intent was sent from the same application.
                                    // See section "Secure Handling of the Input Data"
                                    Toast.makeText(this, String.format("Received result: %s, result), Toast.LENGTH_LONG).show();
                                    break;
                   }
         }
}

‎Links

  1. https://developer.android.com/guide/components/intents-filters
  2. https://github.com/OWASP/owasp-mstg/blob/master/Document/0x05h-Testing-Platform-Interaction.md
  3. https://developer.android.com/training/basics/intents/index.html