We have recently disclosed a new vulnerability to the Android Security Team. The vulnerability affected many apps, including Settings (the one that is found on every Android device), GmailGoogle NowDropBox and Evernote.  To be more accurate, any App which extended the PreferenceActivity class using an exported activity was automatically vulnerable. A patch has been provided in Android KitKat. If you wondered why your code is now broken, it is due to the Android KitKat patch which requires applications to override the new method, PreferenceActivity.isValidFragment, which has been added to the Android Framework.

In this blog post we will begin with a short introduction on Android and its sandbox, and then we will deep-dive into the vulnerability itself. For the sake of simplicity we omitted some of the details which can be found in our whitepaper.

 

The UI building blocks of Android Apps

The UI of Android apps is made of activities. An Activity provides a single screen with some functionality (for instance: a browser’s bookmarks manager). A Fragment  can be considered as a sub-activity. It is a piece of the App’s UI. Fragments provide some flexibility as they allow reuse in different activities. While a Fragment instance is coupled with the Activity it resides inside, different instances can be embedded in different activities. See Figure 1 for the relation between activities and fragments.

Figure 1: The relation between activities and fragments.
Scroll to view full table

 

Android Sandboxing, Permissions, Inter-app communication and Attacks by Malicious Apps

In Android, apps are isolated from each other and subject to their declared set of permissions by the use of Sandboxing. An app cannot normally access sensitive data of another. That being said, it is possible for one app to invoke application components (such as activities) of another app for feature reuse.  For example, Chrome invokes the Google play app when opening Google Play URLs.  The invocation is done using Intents which are IPC objects that the source application passes to the corresponding API. Intents do not just specify the target, they also contain data in two places. The first location is the data attribute (of URI type) and the second one is a dictionary (Bundle) that can contain an arbitrary amount of information (also known as Intent extras). Activities can be invoked by an external app if they are exported in the application’s manifest file (ApplicationManifest.xml). Making an activity public (exported) creates a potential hole in the Android Sandbox. Since activities access the input Intent’s data, a bad app can invoke the exported activity and provide it with malicious data, that may trigger vulnerabilities if the data are not properly santizied or validated in the target application. As of Fragments, they can receive input by accessing the embedding activity thus its input Intent or as Fragment-specific arguments. See Figure 2 for an attack outline.

 
Figure 2: Attacking exported activities.
Scroll to view full table

 

The PreferenceActivity

The PreferenceActivity is a base class (provided by the Android Framework) for showing a hierarchy of preferences to the user. The preferences are associated with a PreferenceFragment. The PreferenceActivity consumes a few Intent extras. One of them is :android:show_fragment which tells the PreferenceActivity which fragment to display first. The dynamic Fragment loading is done by a chain of calls which start at the activity creation and end at Fragment.instantiate (see Figures 3,4). The latter loads the Fragment using the Java Reflection API.

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

   String initialFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT);
   Bundle initialArguments = getIntent().getBundleExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS);

   if (savedInstanceState != null) {

   } else {
       if (initialFragment != null && mSinglePane) {
           // If we are just showing a fragment, we want to run in
           // new fragment mode, but don't need to compute and show
           // the headers.
           switchToHeader(initialFragment, initialArguments);

		} else {

           if (mHeaders.size() > 0) {
               if (!mSinglePane) {
                   if (initialFragment == null) {

                   } else {
                      switchToHeader(initialFragment, initialArguments);
                   }
               }
           }
       }
   }

}

public void switchToHeader(String fragmentName, Bundle args) {
   setSelectedHeader(null);
   switchToHeaderInner(fragmentName, args, 0);
}

private void switchToHeaderInner(String fragmentName, Bundle args, int direction) {
   getFragmentManager().popBackStack(BACK_STACK_PREFS,
                                     FragmentManager.POP_BACK_STACK_INCLUSIVE);
   Fragment f = Fragment.instantiate(this, fragmentName, args);
   FragmentTransaction transaction = getFragmentManager().beginTransaction();
   transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
   transaction.replace(com.android.internal.R.id.prefs, f);
   transaction.commitAllowingStateLoss();
}

Figure 3: Chain of calls in PreferenceActivity ending at Fragment.instantiate (as implemented in Android 4.3)

public static Fragment instantiate(Context context, String fname, Bundle args) {
    try {
        Class<?> clazz = sClassMap.get(fname);
        if (clazz == null) {
            // Class not found in the cache, see if it's real, and try to add it
            clazz = context.getClassLoader().loadClass(fname);
            sClassMap.put(fname, clazz);
        }
        Fragment f = (Fragment)clazz.newInstance();
        if (args != null) {
            args.setClassLoader(f.getClass().getClassLoader());
            f.mArguments = args;
        }
        return f;
    }
...
}

Figure 4: Android 4.3 implementation of Fragment.instantiate.

 

The Vulnerability

A malicious application can invoke any exported PreferenceActivity class and supply it with an :android:show_fragment Intent extra in order to make it load an arbitrary class. The goal of the attacker is to execute some code that will break the Android Sandbox, i.e. access sensitive information pertaining to the vulnerable app, or abuse its permissions. Since the attacker cannot supply his own classes as he is limited to ones found under the class loader of the vulnerable app (Android Framework classes and the App classes), the attack is not trivial. In our whitepaper we depict a couple of exploit techniques, one of them is pretty cool. The malicious app can make the PreferenceActivity load an arbitrary Fragment of the vulnerable app, which is normally loaded inside a non-exported Activity to pratically take it from its natural habitat to a hazardous area where input should not be trusted as the malicious app can now control it.  See Figure 5 for the attack outline.

Figure 5: Attacking a Fragment
Scroll to view full table

 

Attacking the Android Settings

As we mentioned above, all apps which make use of PreferenceActivity are vulnerable. We targeted the Settings app since it is a highly privileged application. By exploiting the the vulnerability we managed to successfully subvert its integrity.  The app’s main activity (which is exported), com.android.settings.Settings, extends PreferenceActivity thus it is vulnerable. We searched for interesting fragments in the app’s package, one of them is ChooseLockPassword$ChooseLockPasswordFragment. This Fragment is responsible of handling the credentials changing of the device’s lock screen and is subject to the Device Management Policy.  The Fragment’s natural habitat is the ChooseLockPassword Activity which is non-exported. Normally the  Fragment first asks the user to insert his old credentials (see Figure 6), unless the embedding activity is supplied with an Intent extra, ‘confirm_credentials’ set to false.

Figure 6: Normal behavior of ChooseLockPasswordFragment
Scroll to view full table

Since the activity is not exported, this parameter cannot be easily manipulated by a malicious app, however by exploiting the Fragments Injection vulnerability, we can embed the ChooseLockPassword$ChooseLockPasswordFragment inside an exported activity, com.android.settings.Settings, and supply it with malicious data, confirm_credentials set to false. See Figure 7 for the attack outline, and Figure 8 for the result. Since this exploit requires user-intervention it cannot be used remotely thus it requires a physical attacker that wants to change the credentials. Please note that by exploiting this vulnerability the attacker can also override Device Management Policy such as the minimum password requirements.

 
Figure 7: Attacking Android’s Settings
Scroll to view full table

 

Figure 8: User does not need to supply his old credentials
Scroll to view full table

 

The Fix

Google  has provided a patch in Android 4.4 KitKat by adding a new protected API, PreferenceActivity.isValidFragment, which is called before the Fragment is dynamically instantiated by PreferenceActivity (see Figure 9). The isValidFragment method must be overridden otherwise the default implementation throws an exception, as documented in the SDK Reference. We encourage developers to properly implement this method (e.g. as a white-list) since a weak implementation will keep your app vulnerable.

private void switchToHeaderInner(String fragmentName, Bundle args, int direction) {
        getFragmentManager().popBackStack(BACK_STACK_PREFS,
                FragmentManager.POP_BACK_STACK_INCLUSIVE);
        if (!isValidFragment(fragmentName)) {
            throw new IllegalArgumentException("Invalid fragment for this activity: "
                    + fragmentName);
        }
        Fragment f = Fragment.instantiate(this, fragmentName, args);
        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        transaction.replace(com.android.internal.R.id.prefs, f);
        transaction.commitAllowingStateLoss();
    }

Figure 9: Potentially safe Fragment instantiation in Android KitKat.

 

Vulnerable versions
Android 4.3 Jelly Bean and below.

Non-Vulnerable versions
Android 4.4 KitKat.

Disclosure Timeline
12/05/2013  Reply from Android Security Team: “Issue is fixed”.
12/05/2013  Requested a status update.
11/11/2013  Reply from Android Security Team: “Fix in progress”
10/24/2013  Requested for status update.
07/14/2013  Reply from Android Security Team: “We are now looking into the issue”.
07/12/2013  Disclosure to Android Security Team.

About the IBM Application Security Research Team
The Application Security Research Team researches new security threats and vulnerabilities and provides regular rule updates to AppScan.

 

More from Application Security

PixPirate: The Brazilian financial malware you can’t see

10 min read - Malicious software always aims to stay hidden, making itself invisible so the victims can’t detect it. The constantly mutating PixPirate malware has taken that strategy to a new extreme. PixPirate is a sophisticated financial remote access trojan (RAT) malware that heavily utilizes anti-research techniques. This malware’s infection vector is based on two malicious apps: a downloader and a droppee. Operating together, these two apps communicate with each other to execute the fraud. So far, IBM Trusteer researchers have observed this…

From federation to fabric: IAM’s evolution

15 min read - In the modern day, we’ve come to expect that our various applications can share our identity information with one another. Most of our core systems federate seamlessly and bi-directionally. This means that you can quite easily register and log in to a given service with the user account from another service or even invert that process (technically possible, not always advisable). But what is the next step in our evolution towards greater interoperability between our applications, services and systems?Identity and…

Audio-jacking: Using generative AI to distort live audio transactions

7 min read - The rise of generative AI, including text-to-image, text-to-speech and large language models (LLMs), has significantly changed our work and personal lives. While these advancements offer many benefits, they have also presented new challenges and risks. Specifically, there has been an increase in threat actors who attempt to exploit large language models to create phishing emails and use generative AI, like fake voices, to scam people. We recently published research showcasing how adversaries could hypnotize LLMs to serve nefarious purposes simply…

Topic updates

Get email updates and stay ahead of the latest threats to the security landscape, thought leadership and research.
Subscribe today