前言
如果大家不懂F00D是什么,我可以做个简单介绍,一句话,F00D是一个处理器专门处理和保存密钥。如果你感兴趣,想要详细了解35C3大会的一篇访谈文章。读完这篇文章,你将学会一个技能,即如何利用F00D加密处理器中所出现的漏洞。在我们深入研究之前,我将解释F00D的一些基本工作原理。
模拟密钥派生
PlayStation®VITA是索尼的一代掌机,简称PSV,今天我们就以它为例进行说明。在PSV上,加密处理的设备有两个,并且,这两个设备所执行的功能基本上是相同的。 “DMAC5”就是其中一种设备,它可以对ARM内核执行各种加密操作,例如:
1.对存储卡进行加密或解密;
2.对连续内存分配器(CMA)PC备份进行加密或解密;
3.对PFS(完全前向保密)进行加密或解密,PFS(perfect forward secrecy),中文可叫做完全前向保密。要求一个密钥只能访问由它所保护的数据;用来产生密钥的元素一次一换,不能再产生其他的密钥;一个密钥被破解,并不影响其他密钥的安全性。
4.对内核核心转储(coredump)进行加密;
……
DMAC5设备由两大部分组成:加密设备本身和与之相关的密钥环。密钥环包含0x20个大小为0x20字节的插槽。默认情况下,F00D都会自带密钥环,其中有几个插槽是直接连着ARM的。然后,DMAC5可以通过在执行加密操作时指定一个密钥槽来使用此密钥环。
PSV上除了DMAC5之外,还有另一个功能相同的加密设备,我们称之为“Bigmac”,因为它只能由“F00D”处理器访问。 虽然Bigmac和DMAC5的界面几乎相同,但Bigmac只能通过F00D访问。
就像DMAC5一样,Bigmac也有一个相关的密钥环,功能和DMAC5大致相同,不过Bigmac的密钥环有0x800个0x20字节的插槽,并且你可以为每个插槽设置特定功能。这些功能通常包括:
1.指定用哪种算法(AES,HMAC,CMAC等)访问它;
2.指定用哪种算法模式(加密,解密或两者兼有);
3.是将输出结果写入内存还是仅写入特定的插槽;
4.是否可以写入;
不过大多数插槽没有权限,无法使用。另外,对于存放主密钥的密钥槽来说,是不允许进行覆盖的;而对于其他槽来说,经过一定的配置,则可用于加密。
Bigmac的关键用途之一就是“派生”密钥,也就是说,Bigmac会将一个加密的密钥“解密”到一个密钥槽中。利用这个原理,索尼既可以更新各种重要的密钥,同时,也不用担心将其暴露在明文中了。这意味着,获得这些派生密钥的唯一方法就是破坏用于解密这些密钥的主密钥,或以某种方式读出密钥槽。
在此,让我们先了解一下使用Bigmac进行解密的传统做法。其中,关键的是以下4个方面:
1.找到我们要解密的数据源;
2.确定数据所在的目标地址,如RAM地址或密钥槽编号;
3. AES密钥存放在哪个密钥槽里;
4.搞清要解密的数据大小;
按着以上的提示,如果要在正常情况下解密密钥,我们首先需要一个经过加密的密钥,然后将目标地址指向一个密钥槽,并将其大小设置为0x10字节。所以要提取密钥,我们的第一选择就是修改目标地址,将其存储在内存地址中。但这一做法显然无法实现,因为用于派生密钥的所有密钥槽,都被明令禁止在目标地址未指向密钥槽的情况下进行使用。
所以我的另一个思路就是尝试改变要解密的数据大小。有趣的是,使用不是分组密码倍数的大小似乎有效。在标准AES中,你需要提供的数据的大小必须是密码块大小的倍数,本文用的是0x10。因此,通常可以假设它们会使用填充模式来处理不可分割的块大小,同时,Bigmac的输出结果与输入的大小是一致的。
经过一番测试,我发现Bigmac可以接受的数据块大小是4个字节的倍数。当执行4字节数据块的解密时,我注意到每次调用引擎时返回的明文都不同。当解密的大小大于0x10字节时,却没有观察到此种现象,这意味着我们输入的部分字节与前面计算的结果混合在了一起。
然后我们可以尝试根据此属性,进行提取密钥的测试。让我们假设Bigmac正在对一些残留数据进行简单的复制。当我们提供4个字节的数据00 00 00 00时,解密过程如下图所示。
Bigmac缓冲区中的残留数据来自之前返回的结果
这样,我们就知道00 00 00 00是用前一个操作中的残留数据来进行加密的。接下来的问题就是,弄清楚残留的数据是什么?为此我们需要使Bigmac内部缓冲区进入已知状态,我们可以使用由0组成的密钥来解密一个完全由0组成的数据块,这样我们就能同时知晓明文、密文和密钥了。
解密00,用已知的明文和密文填充Bigmac缓冲区
为了确定Bigmac没有清除它的内部缓冲区,我们现在可以通过使用0密钥块解密4字节的00 00 00 00来确认这一点。
Bigmac缓冲区包含上次操作的残留数据
正如以上我所设想的那样,当传入的数据小于加密块时,Bigmac只是一味地往里复制数据,而不会清除其内部缓冲区。而往里复制的数据大小,则完全取决于我们输入的大小。
提取过程
在搞清楚了密钥存储原理后,就是利用其中的漏洞来进行攻击了。不过先别急,在进行正式攻击之前,让我们来模拟一次密钥派生过程。假设有一个密钥:00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D0E 0F,它是以某种加密形式进行存储的,并且加密密钥是未知的。假设我们需要将这个加密密钥解密到某个密钥槽中。这样的话,Bigmac的内部缓冲区中就会包含相应的解密的密钥。如果我们要求Bigmac使用全部是0的密钥块来解密长4字节的数据00 00 00 00,则会发生如下过程。
部分覆盖可以降低暴力破解密钥数据的难度
大家可以看到,当前内部缓冲区中,解密后的数据为00 00 00 00 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F,由4字节的全部是0的数据块和后面的密钥数据组成。要注意的是,即使原始密钥派生必须将结果存储到密钥槽中,我们也不会受到部分解密的限制。这使我们能够控制密钥、观察密文和部分控制明文。
由于此数据的4个字节为零,我们可以使用2 ^ 96次而不是2^128次,就能暴力破译就能破解剩余的数据。虽然这是一个巨大的进步,但还是不够理想。
为了解决这个问题,我们需要继续重复上面的过程。不过,这次不是写入4字节的全0值,而是写入12字节的全0值。这样,我们就可以使用2 ^ 32次就能暴力破译就能破解剩余的数据,以现在的PC计算能力,这个工作量,可以在几分钟内轻松完成。
部分写入会导致4字节的密钥数据保留在Bigmac缓冲区中
接着,我们可以使用8字节的全0值来重复上面的过程,不过现在,我们可以借助于从12字节的全0值这一步所获得的已知值来确定密钥的另外4个字节。
现在,我们可以重新使用之前的使用4字节的全0值所获得的值,并使用暴力破解出来的值来确定另外4个字节。
部分覆盖允许我们获得另外32位的密钥数据块
现在在经过3 * 2 ^32次尝试后,终于可以暴力破解出了我们所模拟派生的96位密钥。不过要获得密钥的最后32位,最简单的方法就是使用完整密钥来解密或加密某些选定的明文。然后,通过尝试解密或加密明文来暴力破解最后32位,直到获得预期的密文。
至此,128为模拟的派生密钥全部被解密。
总结
在进行暴力破解时,可能会出现碰撞现象,不过这属于正常现象。
不过,本文所描述的这种密钥提取方法无法用于提取“主密钥”。因为,主密钥位于一个密钥槽中,并且该密钥槽已经被锁定,所以无法进行覆盖。所以,该方法仅适用于在Bigmac设备中进行加密或解密数据。
此类派生的示例是F00D加载器的AA密钥,这个密钥是通过使用主密钥(插槽0x208)将标头的一部分解密到另一个槽(例如0xA)而得到的。这意味着如果索尼更改了AA密钥,我们可以通过设置故障来执行bootrom代码并执行此攻击来获得新密钥。而此方法只在bootrom中有效,因为索尼在引导之后禁用0x208主密钥。
应该说这是一个有趣的漏洞,不过可以通过禁止向加密设备输入非对齐数据来进行提前预防。另一个简单的解决方案就是在加密操作结束时清除内部缓冲区。由于此漏洞存在于在硬件中,攻击者总能够利用它来获取派生密钥。这样的话,系统中唯一可用于加密或解密的安全部分就只剩主密钥了。
本文翻译自:https://www.lolhax.org/2019/01/02/extracting-keys-f00d-crumbs-raccoon-exploit/
翻译作者:lucywang 原文地址:http://www.4hou.com/technology/16200.html