Android账户机制漏洞
0x00前言
Android 2.0中加入了一个新的包android.accounts,该包主要包括了集中式的账户管理API,用以安全地存储和访问认证的令牌和密码,比如,我们的手机存在多个账户,每个账户下面都有不同的信息,甚至每个账户都可以与不同的服务器之间进行数据同步(例如,手机账户中的联系人可以是一个Gmail账户中的通讯录,可联网进行同步更新)。通俗地讲,就是Android系统会开一个异步进程去帮我们登录(验证)账号,就不需要我们每次点开APP的时候还要走一遍登录(验证)账号的流程。我们根据这个机制,找到了三个可以利用的漏洞。
0x01 账户机制介绍
我们先看一下账户机所运用到的API:
- 创建账户:
首先是class Authenticator extends AbstractAccountAuthenticator ,如下图,该类是账号验证类 ,其中addAccount方法用来定义需要增加账号时的操作,如调用AuthenticatorActivity来进行账号的添加认证:
- 同步账户
SyncAdapter继承自AbstractThreadedSyncAdapter,SyncAdapter同样需要一个服务(Service)和一个同步适配器(AbstractThreadedSyncAdapter)。SyncAdapter的Service 需要在AndroidManifest里面声明一个带有Intent:android.content.SyncAdapter的Service来达到向系统注册一个具有同步功能的账户适配器(sync-adapter)。同步的方法主要在:
在开发代码中用accountManager调用了addAccount方法后,就可以在android系统的 设置—>账户 里面可以看到我们创建的账户:
接下来点击Account账户中,可以找到立即同步的按钮,点击的话可以执行“立即同步”,就相当于执行了onPerformSync方法:
下图为安卓系统添加账户的整体流程图:
0x02 漏洞利用及复现
2.1 Launch Anywhere
AccountManagerService是系统服务之一,暴露给开发者的的接口是AccountManager。普通应用(记为AppA)去请求添加某类账户时,会调用AccountManager.addAccount,然后AccountManager会去查找提供账号的应用(记为AppB)的Authenticator类,调用Authenticator. addAccount方法;AppA再根据AppB返回的Intent去调起AppB的账户登录界面。这个过程如图所示:
- 漏洞原理:
这种设计的本意是,AccountManagerService帮助AppA查找到AppB账号登陆页面,并呼起这个登陆页面。而问题在于,AppB可以任意指定这个intent所指向的组件,AppA将在不知情的情况下由AccountManagerResponse调用起了一个Activity. 如果AppA是一个system权限应用,比如Settings,那么AppA能够调用起任意AppB指定的未导出Activity。
主要可以利用的代码:
/** Handles the responses from the AccountManager */
Private class Response extends IAccountManagerResponse.Stub {
Public void onResult (Bundle bundle) {
Intent intent = bundle.getParcelable(KEY_INTENT);
If (intent != null && mActivity != null) {
// since the user provided an Activity we will silently start intents
// that we see
mActivity.startActivity(intent);
// leave the Future running to wait for the real response to this request
} else if (bundle.getBoolean ("retry")) {
...
- 复现代码:
继承了AbstractAccountAuthenticator的类:
@Override
public Bundle addAccount(AccountAuthenticatorResponse response