本文是本系列的最后一篇,我们将继续向读者介绍如何破解三星手机固件,并将其变成NFC安全研究的利器。
改变漏洞的利用方式
我们还发现 I2C 通信无法打印,因为该选项似乎已从手机配置中完全删除。这使得很难跟踪更新期间的任何更改。最后,我找到了一个名为“/proc/”的文件,其中包含有关执行某项操作的时间以及发送到芯片的有效负载大小的数据。
通过这个文件,我能够跟踪新的固件更新过程。最终,我注意到在固件更新开始时,发送的哈希块大小为 0x24。这是 4 字节命令头和 32 字节哈希值的长度。我以为这意味着芯片使用的是 SHA-256 算法而不是 SHA-1 算法,幸运的是,事实确实如此。
摸着石头过河
由于没有相关代码可供使用,所有漏洞利用方法都是通过反复试验来完成的,或者更准确地说,基于对芯片工作原理的假设和从原始芯片获得的知识。
首先,我想证明缓冲区溢出仍然存在。为此,我开始增加哈希的大小,直到芯片因接收过多数据而停止响应。我可以通过观察芯片在发送最后一个命令后是否没有响应,或者响应然后崩溃来找到堆栈的确切大小。如果发生后者,则意味着它仍然在芯片的 RAM 中。
现在我知道了堆栈的大小,我可以用 32 位指针填充它。这将使找到所有链接寄存器的值变得最快,并且如果以这种方式篡改它们,则不太可能导致问题。
到目前为止,我还不知道我需要在引导加载程序中跳转到哪里,因为我看不到它,所以我决定采取蛮力的方法。
从芯片上的最低地址开始,开始填充堆栈,然后按照 执行固件。如果此时芯片没有响应 NCI 请求,则意味着它不在正确的位置。此时,您可以启动芯片,将地址增加 2,然后重试。最终,我们发现这种攻击方法在地址 处有效。
报告错误
在我重现该漏洞后,我将其披露给了三星,因为我觉得他们很想修复它。截至 2020 年 4 月,他们已经修复了所有新生产的芯片和目前正在开发的芯片上的漏洞。然而,之前出货的芯片仍然可能受到该漏洞的影响,并且可以在这些芯片上运行自定义固件。
创建自定义固件
虽然修改版本号是一个很好的 POC,但它并没有充分利用这种嵌入式芯片的全部功能。通过修改固件,我不仅能够模拟 13.5 毫米 NFC 标签、嗅探 NFC 通信,甚至还能发起基于读取器的攻击。
因此,我决定将最初的目标保持简单:转储引导加载程序。我想通过 I2C 接口执行此操作,因为这会使以后的调试更加容易。
我打算修改现有固件并添加自己的功能。因此,我首先必须找到具有大量可用空间的固件。因此,我下载了旧的三星 S8 ROM 并提取了其固件的二进制文件。在这个文件中,我发现了一个大约 FF 字节的值。这表明闪存中有可用内存,因此我可以根据需要转储自己的代码,而无需通过覆盖现有代码来破坏它。
我想用 C 语言编写自定义代码,因为它比编写汇编代码容易得多。为此,我使用了 ARM gcc 编译器并使用了“-c”标志。此标志的作用是告诉编译器不要执行链接或重定位过程,而只是编译一个基本目标文件。这种方法的缺点是您无法访问标准库,也不能使用堆 - 您必须自己担心堆。让我从一个基本的 C 函数开始。
在 C 语言中,函数调用以分支和链接指令的形式进行,这些指令将当前程序计数器存储在链接寄存器中,然后以相对寻址的方式跳转到当前位置。这样做的主要原因是从被调用函数返回。由于我的 C 函数在编译时会相应地处理返回地址和堆栈,因此我可以根据需要在实际固件中通过覆盖现有的和链接指令来跳转到相应的地址。
Link 指令采用补码形式的相对地址,因此我们可以跳转到当前位置前后的代码。这个过程可能有点复杂,需要重复计算。为此我编写了一个函数来完成这些繁琐的计算。
我扩展了这个构建应用程序以允许函数重定位,这意味着我不仅可以从我的自定义 C 代码中调用函数来实现尽可能多的功能,而且还可以更轻松地获取相对于我的代码中的自定义函数的地址。
该工具不仅能够以最基本的形式编译我的 C 函数,还能将它们转储到固件有效负载中,覆盖相应的目标函数。
在这里,我决定覆盖一个名为“2F 24”的供应商特定的 NCI 函数,因为我发现我可以向它发送任意长度的参数,并且它在我正在查看的设备上没有任何有意义的功能。
为此,我们需要搜索可能设置 NCI 响应的位置,即以“4F 24”开头的地址 - 我使用 IDA 中的正则表达式搜索“MOVS.*#0x24”并找到了一个函数调用,这肯定是我需要修改的函数。
快速分析表明“”函数正在发送 I2C 响应,因此我选择覆盖“”函数,因为这样我就可以修改响应数据而不允许任何其他操作。
此外,我希望能够接收参数,例如读取的内存地址,但此时,我不知道它们将存储在 RAM 中的什么位置。为了找到这些地址,我创建了一个 NCI 请求,即“2F 24 04 FA CE FA CE”,然后开始搜索这个任意但唯一的值。然后我让代码转储这个地址,以便我可以根据需要在函数中读取它。
有了这些,我就能编写可以转储任意内存的代码了。这样,我们就可以用它来转储引导加载程序。
然后,我拆解了新的引导加载程序来寻找与该漏洞相关的代码。
我发现该地址处的代码读取了存储在 R0 寄存器中的未知地址,并且攻击成功。我决定对其进行修改以匹配该漏洞。
标签模拟
由于我们可以编写自定义固件,我决定从模拟 NFC 标签开始。
这些芯片支持常见的 13. 协议,例如,并且在读取器模式下,可以支持基于这些标准的多种标签类型。我想完全模拟标签,所以我开始研究如何利用它。为此,我曾经启动调试过程。
为了将手机设置为在默认状态下作为标签运行,我重放了按顺序启动芯片的 NCI 命令。然后我逐一检查了这些命令,并删除了那些不影响 NFC 通信的命令。
我发现发送的最后一个命令是 RF 命令,我可以修改它以仅模拟标签而不是其他类型的标签。
硬件外设
我需要了解芯片硬件功能的复杂细节,因此我开始分析我使用的固件。我首先搜索命令 (0x93) 以查看它在哪里使用。第一个搜索结果提供了有关硬件的信息。
以 -M 开头的地址通常是芯片中的硬件外围设备,这意味着 0x93 的值正在从该内存空间的某个地方进行比较。使用我之前的任意读取命令,我一次转储了所有内存,因为这很可能是处理芯片上的 NFC 通信,并且每个硬件外围设备都是单独寻址的。
当手机作为 NFC 读取器查看这些地址时,它会显示 NFC WUPA (0x52) 命令,该命令用于枚举,这意味着这是用于通信的正确硬件地址。同时,较低的地址处还有一些配置数据。
要模拟不同的 NFC 标签,首先需要更改枚举信息。与 NFC 标签通信时,首先需要获取其类型的信息及其唯一标识符,通常由以下值组成:
ATQA:由 NCI 定义。
SAK:由 NCI 定义。
UID:由手机随机分配,第一个字节固定为0x08。
ATQA 和 SAK 值用于定义标签类型和 UID 大小。虽然这些值可以通过 NCI 设置,但设置特定的位可以防止特定标签类型的欺骗。
由于是用于枚举,所以相比普通通信会有一定的时间限制,所以很有可能会使用特殊的硬件寄存器来提高响应速度。
我通过 NCI 写入了非常容易识别的 ATQA 和 SAK 值,然后搜索 RAM。这样我就可以看到访问了哪些静态内存,并找到固件中设置这些值的函数。
我用自己的 C 函数覆盖了这个函数,然后从这个新创建的函数中调用它来完成其余的硬件设置,并根据我的要求修改 SAK、ATQA 和 UID 值。
我用它来读取使用这个自定义固件的手机并发现成功了。
接下来,我计划介绍芯片的全部通信功能。为此,我首先在固件中搜索 HALT (0x50) 和 RATS (0xE0) 命令,因为已知当前形式的固件支持这些命令。然后,为了进行比较,我搜索了 RATS 值并得到了四个结果,其中一个是固件中用于 NFC 通信的状态机。
从这个函数中,我找到了有关响应的信息,因此我可以编写 C 代码自己完成这件事。
我覆盖了状态机,以便可以添加自己的功能。
我实现了一个简单的读取命令,该命令适用于大多数标签,使用 0x30 作为命令值,后跟一个块,然后是 CRC。我这样做是为了给标签提供基本功能,以便将来可以扩展它。
此时,我已经完全实现了通信并准备修补代码。我还为 NFC 添加了一些调试功能。
不过我们还需要注意HALT命令,它可以对硬件状态机进行一些修改。为了简单起见,我调用了核心固件中处理的函数调用。
通过通信功能,我可以使用它来验证和读取块。
虽然这在 上有效,但在合法的读卡器上无效。这是因为与 的通信是加密的。
扩展硬件功能
根据协议,每传输 8 位,就会有一个额外的位用作错误检查的奇偶校验。根据设置的位数是奇数还是偶数,此位设置为 1 或 0。根据标准做法,芯片负责生成这个额外的位,并在响应中使用 8 位缓冲区。这有点问题,因为这个位在合法通信中是加密的。我想芯片的寄存器中可能有一个未知的配置来支持此功能,所以我开始寻找它。
我设置和取消设置了硬件寄存器前 64 个字节中的位,并评估了每个位对响应的影响。这种方法给了我一些有趣的结果:我发现在地址处,可以通过设置位来修改奇偶校验类型。
这样做的目的是设置第九位,但这意味着我必须将 9 个二进制数字放入 8 位空间。我通过移位数据解决了这个问题。
这样才能充分实现。
我为该固件添加的最后一个功能是转储写入。当通过 I2C 上传标签二进制文件时,我希望读取器能够修改它们,并且标签中的文件也会相应地更改。为此,我只需在每次执行写入时发送带有新数据的 I2C 响应即可。
为此,我创建了一个简单的演示,通过使用另一部手机读取 S9 来展示标签模拟的操作。
利用标签模拟技术,不仅可以伪造13.门禁卡,还可以发起其他攻击。需要注意的是,启用此补丁后,其他所有NFC功能仍可正常工作。
我觉得这个办法比专门的攻击工具更加巧妙,而且如果进行相应的扩展,比如增加离线破解功能,可以用来测试各种NFC协议。
我发现这种仿真技术不仅可以扩展到各种协议,而且通过特定的方式修改硬件寄存器,我可以进行一些简单的被动嗅探攻击。有了这个框架,我会进一步丰富它的具体功能。
概括
截至 2020 年 4 月,三星已修补上述所有漏洞。
利用此漏洞需要 root 访问权限。
手机应该被视为易受黑客攻击的嵌入式设备。
引导加载程序漏洞比你想象的更常见,尤其是在手机中。
为专有芯片开发定制固件具有挑战性,但也是很好的学习经历。
如果在旧芯片中发现未公开的漏洞,则很有可能在新芯片中也发现该漏洞。
该项目的所有代码可以在以下位置找到: