利用 checkm8 漏洞访问 iPad 文件系统
近期,笔者接到了维修一台屏幕完全碎裂的 iPad 的请求。根据机主描述,这台 iPad 在多年前由于从高处跌落,外屏完全损坏,无法开机,因此长期没有使用。但是里面有一些重要的照片,希望能够取出来。
经过检查,这台 iPad 型号为 iPad Mini 1(A1432 版本)。机器状况确实非常不理想,不仅屏幕碎裂,后壳也有明显的变形。只能祈祷主板没有受损,不然就超出笔者的维修能力了。
这一代 iPad 的外屏是通过胶水粘合的,正常的拆卸方法是加热后将屏幕揭开,但由于外屏已经完全脱落,这一步骤甚至可以省略。进一步拆卸可以参考 iFixit 发布的指南,并不麻烦,主要就是拧螺丝和拆排线,谨慎操作即可,避免损坏一些脆弱的部件。经过拆卸,这台机器的主板外观还比较完好,变形也比较轻微,看上去还能抢救一下。但是,除了主板外,其它很多硬件都存在不同程度的受损。
相比于单独购买屏幕、电池等配件进行替换,更方便的方法是直接买一台好的 iPad,来一手借尸还魂,把坏机器的主板挪过去。在闲鱼上,同款的 iPad Mini 1 已经是白菜价格,外观成色完美的也就大几十块钱,因此这个方案是经济可行的。
硬件维修的部分还算顺利,经过拆机和更换硬件,这台 iPad Mini 1 终于能够正常开机了。
接下来才是真正有趣的部分:这台 iPad 设置了锁屏密码,但是由于多年没有开机,机主已经忘记了密码。如果要将其中的数据备份出来,就得想办法访问到 iPad 的文件系统了。如果设备在越狱后开启了 SSH 服务,我们可以通过 libimobiledevice 提供的 usbmuxd 转发端口,使用 SSH 连接来访问文件系统。但遗憾的是,经过简单的实验,这台 iPad 似乎并没有越狱,SSH 服务也没有启动,这条路行不通。
由于 iPad Mini 1 是非常古早的设备,想必是有很多现成的 n-day 漏洞可以利用。其中,最著名的就是 2019 年由 iOS 安全研究员 axi0mX 披露的 checkm8 漏洞(这个缩写类似 DotA2 中的 str8,8=eight 是读音的缩写,原意即为 checkmate)。checkm8 漏洞存在于 iOS 设备的 ROM 中,通过 USB 发送恶意的 Payload,可以实现任意代码执行,绕过设备的安全启动限制。这个漏洞影响了搭载 A5 到 A11 芯片的苹果设备,并且苹果无法通过软件更新来修复这个漏洞,非常适合我们的场景。不过,由于 checkm8 漏洞利用需要通过 USB 进行,目前针对 A5 芯片最成熟的方案是使用 Arduino USB Host Shield,这需要我们准备特殊的硬件。
准备工作
我们需要用到的硬件包括:
- Arduino 开发板以及 USB 线,支持的型号包括 Leonardo 和 UNO R3;由于还需要 patch 特定版本的 USB Host Library,较新的 Arduino(例如 UNO R4)可能不适用;
- USB Host Shield,这是一个扩展板,可以让 Arduino 支持 USB Host 模式;需要注意,全新出厂的 USB Host Shield 需要焊接 3.3V 和 5V 供电才能正常使用,可以参考其它教程;
- USB-A 转 Lightning 数据线,用于连接 iPad(USB-C 转 Lightning 的线可能无法让 iPad 进入 DFU 模式)。
需要的软件包括:
- Arduino IDE,用于编译和烧录代码;
- checkm8-a5,这是通过 checkm8 漏洞破解设备的软件,它的依赖则是 Arduino 的 USB Host Library;
- USB Host Library,这是在 Arduino 上支持 USB Host Shield 的库,需要 patch 后才能支持 checkm8-a5;
- Legacy-iOS-Kit,这是一套针对旧版 iOS 的工具集,包括了一些常用的脚本,例如降级系统。
操作步骤
烧录 checkm8-a5
首先,我们将 checkm8-a5
程序烧录到 Arduino 开发板上。将焊好电源供电的 USB Host Shield 插到 Arduino 上,并将 Arduino 连接到电脑。然后,将 checkm8-a5
的代码仓库克隆到本地:1
git clone https://github.com/synackuk/checkm8-a5
checkm8-a5
的代码里除了需要变异并烧录进 Arduino 的主程序 checkm8-a5.ino
外,还包含了对 USB Host Library 的补丁。我们需要在 Arduino 库中安装 USB Host Library,然后再打补丁。根据仓库里的文档,首先安装 USB Host Library:1
2
3
4cd path/to/Arduino/libraries
git clone https://github.com/felis/USB_Host_Shield_2.0
cd USB_Host_Shield_2.0
git checkout cd87628af4a693eeafe1bf04486cf86ba01d29b8
Arduino 的库目录可能在不同的系统上有所不同,笔者的 Mac 上是 ~/Library/Arduino15/libraries
。
如果没问题的话,就可以打补丁了:1
git apply path/to/usb_host_library.patch
usb_host_library.patch
位于 checkm8-a5
仓库的根目录下,对应修改路径即可。打完补丁后,打开 Arduino IDE,然后打开 checkm8-a5
仓库的 checkm8-a5.ino
,选择 Arduino 的型号和端口,然后编译并烧录即可。
进入 DFU 模式
checkm8 漏洞的利用需要在设备进入 DFU 模式后进行,因此我们需要先让 iPad 进入 DFU 模式。笔者尝试成功率比较高的进入 DFU 模式的步骤是:
- 将 iPad 通过 USB 转 Lightning 线连接到电脑,否则无法进入 DFU;
- 按下电源键,保持 3 秒;
- 不松开电源键,同时按下 Home 键,保持 8 秒(如果一开始设备处于开机状态,这一步之后设备屏幕会熄灭);
- 松开电源键,继续按住 Home 键一段时间,直到设备进入 DFU 模式。
需要注意,在进入 DFU 模式时,设备屏幕会一直保持黑屏,不会出现苹果标志或连接 iTunes 的提示。这一点笔者最开始也弄混了 —— 如果出现了连接 iTunes 的提示,那就是进入了恢复模式,它和 DFU 并不同,需要重新开始。如果出现了苹果标志,那就说明电源键按下的时间太久了。没有操作成功也不要灰心,可以耐心地多次尝试。
进入 pwned DFU 模式
接下来,用 USB 线将已经进入 DFU 模式的 iPad 连接到烧录好 checkm8-a5
的 Arduino 上,然后再将 Arduino 连接到电脑(连接之后可以通过串口查看日志,判断是否破解成功了;否则,需要用一个 LED 进行判断)。
使用串口监控程序,查看 Arduino 的输出。正常情况下,会滚动输出大量通过堆风水来实现漏洞利用的日志。最后显示 Done!
就是成功破解了设备,进入 pwned DFU 模式。
如果没有成功的话,可以重复尝试将 iPad 进入 DFU 模式,然后再次连接 Arduino,以进入 pwned DFU 模式。
加载 Ramdisk
进入 pwned DFU 模式后,我们可以通过 Legacy-iOS-Kit
提供的脚本加载 Ramdisk 并启动设备。将 iPad 再次用 USB 线连接到电脑上,然后启动 Legacy-iOS-Kit
(推荐在 Linux 系统中进行)。之后,依次选择 Other Utilities -> SSH Ramdisk。
之后会遇到一个选项,由于我们是 pwned using checkm8-a5,所以选择 n。
如果顺利的话就能够成功加载 Ramdisk,然后启动设备了。如果没有成功,可以再次重试以上步骤。
这时候,我们就可以通过 SSH 连接到设备,访问文件系统了。Legacy-iOS-Kit
提供了一个 Connect to SSH 的选项,不过为了方便拷贝文件,我们使用系统自带的 ssh 进行连接。
访问文件系统
ssh 连接的默认端口是 6414,不过直接连接的话会提示 no matching host key type found。这个问题的解决方案可以参考这个回答,把命令换成:1
ssh -oHostKeyAlgorithms=+ssh-rsa -p 6414 root@localhost
默认登陆密码是 alpine
。如果 ssh 登陆成功,就可以执行 mount.sh
脚本,挂载文件系统。iPad 上的所有文件都在 /mnt2
目录下,可以直接访问。如果没问题的话,就可以进一步通过 scp
等命令拷贝文件了。
解除密码尝试限制
在完成了数据的备份后,机主表示还是想要把 iPad 的密码试出来。众所周知,正常情况下,密码尝试次数过多会导致设备锁定。不过,在能够读写系统的情况下,密码尝试次数也可以被破解。我们可以通过修改 /mnt2/mobile/Library/Preferences/com.apple.springboard.plist
文件来解除密码尝试限制。这个文件是二进制的,可以使用 Mac 上的 Xcode 打开:
我们可以通过修改其中的 SBDeviceLockFailedAttempts
字段来解除限制,将其修改为 - 9999 即可。完成后,重新将此文件复制回 iPad。下次开机时,就可以尝试 9999 次密码,足够我们找到正确的密码了。不过,如果要自动化地进行密码尝试,还需要进一步的工作。