Android BroadcastAnyWhere(Google Bug 17356824)漏洞详细分析
作者:简行(又名 低端码农)
继上次Android的LaunchAnyWhere组件安全漏洞后,最近Google在Android 5.0的源码上又修复了一个高危漏洞,该漏洞简直是LaunchAnyWhere的姊妹版——BroadcastAnyWhere。通过这个漏洞,攻击者可以以system用户的身份发送广播,这意味着攻击者可以无视一切的BroadcastReceiver组件访问限制。而且该漏洞影响范围极广,Android 2.0+至4.4.x都受影响。
漏洞分析
修复前后代码对比
BroadcastAnyWhere跟LaunchAnyWhere的利用原理非常类似,两者都利用了Setting的uid是system进程高权限操作。
漏洞同样发生在Setting的添加帐户的流程上,该流程详细见《Android LaunchAnyWhere (Google Bug 7699048)漏洞详解及防御措施》一文。而BroadcastAnyWhere漏洞则发生在这个流程之前。在分析漏洞之前, 我们先来看看漏洞修复的前后对比,具体代码在AddAccountSetting的addAccount方法。
修复前代码中下:
...
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;
}
修复后代码如下
...
private static final String KEY_CALLER_IDENTITY = "pendingIntent";
private static final String SHOULD_NOT_RESOLVE = "SHOULDN'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 launching activities, services
* or broadcasts.
*
* Unfortunately for legacy reasons we still need to support this. But
* we can cripple the intent so that 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(
acc