该问题允许具有物理访问权限的攻击者绕过锁定屏幕保护(指纹、PIN 等)并获得对用户设备的完全访问权限。该漏洞被跟踪为CVE-2022-20465,它也可能影响其他 Android 供应商。

忘记我的 SIM PIN

我真的很高兴这个错误现在得到修复。这是我发现的最具影响力的漏洞,它越过了我的界限,我真的开始担心修复时间表,甚至只是将其作为一个“秘密”我自己。

我在旅行 24 小时后发现了这个错误。到家后,我的 Pixel 6 电池电量为 1%。它死时我正在发送一系列短信。我认为这是某种我无法正确完成的笑话,所以感觉很尴尬。我冲向充电器,重新启动了手机。

Pixel 启动并询问 SIM 的 PIN 码。我通常都知道,但这次我记错了。我希望我能弄明白,所以我尝试了一些组合,但最终我输入了 3 个错误的 PIN,并且 SIM 卡自己锁定了。它现在需要 PUK 码才能解锁并再次工作。

在进入我的壁橱并以某种方式找到 SIM 卡的原始包装后,我从背面刮掉并得到了 PUK 码。我在 Pixel 上输入了 PUK 码,它要求我设置一个新的 PIN。我做到了,成功完成此过程后,我最终进入了锁定屏幕。但有些事情不对劲:

这是一个全新的启动,而不是通常的锁定图标,指纹图标正在显示。它接受了我的手指,这不应该发生,因为重启后,您必须至少输入一次锁屏 PIN 或密码才能解密设备。

接受我的手指后,它卡在了一个奇怪的“Pixel is started…”消息上,一直呆在那里,直到我再次重新启动它。

我在心里注意到这很奇怪,而且这可能会带来一些安全隐患,所以我应该稍后再看。老实说,当我没有明确地寻找这种行为时,我真的不喜欢发现这样的行为,因为当这种情况发生时,我很容易感到对调查负责。我开始觉得我必须确保没有其他人错过的严重问题。在这种情况下,嗯,有。

刚刚发生了什么?

正如我向自己承诺的那样,第二天我又开始关注这种行为。重启手机后,输入错误的 PIN 3 次,输入 PUK 并选择一个新的 PIN 后,我进入了相同的“像素正在启动……”状态。

我多次玩过这个过程,有一次忘记重启手机,只是从正常的解锁状态开始,锁定设备,热插拔 SIM 卡托盘,然后进行 SIM PIN 重置过程。我什至没有意识到我在做什么。

和以前一样,我输入了 PUK 码并选择了一个新的 PIN。这次电话出了故障,我在我的个人主屏幕上。什么?以前是锁的吧?

这是令人不安的奇怪。我再次做到了。锁定手机,重新插入 SIM 卡托盘,重置 PIN 码……然后我又回到了主屏幕。什么?

我的手此时开始颤抖。什么他妈的?它解锁了自己?

在我稍微平静下来之后,我意识到这确实是一个该死的全锁屏绕过,在完全修补的 Pixel 6 上。我得到了我的旧 Pixel 5,并试图在那里重现这个错误。它也奏效了。

以下是实际的解锁过程:

由于攻击者可以携带他/她自己的 PIN 锁定 SIM 卡,因此除了物理访问之外不需要任何东西来利用。攻击者只需交换受害者设备中的 SIM 卡,并使用具有 PIN 锁且攻击者知道正确 PUK 码的 SIM 卡执行漏洞利用。

谷歌的回应

我把报告寄过去了。这是我认为我迄今为止最短的报告。只需要5个简单的步骤。

Google(更准确地说是Android VRP )在37 分钟内对内部错误进行了分类和提交。那真是令人印象深刻。不幸的是,在此之后,响应的质量和频率开始恶化。

在这个 bug 的生命周期中,由于官方的 bug 票不是太敏感,我有时会从谷歌员工那里得到一些半官方的信息。我实际上更喜欢只在官方频道上获得更新,这是我可以披露的错误票,但由于我正在与一些员工交谈,所以我收集了一些零碎的信息。

另外,值得一提的是,在报告之前,我检查了 Android VRP奖励表,该表指出,如果您报告会影响多个或所有 [Pixel] 设备的锁屏绕过,您可以获得最高 10 万美元的赏金。由于我勾选了所有必需的框,我有点认为这个错误很有可能实际获得 10 万美元的奖励。

在它被分类之后,基本上有一个月的沉默。我听说它实际上可能作为副本关闭。显然有人已经事先报告了,尽管实际上是我的报告让他们采取了行动。处理原始报告时似乎出了点问题。事实上,在报告 31 天后,我醒来时收到一封自动发送的电子邮件,上面写着“Android 安全团队认为这是另一个外部研究人员先前报告的问题的重复。” 这是一个标志性的漏洞赏金时刻,一个从 10 万美元到 0 美元的漏洞。我真的什么也做不了,只能接受这个错误现在是重复的并且不会支付的事实。

在我的报告之后已经过去了将近两个月,只有沉默。在第 59 天,我 ping 了票,要求更新状态。我收到了一个模板回复,说他们仍在努力修复。

快进到九月,也就是我的报告三个月后。我当时在伦敦,参加了Google 的名为 ESCAL8 的 bug 搜寻活动。2022 年 9 月的补丁刚刚发布,我更新了手机,在酒店房间的一晚,我试图重现该错误。我希望他们可能已经修好了。不,我仍然能够解锁手机。

