Detailed analysis of the vulnerability of Android Broadcastanywhere (Google Bug 17356824)

Source: Internet
Author: User

Detailed analysis of the vulnerability of Android Broadcastanywhere (Google Bug 17356824)

Low-end Code Farm (Jane, Boyliang)

Blog: www.im-boy.net

Date: 2014.11.16

Following the last Android Launchanywhere component security vulnerability, Google recently fixed a high-risk vulnerability on the Android 5.0 source, a Launchanywhere sister version of--broadcastanywhere. Through this vulnerability, an attacker could send broadcasts as a system user, which means that an attacker could ignore all the Broadcastreceiver component access restrictions. And the vulnerability is extremely wide, and Android 2.0+ to 4.4.x are affected.

Vulnerability analysis repair before and after code comparison

Broadcastanywhere and Launchanywhere Use the same principle very similar, both take advantage of the setting UID is the system process high-privilege operation.

The vulnerability also occurs on setting's Add account process, which is detailed in the "Android launchanywhere (Google Bug 7699048) vulnerability and defense measures" article. The Broadcastanywhere vulnerability occurs before this process. Before parsing the vulnerability, let's look at the front-to-back comparison of the bug fixes, with specific code in Addaccountsetting's AddAccount method.

In the pre-repair code:

 ... private static final String KEY_CALLER_IDENTITY = "pendingIntent"; ... private void addAccount(String accountType) {        Bundle addAccountOptions = new Bundle();        mPendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(), 0);        addAccountOptions.putParcelable(KEY_CALLER_IDENTITY, mPendingIntent);        addAccountOptions.putBoolean(EXTRA_HAS_MULTIPLE_USERS, Utils.hasMultipleUsers(this));        AccountManager.get(this).addAccount(                accountType,                null, /* authTokenType */                null, /* requiredFeatures */                addAccountOptions,                null,                mCallback,                null /* handler */);        mAddAccountCalled  = true;    }

After the repair code is as follows

... private static final string key_caller_identity = "Pendingintent";p rivate static final String should_not_resolve = "SHO Uldn ' T resolve! ";    ... private void AddAccount (String accounttype) {Bundle addaccountoptions = new Bundle (); /* * The identityintent is for the purposes of establishing the identity * of the caller and isn ' t intended for LA     Unching activities, services * or broadcasts. * * Unfortunately for legacy reasons we still need  But * we can cripple the intent so, 3rd party authenticators can ' t * fill in addressing information and launch     arbitrary actions.    */Intent identityintent = new Intent ();    Identityintent.setcomponent (New ComponentName (Should_not_resolve, should_not_resolve));    Identityintent.setaction (Should_not_resolve);    Identityintent.addcategory (Should_not_resolve);    Mpendingintent = Pendingintent.getbroadcast (this, 0, identityintent, 0); Addaccountoptions.putparcelable (key_caller_identity, MPenDingintent);    Addaccountoptions.putboolean (Extra_has_multiple_users, Utils.hasmultipleusers (this)); Accountmanager.get (This). Addaccountasuser (AccountType, NULL,/* Authtokentype */NULL,/            * Requiredfeatures */addaccountoptions, NULL, mcallback, NULL/* handler */,    Muserhandle); maddaccountcalled = true;}

The role of mpenddingintent is mainly used as identification.

By contrast, the fix is to put the mpendingintent into the Intent, from the original simple New Intent () to advance through a series of filled identityintent. In doing so, it is possible to prevent third-party authenticator (mainly Trojans) from filling two times, which is described in detail later.

Note that in the Pendingintent.getbroadcast call, an "empty" intent object is passed in before the repair, which is critical for subsequent analysis.

The realization principle of peddingintent

By comparing the above code, if you have already made the details of the implementation of Peddingintent clear, then this section can be skipped. In the Penddingintent.java source file, there is a description:

/** * ... * <p>by giving a pendingintent to another application, * is granting it the right to perform th  E operation you has specified * as if the other application is yourself (with the same permissions and * identity). As such, you should is careful about how to build the pendingintent: * Almost always, for example, the base Intent you su Pply should has the component * name explicitly set to one of your own components, to ensure it is ultimately * sent ther E and nowhere else. * * <p>a pendingintent itself is simply a reference to a tokens maintained by * The system describing the original DA  Ta used to retrieve it. This means *, even if it owning application ' s process is killed, the * pendingintent itself would remain usable from  Other processes that * has been given it.  If the Creating application later re-retrieves the * Same kind of pendingintent (same operation, same Intent action, data, * Categories, and components, and same flags), it'll receIve a pendingintent * representing the same token if that's still valid, and can thus call * {@link #cancel} to remove it . * ... * ... */

