简介
这篇文章将详细介绍我在 D-Link 的带摄像头 Komfy 开关 上的发现——通过蓝牙 4.0 (BLE) 获取设备关联的 wifi ssid 和密码。Komfy 开关是一款家庭安全和自动化产品,可以替换家中的墙壁开关,提供视频监控、温度、湿度水平和空气质量监测,以及灯开关的远程控制。
蓝牙 BLE 分析
在决定进一步深入研究之前,我使用 LightBlue iOS 应用对 BLE 设备进行了一些快速分析。此时,Komfy 设备已在线,并配置了典型的使用场景设置。通过 LightBlue 连接到 Komfy 时,我注意到一个非标准的 GATT 服务,暴露了八个自定义特征(或功能)。考虑到 BLE 规范中每个数据包最大为 20 字节,其中两个特征接收到的数据量异常大。如果外设和主设备都支持,则可以协商更高的 MTU,以支持通常所说的“长”读取或写入。下面的前几张截图展示了 GATT 服务和特征(从 0xB002 到 0xB00A)。接下来的两张截图展示了本文将重点分析的两个特征(0xB006 和 0xB007)。0xB006 和 0xB007 特征显示了 Wifi SSID 以及一个在解码为 ASCII 后看起来像是 base64 编码字符串的内容。然而,如最后一张截图所示,对该字符串进行 base64 解码并未显示任何可读数据。
Komfy 应用:方法调用跟踪
为了更好地理解 Komfy 设备实现的 GATT 特征,我使用 class-dump-z 转储了 Komfy iOS 应用的方法,并为感兴趣的方法设置了方法跟踪。完整的类转储可参见此处。我特别关注 BLEDevice 类以及任何其他引用蓝牙的方法。可以使用 Prateek 在此处详述的 Logify.pl Perl 脚本来设置方法跟踪。
上面的截图显示了在全新安装和配置 Komfy 期间的方法跟踪输出。注意以明文形式出现的 Wifi 密码 "chipotlemakesmehappy",然后又是之前 LightBlue 应用从 0xB007 GATT 特征中获取的那个看起来像 base64 的字符串。跟踪实际上显示了对 +[Base64 encode:] 方法的调用,起初这让人困惑,因为使用标准库无法对其进行 base64 解码。几乎可以断定 base64 解码后的值是经过加密或进一步编码的,直到意识到 +[Base64 encode:] 是一个私有实现的方法(并非来自 NSData 类)。这种古怪的编码必须得到解决。
使用 Hopper 进行反汇编
现在开始对 D-Link 实现的“base64”编码方案进行逆向工程(“逆向工程”这个词听起来比实际要难得多,尤其是考虑到最终的结果)。在 Hopper 中加载 Komfy 应用,并分析 -[BLEDevice getWifiPassword:] 和 +[Base64 decode:] 方法,这是显而易见的起点。分析 -[BLEDevice getWifiPassword:] 验证了 0xB007 GATT 特征确实在检索 Wifi 密码。
浏览 +[Base64 decode:] 的 ARM 汇编代码,发现它与标准的 NSData 类实现非常相似,于是我转而查看 +[Base64 encode:]。Hopper 很快就给了我答案的提示。在其中一条汇编指令附近打印了一个字符串常量,它包含了标准 base64 字母表中的所有字母,但顺序完全错乱。因为没想到这种简单的替换(难度不亚于最初的凯撒密码),我略感尴尬,于是写了一个脚本来还原 base64 字符的顺序,瞧!屏幕上打印出了 "chipotlemakesmehappy"。
所以本质上,以下是还原并对该字符串进行 base64 解码的方法:

完整的 autopwn 脚本在此。
而且,是的,Chipotle 确实让我很开心。
Ubertooth BLE 捕获文件可在此下载。