当前位置:首页 >资讯 >如何攻击被加密的磁盘


最近,我们的研究人员讨论了对Linux系统完全加密的冷启动攻击。每个人都认为这种攻击是可行的,但执行这样的攻击有多困难?攻击的可行性是多少?

由于市场上没有现成的工具可以执行此攻击,我们制作了自己的工具,并将其命名为Evilabigail。Evilmaid攻击可以针对任何操作系统。本研究旨在使用LUKS完全加密的Linux系统。

一般来说,当Linux系统完全加密时,它将由一个小分区或不加密。该区域用于解密和引导加密磁盘。该分区将挂载在/boot中,包括内核和初始RAM磁盘(initrd)。虽然攻击核心或bootloader也是可行的,但我们仍然攻击initrd。

initrd是指在启动阶段被Linux内核调用的临时文件系统。initrd主要用于root文件系统挂载前的准备工作。initrd包括解密和挂载root文件系统所需的目录和可执行程序的最小集合。initrd任务一旦完成,就会执行pivot_rot,从而卸载initrd根文件系统,挂载真正的根文件系统。

一般来说,initrd是一过gzip压缩的cpio镜像。我们测试的基于debian的操作系统是这样的,但是基于redhat的操作系统(fedora、rhel、centos)现在使用dracut,包括未压缩的cpio镜像。基于debian的initrds将使用ashshell脚本启动,而dracut将使用systemd及其相关配置方法。

为了执行我们的攻击,我们选择使用基于LD_PRELOAD的bootkit,但也可以注入恶意核心或可执行文件。我们使用LD_PRELOAD的主要目标是在新解密的root文件系统中注入第一个可执行文件共享对象。第一个可执行文件通常是/sbin/init,PID通常是1。攻击最简单的方法就是修改init脚本,导出环境变量,这样在执行pivot时设置环境变量。因为当文件系统更改时,共享对象必须在正确的时间(解密后)复制到新系统中。将以下两行放入initrdinit脚本中,插入切换文件系统:

cp/hack.so/${rootmnt}/hack.so.

ExportLD_PRELOAD=/hack.so。

之所以这样可行,是因为真正的root文件系统是在临时root文件系统下解密挂载的,先于pivot,rootmnt变量填充在挂载点位置。然而,在此之前,有必要将目标文件系统重新挂载到读写中,因为默认情况下,只有读写。在我们的例子中,我们修改了init脚本,并修改了脚本分析的核心命令行的位置。因此,无论提供什么参数,root文件系统都以读写方式挂载。另一种方法是在注入命令中添加

mount-oremount,rw/${rootmnt}。

然而,基于dracut的initrds中没有注入点,因为init的可执行文件是二进制文件,而不是shell脚本。这给我们带来了三个问题。只有克服了这三个问题,我们才能注入pid1过程。

第一个问题是将我们的二进制文件复制到解密的root文件系统。这个问题是三个问题中最好的解决方案之一。我们可以向负责pivote文件系统的systemd服务文件添加两个execpre指令。这基本上相当于插入脚本的方法。第一个命令将通过读写重新登录root文件系统,第二个命令将执行复制操作。

第二个问题是关于LD_PRELOAD。因为我们不是在修改shell脚本,我们不能将环境变量传递给这个过程(因为它是由核心调用的),所以加载我们的共享对象有点困难。最简单的方法就是先把init二进制文件移到另一个位置,然后把自己的shell脚本插入原来的位置,最后执行原来的二进制文件。我们只需要两行代码。第一行导出LD_PRELOAD,第二行执行原始systemd二进制文件。请注意,initrd中的pid1过程是注入的,而不是最终root文件系统的pid1。

第三个问题是,在调用switch-root命令之前,systemd将使用clearenv()函数清除所有环境变量。因为这个函数是标准库的一部分,我们可以重写这个函数,这样注入的过程就可以调用我们的函数而不是原来的函数。我们不关心环境变量的真正清除。我们写的clearenv()函数将清除所有环境变量,然后将我们的ld_preload变量注入环境。因为clearenv()只会调用一次,我们的修改不会导致任何副作用。 在解决了上述三个问题后,我们的共享将被复制到加密的root文件系统中,我们的ld_preload将注入到目标文件系统的pid1过程中。接下来,我们可以获密用户密码。对于debian的initrds,执行文件将要求用户输入密码,然后解密并挂载root文件系统。我们可以在pipeline过程中注入脚本以获取密码。

至于systemd,它将通过Unixdomainsockets使用更复杂的过程间通信。我们选择攻击文件系统的挂载,而不是这个过程。这是另一个库函数。它在动态加载库中从systemd中调用,因此我们可以使用此函数。解密硬盘的函数称为crypt_activate_by_passphrase。该函数将密码作为char数组。我们可以通过hook获得密码。我们必须包裹原始函数,所以我们用dlsym打开真正的函数并呼叫它。但在此之前,我们将保存密码以便将来收回。

为了保存密码,我们只需将密码添加到root文件系统的共享对象中即可复制。我们选择这种方法是因为我们已经知道这个文件存在并将被复制。这种方法还将减少我们接触到的磁盘文件的数量。为了获取密码,我们将阅读自己文件的末尾(通过LD_PRELOAD变量定位),然后将其设置为我们反弹Shell中PASWORD环境变量的值,因此(以meterpreter为例)可以通过getenvpassword命令获得解密磁盘的密码。由于我们所有的目标主机都默认安装了python,我们使用pythonmerpreter反弹shell。

解决这个问题的方法有很多。然而,即使使用这些解决方案,如果攻击者能够物理接触计算机并有足够的时间重新刷BIOS/UEFI,他们也无法阻止。

第一种方法是将bootloader、内核和initrd放在外部U盘上,然后从U盘开始替换/boot分区。但这种方法对用户来说非常糟糕,因为当他们离开笔记本电脑时,他们应该记得拔出U盘。如果他们不卸载,他们应该安全卸载/boot分区。更新也很麻烦。您应该插入U盘以更新initrd/内核。

另一种方案是完全关闭外部媒体启动系统。这样,就不可能进行自动攻击,但在某些情况下,如果包括shell的debianinitrds,它仍然可以手动从initrd中挂载和修改initrd。这可以通过自动键盘设备完成,从而绕过外部媒体启动系统的限制。此外,BIOS启动密码也可以打开,这样没有密码的人就不能。