iOS搜索派对深度解析:FindMy网络数据取证与加密数据库解密

本文深入探讨了iOS系统如何处理FindMy网络兼容设备的观测数据,揭示了加密数据库Observations.db的解密方法、其中记录的设备发现时间、位置、信号强度等信息,及其在数字取证中的应用价值与数据保留挑战。

进一步观察:深入探索iOS搜索派对

iOS正在观察。也在进行判断。

注意:本文假设您已阅读之前一篇关于AirTags的文章(链接在此),因为它会引用与iOS searchpartyd相关的项目,且几乎不做解释。强烈建议在继续阅读前先阅读前一篇文章。

在过去的几个月里,我一直在探索iOS的搜索派对功能。它是支撑苹果FindMy网络运作的核心机制。理解其底层工作原理以及哪些数据在取证上可能可用,花费了一些时间。主要的障碍是加密。对此,我的感受是矛盾的。作为一名用户,我欣赏这种数据保护。作为一名从业人员,我欣赏这种数据保护。去年在准备一个SANS演讲时,我与这个问题斗争了一段时间,最终才弄清楚了如何获取关于不受欢迎的AirTags的信息(您可以在这里阅读那次尝试)。

事实证明,从searchpartyd中还可以获取其他数据,这使其处理蓝牙追踪器检测的方式与Android相似。为了测试,我使用了运行iOS 17.5.1的iPhone 14和运行iOS 18.3的iPhone 11,后者是对去年研究的更新。请注意,本文描述的文件仅在iOS 16.x及以上版本中观察到。

加密。再一次。

在研究“野生AirTags”文章时,我不禁想知道iOS是如何追踪它在环境中看到的FindMy兼容设备的。毕竟,苹果在谈论这一功能时,喜欢吹嘘网络上有多少兼容设备。显然,iOS必须将这些数据存储在某个地方,我认为这可能类似于Android处理恶意设备的方式。在同一父目录(/private/var/mobile/Library/com.apple.icloud.searchpartyd)中有几个数据库看起来是可能的候选,但我发现这些文件当然是加密的。其中一个候选者是一个名为Observations.db的SQLite数据库。参见图1。

图1. com.apple.icloud.searchpartyd中的Observations.db。

用十六进制查看这个文件揭示了一些有趣的信息。参见图2。

图2. 十六进制格式的Observations.db。

乍一看,这个文件似乎是加密的,确实如此;然而,这里有一个非常细微的线索,直到我开始查看父级searchpartyd目录中的其他数据库时才发现。这个线索(在图2的红框中高亮显示)是第16-23字节没有加密。这些字节是SQLite文件头的一部分,提供了一些关于数据库的信息。它们表示以下内容(大端序读取):

字节
16 – 17 页大小(字节数)
18 格式写入版本(1 = 传统,2 = WAL)
19 格式读取版本(1 = 传统,2 = WAL)
20 页尾保留字节(填充)
21 最大嵌入式负载(必须为64)
22 最小嵌入式负载(必须为32)
23 叶子负载比例(必须为32)

检查同一目录路径下的其他数据库发现,这种行为(以及字节值)在所有文件中是(都是)相同的。我观察到每个数据库的以下值:

字节
16 – 17 每页4096字节 (x1000)
18 WAL写入版本 (x02)
19 WAL读取版本 (x02)
20 12字节填充 (x0C)
21 64字节最大负载 (x40)
22 32字节最小负载 (x20)
23 32字节叶子负载比例 (x20)

多个文件的这些字节相同,排除了SQL Cipher作为加密方法。事实证明,Observations.db(以及其他数据库)是使用SQLite加密扩展加密的。SEE规范指出,这些字节作为该方法的一部分不被加密。此外,该方法在RC4、AES-128或AES-256模式下运行,填充为12字节;在这种情况下,填充是数据库中每个页的初始化向量。了解这些信息后,我转向钥匙串,查看可能与searchpartyd相关的其他凭证。参见图3。

图3. 按searchpartyd过滤的钥匙串条目。

图3显示了iPhone 14的钥匙串,过滤了与searchpartyd相关的项目(红框中高亮显示)。令人惊讶的是,我在searchpartyd目录中看到的每个数据库(见图1)都有其对应的钥匙串条目,名称完全一致。Observations.db的密钥长度为32字节,这意味着很可能使用了AES-256 OFB模式的SEE。有了密钥、页大小和填充信息,我开始尝试解密数据。虽然我不是它最大的粉丝,但我得承认,ChatGPT在这里尝试不同方法直至最终生成可用的数据库时确实帮上了忙。我(至今仍然)不信任它,因此我请Ian Whiffin协助,他发现-WAL文件的加密存在一些额外的棘手问题,花了一些时间才解决。不过,最终结果是得到了解密的数据库及其关联的-WAL文件。

观察

