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

Kronos Malware Reemerges with Increased Functionality

The Evolution of Kronos Malware The Kronos malware is believed to have originated from the leaked source code of the Zeus malware, which was sold on the Russian underground in 2011. Kronos continued to evolve and a new variant of Kronos emerged in 2014 and was reportedly sold on the darknet for approximately $7,000. Kronos is typically used to download other malware and has historically been used by threat actors to deliver different types of malware to victims. After remaining…

Self-Checkout This Discord C2

This post was made possible through the contributions of James Kainth, Joseph Lozowski, and Philip Pedersen. In November 2022, during an incident investigation involving a self-checkout point-of-sale (POS) system in Europe, IBM Security X-Force identified a novel technique employed by an attacker to introduce a command and control (C2) channel built upon Discord channel messages. Discord is a chat, voice, and video service enabling users to join and create communities associated with their interests. While Discord and its related software…

A View Into Web(View) Attacks in Android

James Kilner contributed to the technical editing of this blog. Nethanella Messer, Segev Fogel, Or Ben Nun and Liran Tiebloom contributed to the blog. Although in the PC realm it is common to see financial malware used in web attacks to commit fraud, in Android-based financial malware this is a new trend. Traditionally, financial malware in Android uses overlay techniques to steal victims’ credentials. In 2022, IBM Security Trusteer researchers discovered a new trend in financial mobile malware that targets…

Twitter is the New Poster Child for Failing at Compliance

All companies have to comply with privacy and security laws. They must also comply with any settlements or edicts imposed by regulatory agencies of the U.S. government. But Twitter now finds itself in a precarious position and appears to be failing to take its compliance obligations seriously. The case is a “teachable moment” for all organizations, public and private. The Musk Factor Technology visionary and Silicon Valley founder and CEO, Elon Musk, bought social network Twitter in October for $44…