这个酒店房间事件真的把我吓坏了。我觉得我比谷歌自己更担心和关心修复这个错误。不应该是这样。即使我反应过度。所以那天晚上,我开始联系与我们一起参加活动的其他 Google 员工。

第二天,我最终向多人解释了我的情况,我什至在谷歌办公室里用一些 Pixel 进行了现场演示。那是一种体验。我们没有 SIM 卡弹出工具。首先,我们尝试使用针头,但不知怎的,我设法在多处割伤了手指,手开始流血。我让一位 Google 工程师在我的手指上贴了一个创可贴。(还有谁可以这么说??)由于针不起作用,我们开始四处打听,一位非常善良的女士给了我们她的耳环试穿。有效!我们交换了 SIM 卡,并在遇到一些困难的情况下设法解锁了这些设备。现在我感觉好多了,人们似乎关心这个问题。

我将披露截止日期定为 10 月 15 日,但 Android VRP 团队回应称该漏洞不会在 10 月修补。他们的目标是十二月。考虑到影响,这对我来说似乎太过分了。我决定坚持 10 月份的最后期限。

在与一些 Google 员工讨论了这个 10 月的截止日期后,Android VRP 团队的一名成员亲自评论了这个 bug 票,并让我建立一个电话来讨论这个 bug,并分享反馈。我们与多人进行了一次见面电话,他们非常友善,听了我关于在黑暗中几个月的整个故事,只得到模板响应(即使是 10 万美元 -> 0 美元的重复),总体感觉就像我在乎比谷歌更多关于这个错误。他们说修复程序现在计划在 11 月发布,而不是 12 月。尽管如此,我的最后期限还是定在了 10 月。

通话两周后,我收到了一条新消息,证实了我所掌握的原始信息。他们说即使我的报告是重复的,只是因为我的报告,他们才开始着手修复。因此,他们决定破例,奖励 70,000 美元用于绕过锁屏。我还决定(甚至在赏金之前)我太害怕了,不敢真正推出实时错误,而且由于距离修复不到一个月,所以无论如何这并不值得。我决定等待修复。

总而言之,尽管这个错误一开始对我(黑客)来说并不是很好的体验,但在我开始大声“尖叫”之后,他们注意到了,并且真的想纠正哪里出了问题。希望他们也公平对待最初的记者。最后,我认为谷歌做得很好,尽管修复时间对我来说仍然很长。

但我会让你来评判它。

是什么导致了这个错误?

由于 Android 是开源的,因此通过所有代码更改修复此问题的提交是公开可见的:

提交消息的屏幕截图

当我第一次看到这个提交时,让我感到惊讶的第一件事是更改的文件数量。我以前认为这个错误只会有一个简单的单行修复,删除负责触发解锁的错误代码行。但事情并没有那么简单:

提交的更改文件部分的屏幕截图

在阅读了提交消息和代码更改之后,我想我能够大致了解幕后发生的事情。请记住,我不是 Android 工程师,所以我想保持这个高水平。

似乎,在 Android 上,有一个“安全屏幕”的概念。安全屏幕可以是多方面的。PIN 输入屏幕、指纹扫描屏幕、密码输入屏幕,或者在我们的例子中是 SIM PIN 和 SIM PUK 输入屏幕。

这些安全屏幕可以堆叠在彼此的“顶部”。例如,当手机被锁定并且 SIM PIN 条目可见时,它在“指纹安全屏幕”顶部有一个 SIM PIN 安全屏幕。

SIM PUK 重置成功后, PUK 重置组件调用.dismiss()“安全屏幕堆栈”上的一个函数,导致设备关闭当前的安全屏幕并显示堆栈中“下方”的安全屏幕。在我们的示例中,这是指纹安全屏幕。

由于该.dismiss()函数只是简单地关闭了当前的安全屏幕,因此很容易受到竞争条件的影响。想象一下,如果在 PUK 重置组件调用之前,后台的某些东西改变了当前的安全屏幕,会发生什么.dismiss()?PUK 组件在最终调用时会关闭不相关的安全屏幕.dismiss()吗?

这似乎正是发生的事情。系统的其他部分正在后台监控 SIM 卡的状态,当它检测到变化时,它会更新当前处于活动状态的安全屏幕。似乎这个背景组件将正常的指纹屏幕设置为活动的安全屏幕,甚至在 PUK 组件能够进行自己的.dismiss()函数调用之前。当 PUK 组件调用.dismiss()函数时,它实际上关闭了指纹安全屏幕,而不是像最初打算的那样仅仅关闭 PUK 安全屏幕。在指纹安全屏幕上调用.dismiss()会导致手机解锁。

Android 工程师似乎决定重构该.dismiss()函数并使其需要一个额外的参数,调用者可以在其中指定要关闭的安全屏幕类型。在我们的例子中,PUK 组件现在显式调用.dismiss(SecurityMode.SimPuk), 以仅关闭类型为SimPuk. 如果当前活动的安全屏幕不是SimPuk屏幕(因为可能某些背景组件改变了它,就像在我们的例子中一样),则关闭函数不会做任何事情。

在我看来,这似乎是一个非常优雅和强大的解决方案,可以抵御这种情况以及未来的竞争条件。我没想到这个错误会在 Android 中引起如此大的代码更改。