Observations.db的行为确实如我所料:它记录着所有看到的FindMy兼容设备(稍后会详细介绍其外观)。与它的Android版本不同,数据分散在三个表中:ObservedAdvertisement、ObservedAdvertisementBeaconInfo和ObservedAdvertisementLocation。为了方便,我创建了一个快速的SQLite查询来汇总数据:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
SELECT
ObservedAdvertisement.scanDate AS "Seen_Time",
ObservedAdvertisementLocation.latitude AS "Latitude",
ObservedAdvertisementLocation.longitude AS "Longitude",
ObservedAdvertisementBeaconInfo.beaconIdentifier AS "Identifier",
ObservedAdvertisement.macAddress AS "MAC_Address",
ObservedAdvertisement.rssi AS "Signal_Strength",
ObservedAdvertisement.advertisementData AS "Advertised_Data"
FROM
ObservedAdvertisementLocation
LEFT JOIN ObservedAdvertisement ON ObservedAdvertisement.advId = ObservedAdvertisementLocation.advId
LEFT JOIN ObservedAdvertisementBeaconInfo ON ObservedAdvertisementBeaconInfo.advId = ObservedAdvertisementLocation.advId
ORDER BY "Seen_Time"

执行后的查询结果见图4。

图4. 执行后的SQL查询。

就像Android一样,iOS记录了它看到FindMy兼容设备的时间,以及检测到它们时手机的位置。iOS在位置数据来源方面并不匮乏,但这是另一个可靠的来源(这些经纬度值非常准确)。还有一个信号强度值,有助于了解与被检测设备的接近程度。该值越接近0,信号越强,理论上设备离手机越近;然而,重要的是要记住,环境条件如建筑结构、地形、人员和电磁干扰都可能影响RSSI值。

查询还显示了信标标识符。与手机上登录的iCloud账户或与之共享账户所拥有的信标(指任何参与FindMy网络的设备)将有一个标识符。有关这些UUID的信息可以在~/BeaconNamingRecords/~/SharedBeacons下的plist文件中找到。这些在我的上一篇AirTag文章中有所涉及。图4中看到的每个条目都有一个UUID值,这表明看到的信标与手机上登录的iCloud账户相关联,无论是拥有的还是共享的。

查询返回的最后两列与观察到的设备的MAC地址和相应的广播载荷有关。由于在FindMy网络上运行的设备使用旋转的蓝牙MAC地址(根据规范),在信标与账户无关的情况下(即数据库记录中没有UUID),这些MAC地址基本上是无用的。然而,在不受欢迎的跟踪案例中,可能有应用价值。例如,如果同一个MAC地址在一段时间内(可能是24小时左右)持续出现在Observations.db记录中,但手机尚未将其识别为WildMode项目。

广播信息很有趣。首先,参见图5。

图5. 来自Advertised_Data(advertisementData)列的BLE广播数据。

Advertised_Data列中的数据应该包含某些信息,但我发现,至少对于AirTags和AirPods,只包含了部分数据。由苹果和谷歌共同起草的公共规范指出,广播其数据的设备应在广播载荷中提供以下信息:

字节:
0 – 5 MAC地址
6 – 8 标志TLV(可选)
9 – 12 服务数据TLV(可选)
13 网络ID
14 靠近所有者位(LSB + 7个保留位)(1=是, 0=否)
15 – 36 专有载荷(可选)

关于这个规范和观察到的载荷,有三点需要注意。首先,此规范仍处于草案阶段,因此很可能不完整。例如,就我所知,网络ID尚未在IANA注册,因此目前很难判断设备属于哪个网络(谷歌或苹果)。我在上面描述的字节13中没有发现任何一致性。其次,我还发现广播载荷中的靠近所有者位在不同设备间也不一致。有时字节14中的最低有效位被设置为“1”,但它并不是测试账户所拥有的信标,并且测试手机会发出不受欢迎的警报。这引发了两家公司目前是否遵循规范的疑问。我完全预计这会改变,但目前情况似乎并不总是一致,这使它们不可靠。

第三,“Advertised_Data”列中广播的载荷数据中的MAC地址与“MAC_Address”列中看到的MAC地址存在差异。参见图6。

图6. 图5中看到的信标的MAC地址。

注意,图6中第一个字节的第一个半字节与图5中看到的(87对比C7)不同。这是由于网络上运行的设备使用的随机化方式。蓝牙规范对此有详细说明,但根据苹果-谷歌规范,两个最高有效位应该以某种方式切换,成为私有的、不可解析的MAC地址;然而,我观察到的并非如此(再次强调,该规范是草案)。在上面的例子中,第二最高有效位从1变为0,导致MAC地址的第一个八位字节从C7(0b11 – 静态地址)变为87(0b10 – 保留供私人使用)。

图7-1和7-2显示了位变化如何影响第一个八位字节。

图7-1. 以C7开头的静态地址。

图7-2. 以87开头的“保留供将来使用”地址。

为了举例说明,我带着一个AirTag,使用了iPhone 11和一部小米Poco X7 Pro。两部设备都看到了这个标签。图8显示了来自Observations.db的MAC地址,图9显示了来自小米手机的Android追踪器检测数据库中的MAC地址。

图8. 来自Observations.db的观察到的静态MAC地址。

图9. 来自小米手机的观察到的MAC地址。

注意,小米设备似乎已经完成了从“保留供将来使用”地址到静态地址的转换,因为没有任何引用以8F开头的地址,而这个地址在iPhone观察到的载荷中可以看到(见图10)。

图10. 来自AirTag的观察到的载荷。

为了再次说明位变化,参见图11-1和11-2。

图11-1. 以CF开头的静态地址。

图11-2. 以8F开头的“保留供将来使用”地址。

关于Observations.db的三点说明。首先,我发现当设备静止或移动不大时,条目写入此文件的频率更高。在我驾驶期间,相比于手机在我家或其他我或手机不怎么移动的地方,它观察的频率似乎更低。静止时,手机经常看到信标。例如,观察到一个信标的间隔从两秒到四秒不等。其他信标被观察到的频率更高!频率可能是手机观察环境的产物,但要知道它可以非常频繁地发生。

第二点说明,这一点非常重要:这个数据库丢弃和清理记录的速度非常、非常快。例如,其中一个测试环境是我家附近五分钟车程的一家本地餐厅。我带了一个“野生”AirTag,在餐厅里坐了一个多小时。我直接开车回家并运行了提取。Observations.db中完全没有关于餐厅里那个AirTag的任何信息;然而,从我开进车库到我打开飞行模式运行提取(在我家)之间,它确实看到了那个AirTag十次。另一个测试涉及AirTag和iPhone 14,当时我正在做一些纹身工作(大约三个小时)。在离开纹身店之前,我将手机置于飞行模式,确保蓝牙无线电关闭,然后开车回家。这一次,Observations.db中记录了相当多的条目,似乎是纹身店的AirTag(基于RSSI值),以及从我家中到纹身店途中偶尔记录的位置。

我提到这两个场景是想说明:如果你想从这个数据库中获取不涉及你的实验室/工作场所的位置数据,必须在设备被扣押的地方(即犯罪现场)确保蓝牙无线电被切断。否则,Observations.db将丢弃和清理可能与你的检查目标相关的记录。例外情况是与拥有/共享信标相关的记录。这些记录往往保留的时间要长得多。

最后,使用关联的-WAL文件检查此文件也极其重要。为了说明原因,参见图12和图13。

图12. 不带-WAL的Observations.db。只有264条记录…

图13. …带上-WAL。多了四十条记录!

从-WAL中提取的记录量可能很大,并且很可能包含主数据库中没有的数据,因此请确保你使用的任何工具都能处理-WAL条目。由于记录写入和删除的速度很快,使用-WAL检查文件是必要的。

一个示例

为了说明Observations.db如何处理未知信标,我带着iPhone 11和一个AirTag去了一个人口密集的地方:纽约市的肯尼迪机场。由于有这么多人(和i设备),iPhone应该有很多可观察的对象,这应该会使Observations.db非常繁忙。AirTag和iPhone 11都在我的背包口袋里,并且实际上相互接触,因此理论上,RSSI信号应该相对较高,这可能有助于识别AirTag。事实证明,这些想法是正确的。参见图14。

图14. iPhone 11看到了许多记录,但有两个突出。

由于RSSI信号的原因,图14红框中高亮显示的值与Observations.db中的其他数据相比是异常值。RSSI值为-37和-38都是接近距离的良好指标。与这两个条目关联的广播载荷是相同的。图15高亮了图14中-38 RSSI记录条目的广播载荷。图15中还高亮了广播的MAC地址。

图15. 广播的载荷。

Observations.db中有多条记录具有此载荷,这表明AirTag在机场“跟随”我。最终,AirTag被识别为不受欢迎的,这触发了在searchpartyd目录的~/WildModeAssociationRecord中创建了一个plist文件,但没有通知。iPhone 11为该AirTag分配了标识符13BB48EF-F050-4013-A36B-309821C999ED。解密plist文件发现了以下信息。参见图16。

图16. 测试AirTag的WildModeAssociation记录。

加密plist文件中的广播数据(图16红框)与在Observations.db的广播载荷中看到的数据匹配。此外,载荷中的MAC地址在plist中有自己的键/值对(图16蓝框高亮),并且与广播载荷中的匹配。此外,第一个位置条目(未高亮)将手机定位在肯尼迪机场的4号航站楼,这正是我所在的位置。参见图17。

图17. WildModeAssociation记录中看到的第一个位置。

.plist文件的底部包含了一些信息。即,给用户(我)的(可能的最终)通知状态,以及.plist文件创建前最后一次看到的位置。参见图18。

图18. 观察到的状态和最后看到的位置。

上面,通知状态“已暂存”在红框中可见,以及最后看到的位置(未高亮)。映射位置见图19。我当时静止在4号航站楼的B48登机口等待登机。

图19. 通知前的最后看到位置。我在B48登机口。

Observations.db中的位置略有不同,因为关联的时间戳晚于.plist文件中的时间戳;Observations.db记录发生在.plist文件中最后一个位置之后大约1小时20分钟。图20显示了映射位置。请注意,位置出现在4号航站楼外,这是合理的,因为我在飞机上(就在起飞前)打开了iPhone 11的飞行模式。

图20. 在飞机上。

又一个观察结果

虽然我能够查看父级searchpartyd目录中的其他数据库,但它们都没有包含任何有价值的数据,大多数是空的,只有一个例外:ItemSharingKeys.db。这个数据库很有趣。它包含与所检查设备上iCloud账户所有者共享的信标的广播数据,但这并不是它有趣的地方。它的有趣之处在于,它似乎包含共享信标的当前和未来广播载荷信息,包括一组私钥和蓝牙MAC地址。为了提取必要的信息,我稍微修改了SQL查询,添加了Observations.db中的广播标识符。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
SELECT
ObservedAdvertisement.scanDate AS "Seen_Time",
ObservedAdvertisementLocation.latitude AS "Latitude",
ObservedAdvertisementLocation.longitude AS "Longitude",
ObservedAdvertisementLocation.advId AS "Advertisement_Identifier",
ObservedAdvertisementBeaconInfo.beaconIdentifier AS "Identifier",
ObservedAdvertisement.macAddress AS "MAC_Address",
ObservedAdvertisement.rssi AS "Signal_Strength",
ObservedAdvertisement.advertisementData AS "Advertised_Data",
ObservedAdvertisementBeaconInfo.sequence AS "Sequence_Number"
FROM
ObservedAdvertisementLocation
LEFT JOIN ObservedAdvertisement ON ObservedAdvertisement.advId = ObservedAdvertisementLocation.advId
LEFT JOIN ObservedAdvertisementBeaconInfo ON ObservedAdvertisementBeaconInfo.advId = ObservedAdvertisementLocation.advId
ORDER BY "Seen_Time"

此查询从ObservedAdvertisementLocation表中提取广播标识符。此列中的值与ObservedAdvertisementBeaconInfo表中的列索引相关,后者是我们感兴趣的列。接下来,参见图21和图22。注意图21右窗格中共享标签的MAC地址载荷。

图21. Observations.db中共享标签的记录条目,以及广播ID和MAC地址。

图22. Observations.db中ObservedAdvertisementBeaconInfo表的广播ID和索引值。

ObservedAdvertisementBeaconInfo中的列索引与ItemSharingKeys.db中NearOwnerKeys表的同名列相关。参见图23。

图23. 图21中的广播MAC地址。

图23中有趣的发现是,AirTag的广播MAC地址列在nearOwnerAdvertisement列中。还有一些额外数值递增的索引号,每个都有自己的nearOwnerAdvertisement值,所有这些似乎都是MAC地址。为了进一步调查,我等了几个小时,带着同一个“共享”AirTag,开车转了一会儿,然后重新提取了设备。图24显示了后来提取的Observations.db。

图24. 后来提取的记录条目。注意广播标识符。

在ObservedAdvertisementBeaconInfo表中查找索引列中的值126603。参见图25。

图25. 从后来提取中获取的新索引值。

跳回到第一次提取的ItemSharingKeys.db,并查找126603,可以看到图26所示内容。

图26. nearOwnerAdvertisement中匹配的MAC地址。

广播的MAC地址匹配。本质上,与之共享AirTag的手机为该共享AirTag保留了一批广播MAC地址,很可能供将来“看到”该AirTag时使用。NearOwnerKeys表中有230条记录,因此理论上,可能可以在合理范围内预测共享AirTag的广播MAC地址。显然,这需要超出本文范围的额外研究,但规范要求能够预测地址序列,这无疑为这一理论提供了可信度。

到此为止。暂时如此。

这是一个不错的发现,因为它在一定程度上证实了我的想法,即iOS设备像Android一样,会记录它们看到的所有FindMy兼容设备。Observations.db为检查人员提供了iOS上又一个位置数据来源,尽管其保留时间还有很大改进空间。尽管如此,它是另一个来源,如果处理得当,可以被利用。

虽然iOS 17和18之间似乎相当一致,但我完全预期一旦公共规范发布,情况就会发生变化。当然,这并不排除今年晚些时候iOS 126到来时发生变化。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计