在适用于 Android 的 COVIDSafe 应用 1.0.21 及更早版本中,GATT 连接中不安全地使用蓝牙传输选项,允许攻击者诱骗该应用通过蓝牙 BR/EDR 传输建立连接,从而在未经授权的情况下泄露受害者手机的公共蓝牙地址,绕过手机上的蓝牙地址随机化保护。此问题通过 CVE-2020-14292. 进行跟踪。
该问题的原因在于 startWork 函数, 该函数使用 connectGatt 建立 GATT 连接,但未指定传输选项。
fun startWork(
context: Context,
gattCallback: StreetPassWorker.StreetPassGattCallback
) {
gatt = device.connectGatt(context, false, gattCallback)
if (gatt == null) {
CentralLog.e(TAG, "Unable to connect to ${device.address}")
}
}
这将导致 Android 在发起蓝牙连接时对传输方式使用 TRANSPORT_AUTO 选项。从 Android 的实现来看,如果所连接的外设是双模设备(同时支持 BR/EDR 和 LE),则默认使用 BR/EDR 传输;这可能是由于 Android 中 GATT 客户端的以下实现所致,例如参见 此代码(相关代码片段如下):
// Determine transport
if (transport_p != BT_TRANSPORT_AUTO) {
transport = transport_p;
} else {
switch (device_type) {
case BT_DEVICE_TYPE_BREDR:
transport = BT_TRANSPORT_BR_EDR;
break;
case BT_DEVICE_TYPE_BLE:
transport = BT_TRANSPORT_LE;
break;
case BT_DEVICE_TYPE_DUMO:
if (transport_p == BT_TRANSPORT_LE)
transport = BT_TRANSPORT_LE;
else
transport = BT_TRANSPORT_BR_EDR;
break;
}
由于 BR/EDR 不支持 MAC 地址随机化,中心设备将向外设暴露其身份地址。
要发起攻击,攻击者需要在双模设备(BR/EDR + LE)上使用公共地址广播 GATT 服务器(这一步很重要,否则不会发生降级,Android 中心设备将使用 LE 传输)。这将导致 COVIDSafe 应用使用 BR/EDR 传输而非 LE 传输来连接外设,进而导致手机的公共地址被泄露。这对所有经过测试的手机和 Android 版本均有效。
对于 Android 6 及更高版本,修复方法很简单:只需显式指定传输选项。
gatt = device.connectGatt(context, false, gattCallback, BluetoothDevice.TRANSPORT_LE)
但是,这不适用于 Android 5.1(API 级别 22),因为该方法未在该 API 中公开。它实际上存在于 API 中,但被隐藏。 因此,对于 Android 5.1,一种可能的修复方案是使用反射来调用该隐藏方法。 这些修复已在 COVIDSafe(Android)v1.0.48 中实现。
然而,针对 Android 5.1 的修复可能并非 100% 有效;我的测试表明仍存在身份地址泄露。这可能是由于反射技术在运行时失败所致;需要进一步调查。
攻击者一旦掌握手机的身份地址,就可在手机开启蓝牙且处于攻击者蓝牙范围内时对该手机进行跟踪。某些与蓝牙相关的漏洞(例如 CVE-2020-0022)依赖于对身份地址的掌握来发起进一步攻击,因此存在将此攻击与其他攻击串联使用的可能。关于攻击者掌握身份地址可能带来的部分后果,请参阅此文档。
强烈建议 Android 版 COVIDSafe 应用的用户更新其应用。对于运行 Android 5 的用户,建议在不需要蓝牙功能的情况下关闭蓝牙。
此问题于 2020 年 6 月 2 日首次报告给澳大利亚政府数字转型局。第一个修复于 2020 年 6 月 22 日发布,适用于 Android 6 及以上版本,并已确认在 Android 6 及以上版本上有效。但该问题仍影响 Android 5.1。第二个修复于 2020 年 7 月 30 日发布,解决了 Android 5.1 的剩余问题。
感谢 Jim Mussared 独立确认此问题,并就此问题进行了多次讨论。