Simply put, the Penddingintent object can be triggered by a predetermined action, when the object is passed (through binder) to other processes (users of different UID), other processes take advantage of this Penddinginten object, The specified trigger action can be performed by the identity permission of the original process, which is somewhat similar to the effect of Suid or GUIDs on Linux. In addition, because the triggered action is performed by the system process, the triggering action on the Penddingintent object is still valid even if the original process is no longer present.

Peddingintent is a Parcelable object that contains a basement mtarget member, and the type is. This field is actually a Binerproxy object, and the real implementation logic is Penddingintentrecored.java. From the source analysis, it is known that Pendingintent.getbroadcast finally calls the Getintentsender method in activitymanagerservice . The key code is as follows:

  public iintentsender getintentsender (int type, string packagename, IBinder token, string resultwho, int reques Tcode, intent[] intents, string[] resolvedtypes, int flags, Bundle options, int userId) {Enforcenotisolatedcaller ("get    Intentsender ");        ... synchronized (this) {int callinguid = Binder.getcallinguid ();        int origuserid = userId; UserID = Handleincominguser (Binder.getcallingpid (), Callinguid, userId, type = = Activitymanager.intent_        Sender_broadcast, False, "Getintentsender", null); ... return getintentsenderlocked (type, PackageName, Callinguid, userId, token, resultwho, Requestcode, I            Ntents, Resolvedtypes, flags, options);            } catch (RemoteException e) {throw new SecurityException (e); }        }    }
  iintentsender getintentsenderlocked (int type, String packagename, int callinguid, int userId, IBinder token, S Tring resultwho, int requestcode, intent[] intents, string[] resolvedtypes, int flags, Bundle options) {if (debug_        MU) slog.v (Tag_mu, "getintentsenderlocked (): uid=" + callinguid);        Activityrecord activity = NULL;        ...        ... Pendingintentrecord.key Key = new Pendingintentrecord.key (type, packagename, activity, resultwho, Requestcode, intents, Resolvedtypes, flags, options, USERID);        Generates a Pendingintentrecord.key object weakreference<pendingintentrecord> ref based on the caller's information;        ref = Mintentsenderrecords.get (key); Pendingintentrecord REC = ref! = NULL?        Ref.get (): null; ... rec = new Pendingintentrecord (this, key, Callinguid); Finally generate Pendingintentrecord object Mintentsenderrecords.put (key, Rec.ref); Save ... return rec; and returns}  

Summarize this process, That is, AMS will save the generated penddingintent process (Caller) information to Pendingintentrecord.key, and maintain a Pendingintentrecord object for it, this object is a binderstub.

Pendingintent provides a series of send methods for action triggering, which is ultimately called Pendingintentrecord's Send method, and we analyze the code here directly:

public int send(int code, Intent intent, String resolvedType,            IIntentReceiver finishedReceiver, String requiredPermission) {        return sendInner(code, intent, resolvedType, finishedReceiver,                requiredPermission, null, null, 0, 0, 0, null);    }

Follow in:

int Sendinner (int code, Intent Intent, String resolvedtype, Iintentreceiver finishedreceiver, String requiredpermis     Sion, IBinder Resultto, String resultwho, int requestcode, int flagsmask, int flagsvalues, Bundle options) {            Synchronized (owner) {if (!canceled) {sent = true;                if ((key.flags&pendingintent.flag_one_shot)! = 0) {owner.cancelintentsenderlocked (this, true);            Canceled = true; } Intent finalintent = key.requestintent! = null?            New Intent (key.requestintent): New Intent ();                if (intent! = NULL) {int changes = Finalintent.fillin (intent, key.flags);//fill intent with incoming finalintent                if ((changes&intent.fill_in_data) = = 0) {resolvedtype = Key.requestresolvedtype;            }} else {resolvedtype = Key.requestresolvedtype;  }            ...            ...          Switch (key.type) {... case activitymanager.intent_sender_broadcast:  try {//If a completion callback have been requested, require//That                                The broadcast be delivered synchronously owner.broadcastintentinpackage (Key.packagename, UID,                            Finalintent, Resolvedtype, finishedreceiver, code, NULL, NULL,                        Requiredpermission, (finishedreceiver! = null), FALSE, userId);                    Sendfinish = false; } catch (RuntimeException e) {SLOG.W (Activitymanagerservice.tag, "U                    Nable to send startactivity intent ", e);                } break;            ...            }        ... return 0; }} return activitymanager.start_canceled;

For this vulnerability we only analyze the logic of the broadcast branch. Found here, will be sent in the intent to fill the finalintent, through the previous code analysis, where the finalinent is an "empty" intent, that is, maction, mdata,mtype, etc. are all null, This makes it almost arbitrary to specify the contents of the Finalintent, see Fillin's Code:

public int FillIn (Intent other, int flags) {int changes = 0; if (other.maction! = null && (maction = = NULL | |        (flags&fill_in_action)! = 0)) {maction = other.maction;    Changes |= fill_in_action;                    if (other.mdata! = NULL | | Other.mtype! = NULL) && ((Mdata = = NULL && Mtype = = null) ||        (flags&fill_in_data)! = 0)) {mdata = Other.mdata;        Mtype = Other.mtype;    Changes |= fill_in_data; } if (other.mcategories! = null && (mcategories = = NULL | | (flags&fill_in_categories)! = 0)) {if (other.mcategories! = null) {mcategories = new arrayset<s        Tring> (other.mcategories);    } changes |= fill_in_categories; } if (other.mpackage! = null && (Mpackage = = NULL | |        (flags&fill_in_package)! = 0)) {//only does this if mselector are not set. if (Mselector = = null) {Mpackage = Other.mpackage;        Changes |= fill_in_package; }}//Selector is special:it can only be set if explicitly allowed,//For the same reason as the component Nam            E. if (other.mselector! = null && (flags&fill_in_selector)! = 0) {if (mpackage = = null) {            Mselector = new Intent (other.mselector);            Mpackage = null;        Changes |= fill_in_selector; }} if (Other.mclipdata! = null && (Mclipdata = = NULL | |        (flags&fill_in_clip_data)! = 0)) {mclipdata = Other.mclipdata;    Changes |= fill_in_clip_data;  }//Component is special:it can-only-be set if explicitly allowed,//since otherwise the sender could force the    Intent somewhere the//originator didn ' t intend.        if (other.mcomponent! = null && (flags&fill_in_component)! = 0) {mcomponent = other.mcomponent;    Changes |= fill_in_component;    } mflags |= other.mflags; if (Other. Msourcebounds = null && (Msourcebounds = = NULL | |        (flags&fill_in_source_bounds)! = 0)) {msourcebounds = new Rect (other.msourcebounds);    Changes |= fill_in_source_bounds;        if (Mextras = = null) {if (Other.mextras! = null) {Mextras = new Bundle (Other.mextras);            }} else if (Other.mextras! = null) {try {bundle newb = new Bundle (Other.mextras);            Newb.putall (Mextras);        Mextras = newb; } catch (RuntimeException e) {//Modifying the extras can cause us to unparcel the contents//Of T  The He bundle, and if we do this in the system process and/or may fail.            We really should handle this (i.e., the Bundle//Impl shouldn ' t is on top of a plain map), but is now just Ignore it and keep the original contents.            :(        LOG.W ("Intent", "Failure filling in Extras", e); }} return changes;}

From the above code, we can arbitrarily specify all the fields except Mcomponent, which can satisfy most of the usage scenarios.

Exploits and Harms

With the previous analysis, the exploit code is very simple, here is an example of sending the system to start the broadcast:

// the exploit of broadcastAnyWherefinal String KEY_CALLER_IDENTITY = "pendingIntent";PendingIntent pendingintent = options.getParcelable(KEY_CALLER_IDENTITY);Intent intent_for_broadcast = new Intent("android.intent.action.BOOT_COMPLETED");intent_for_broadcast.putExtra("info", "I am bad boy");try {    pendingintent.send(mContext, 0, intent_for_broadcast);} catch (CanceledException e) {    e.printStackTrace();}

In fact, there are too many available broadcasts, such as:

    • Send Android.provider.Telephony.SMS_DELIVER can be forged to receive text messages;
    • Send Android.intent.action.ACTION_SHUTDOWN can be directly shut down;
    • Send Com.google.android.c2dm.intent.RECEIVE broadcast, the device will revert to factory settings;
    • Wait a minute

An attacker could forge a message from a friend or a bank e-commerce through a loophole, which is exactly the same as a normal text message, which no ordinary user can identify.

In addition to fake text messages, attackers can use this vulnerability to restore factory settings, threats to users, and so on.

Componentsuperaccessor

Combined with Luanchaynwhere and broadcastanywhere two vulnerabilities, I appropriately encapsulated a bit, implemented a componentsuperaccessor library, interested friends can go to https://github.com/ Boyliang/componentsuperaccessor.git download.

Security recommendations
    • For developers, penddingintent not pass across processes as much as possible, avoiding permission leaks. Or try to fill the fields in pendingintent to avoid malicious redirection;
    • For users and vendors, upgrade to Android L as soon as possible;

Detailed analysis of the vulnerability of Android Broadcastanywhere (Google Bug 17356824)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.