Skip to content

BootHole: GRUB2 config buffer overflow (CVE-2020-10713)

Unsigned bir grub.cfg, GRUB2'nin flex tarafından üretilmiş parser buffer'ını overflow eder ve UEFI Secure Boot'u aşan boot-time code execution verir.

Mechanism

Note

Secure Boot'un trust chain'i signed GRUB2 binary'sini (ve shim'ini) verify eder ama grub.cfg'yi — GRUB'un runtime'da EFI System Partition'dan okuduğu text configuration dosyasını — verify etmez. Örtük invariant şu: verify edilmiş, değiştirilemez bir bootloader, config "sadece data" olduğu için attacker tarafından değiştirilebilir bir config'i güvenle tüketebilir. BootHole bu invariant'ı kırar: config parser'ındaki bir memory-safety bug, data'yı code'a dönüştürür.

GRUB, grub.cfg'yi flex tarafından üretilen bir lexer ile tokenize eder. YY_DO_BEFORE_ACTION flex macro'su, fazla büyük bir token tespit edip YY_FATAL_ERROR() üzerinden abort etmek için tasarlanmıştır. Ancak GRUB2'de YY_FATAL_ERROR, halt etmek yerine yalnızca bir hata print eden ve return eden bir rutine bağlanmıştı. Bu yüzden execution yy_flex_strncpy()'a düşer; bu da fazla uzunluktaki token'ı çok küçük bir heap buffer'a kopyalar — komşu parser yapılarını bozan bir heap buffer overflow. GRUB, OS'tan ve ExitBootServices'ten önce çalıştığından, bu overflow'u kontrol etmek trusted boot ortamı içinde arbitrary code execution verir ve OS'un altında, çoğu endpoint savunmasının altında bir bootkit kalıcı kılar.

Walkthrough

Saldırganın EFI System Partition'a yazmak için administrative/root hakları (veya fiziksel erişim) gerekir. Payload, parser'ın buffer'ından daha uzun, crafted bir token'dır.

# Locate the GRUB config on the ESP (Linux example)
$ sudo mount | grep -i efi
/dev/sda1 on /boot/efi type vfat (rw,relatime,...)
$ ls /boot/efi/EFI/*/grub.cfg
/boot/efi/EFI/ubuntu/grub.cfg

Minimal bir trigger, lexer'ın sabit buffer'ını aşan bir token ekler:

# Conceptual PoC: a single absurdly long token in grub.cfg overruns the
# flex token buffer instead of being rejected.
$ python3 -c 'print("set x=" + "A"*0x10000)' | sudo tee -a /boot/efi/EFI/ubuntu/grub.cfg

Zafiyetli bir GRUB2'de, bu satırı parse etmek size check'inde durmaz:

Warning

Bug, fatal-error path'inin return etmesidir. Beklenen (güvenli) davranış anında bir abort'tur; gözlemlenen (zafiyetli) davranış ise yy_flex_strncpy()'nin buffer'ın ötesine kopyalayıp heap'i bozmasıdır. Güvenilir bir exploit, control flow'u yeniden yönlendirmek için heap'i şekillendirir ve parser state'ini overwrite eder.

# Vulnerable build: prints the error, then continues into the copy -> corruption
error: ... token too large ...
# (parser keeps running; heap state corrupted)

Signed GRUB binary'si değişmediğinden, Secure Boot onu yine de launch eder — zararlı config verification'dan sonra tüketilir, dolayısıyla signature check geçer.

Patch'lemek neden zahmetli (revocation problemi)

Kodu düzeltmek yeterli değil: daha önce signed her zafiyetli GRUB binary'si Secure Boot altında geçerli kalır ve yeniden tanıtılabilir. Tam remediation, zafiyetli bootloader'ları revoke etmek için UEFI dbx (forbidden-signature database)'i güncellemeyi gerektirdi; bu da dbx update'leri ve yeni shim'ler/bootloader'lar lockstep şekilde deploy edilmezse sistemleri brick'leme riski taşıyordu.

Detection

  • ESP'deki grub.cfg'yi beklenmedik değişiklikler ve anormal uzunlukta token / satırlar için integrity-monitor et.
  • UEFI dbx içeriğini denetle; zafiyetli GRUB/shim hash'lerinin revoke edildiğinden emin ol.
  • Measured Boot: değiştirilmiş bir boot path PCR değerlerini değiştirir, dolayısıyla TPM-based remote attestation, Secure Boot bypass edilse bile müdahale edilmiş configuration'ı tespit eder.

Mitigation

  • Fazla büyük token'larda abort eden ve parser'ı sertleştiren patch'li GRUB2 uygula.
  • Güncellenmiş, re-signed shim'leri/bootloader'ları deploy et ve zafiyetli signed binary'lere rollback'i önlemek için ilgili dbx revocation'larını birlikte push et.
  • Secure Boot signature kontrolünden bağımsız bir defense-in-depth sinyali olarak Measured Boot / TPM attestation kullan.

References