
Bootkit UEFI GRUB2 che installa un impianto di rete pre-avvio tramite l'opzione di avvio NVRAM, esegue il chainload di un UKI, lancia un payload dracut ed esegue il kexec del kernel stock.
slot2: un bootkit UEFI GRUB2 a due stadi che persiste un implant di rete pre-OS su Amazon Linux 2023 su AWS EC2 UEFI x86_64.
di cenobyte [email protected] 2026
https://github.com/cenobyte-vincit/slot2
slot2 è un bootkit per Amazon Linux 2023 su EC2. Il firmware UEFI di AWS EC2 lo carica per primo. Un implant incorporato viene eseguito nella UKI del bootkit (Unified Kernel Image: un singolo file EFI con un kernel del bootkit e initrd) prima che si avvii il sistema operativo originale, rete inclusa, poi viene usato kexec per avviare il kernel originale che avrebbe usato un boot normale. Il sistema operativo che si avvia è quello reale, originale.
La persistenza avviene tramite un'opzione di caricamento NVRAM UEFI e due file, un file ESP del bootkit e una UKI del bootkit; non viene usato/richiesto alcun helper/servizio rootkit in userspace, e non si tratta di un bootloader del fornitore sostituito. In slot2, 98-payload.sh è l'implant usato per C2/infil/exfil pre-boot e scritture arbitrarie su disco per inserire payload come RAT o rootkit basati su kernel sui filesystem del target. L'implant in questo albero è una dimostrazione: scrive /root/HELLO.TXT e attiva la rete per stabilire una connessione Internet/di rete, che in un'operazione potrebbe essere un'infil o exfil di rete.
Il firmware UEFI non sceglie un kernel da solo. Percorre un BootOrder di opzioni di caricamento NVRAM, ciascuna uno slot numerato (Boot0001, Boot0002, ...) che punta a un eseguibile EFI sulla ESP. Su EC2, Boot0001 è sempre presente: la voce Amazon EBS che avvia il \EFI\BOOT\BOOTX64.EFI originale. slot2 aggiunge Boot0002, che punta a un secondo file sulla stessa ESP, e mette Boot0002 per primo nel BootOrder. Il firmware mantiene comunque Boot0001 come fallback.
Quel secondo file deve essere qualcosa che il firmware possa eseguire, e deve raggiungere la UKI del bootkit sul filesystem root, che il firmware non può vedere. Si usa GRUB perché è in grado di leggere GPT e XFS, trovare la UKI e fare chainload. L'immagine è un grub2-mkimage personalizzato, non il GRUB Amazon pacchettizzato; il BOOTX64.EFI originale resta dove il fornitore l'ha messo. L'unico compito di GRUB qui è passare il controllo alla UKI.
Il kernel della UKI esegue poi 98-payload.sh, quindi 99-kexec-stock.sh usa kexec per avviare il kernel e l'initrd originali che avrebbe usato un boot BLS normale.
EC2 UEFI NVRAM
├── Boot0001 -> stock \EFI\BOOT\BOOTX64.EFI (untouched)
└── Boot0002 -> bootkit \EFI\BOOT\.BOOTX64.EFI (created; first on BootOrder)
|
v
ESP (VFAT) /boot/efi
└── /EFI/BOOT/
├── BOOTX64.EFI stock (untouched) <- Boot0001
└── .BOOTX64.EFI bootkit GRUB2 PE --chainload--+ <- Boot0002
|
root FS (XFS, typical AL2023) |
└── /var/lib/systemd/boot/ |
└── uki.efi <------------------------------------------+
|
| 98-payload.sh, then 99-kexec-stock.sh
| resolve stock target under /sysroot/boot/:
| loader/entries/*.conf (BLS + grubenv; AL2023 primary)
| grub2/grub.cfg (legacy fallback)
|
+-- kexec ----------------------------------------+
|
/boot (stock, untouched) |
├── vmlinuz-* <--------------------------------------------+
└── initramfs-*.img
|
+-- stock initrd -> stage-2 stock userspace
Se kexec fallisce, lo stage 1 continua sul kernel UKI. La macchina resta avviabile.
L'impianto è 98-payload.sh, un hook dracut pre-pivot all'interno dell'UKI del bootkit. Non è un servizio userspace post-avvio. L'implementazione in questo albero è una demo: rimonta /sysroot in lettura-scrittura, scrive /root/HELLO.TXT, attiva le NIC, DHCP, poi wget su ifconfig.me (budget di 5s). Il lease DHCP e il file resolver restano nell'initrd (/tmp/udhcpc.*.lease, /etc/resolv.conf); non vengono scritti sulla root reale. Un errore di rete non blocca kexec.
Lo stage 1 ha la root reale in /sysroot (tipicamente XFS, rimontata rw). /boot è /sysroot/boot. I volumi EBS aggiuntivi non vengono montati a meno che l'hook non li monti. L'initrd slim include udhcpc e wget di busybox. ip(8) è il binario della root reale, eseguito tramite il loader dell'initrd.
L'host di runtime è il target (l'istanza EC2 che esegue deploy e poi si riavvia nel bootkit).
uefi o uefi-preferred/boot/efi (l'automount di systemd va bene; deploy la attiverà)libefivar e libefiboot (deploy è linkato dinamicamente; entrambe sono incluse nel sistema operativo standard)ARM64 / Graviton non è testato e quindi non supportato (per ora?).
Amazon Linux 2023 x86_64.
./install-dependencies.sh/boot/vmlinuz-$(uname -r) e /boot/initramfs-$(uname -r).img del kernel in esecuzione (questi file vengono inseriti nell'UKI)cc, make, pkg-config, grub2-mkimage, objcopy, kexec, openssl, xxd./install-dependencies.sh è il bootstrap. Installa i pacchetti dnf sopra indicati (più grub2-efi-x64-modules, systemd-boot-unsigned, efivar-devel, dracut) e scarica i binari udhcpc e wget di busybox nella versione fissata.
Sull'host di build:
./install-dependencies.sh
make
Un semplice make scrive uki.efi, BOOTX64.EFI e deploy. Non scrive l'ESP, /var/lib/systemd/boot né la NVRAM. Il magic del trailer e SOURCE_DATE_EPOCH sono descritti in ARCHITECTURE.md.
Copia l'ELF deploy fornito sul target. Nessun compilatore. uki.efi e BOOTX64.EFI sono già all'interno del trailer.
scp deploy user@target-host:~/
Su un'istanza AL2023 con colocation la copia è opzionale; esegui ./deploy dall'albero di build.
Al riavvio successivo, il firmware Boot0002 carica l'ESP PE, il PE esegue il chainload dell'UKI, il payload viene eseguito, poi kexec avvia il kernel BLS stock (ARCHITECTURE.md). Se deploy stampa EFI variables are not supported on this system, questo avvio è in BIOS; vedi Requisiti.
deploy richiede i privilegi di root. Senza argomenti esegue il dump degli offset del trailer e della NVRAM e non scrive nulla. -y installa le immagini e la NVRAM, poi cancella e rimuove questo eseguibile. Qualsiasi altro argomento stampa le istruzioni d'uso.
./deploy # dump only: trailer offsets and NVRAM; no writes
./deploy -y # plant, then wipe and unlink this binary
reboot
Con un'esecuzione -y riuscita, il processo pianifica la cancellazione del proprio eseguibile (/dev/urandom, troncamento, unlink) dopo la sua uscita, quindi ls deploy dovrebbe fallire. L'UKI impiantato e l'immagine GRUB del bootkit restano.
-y scrive /var/lib/systemd/boot/uki.efi (root:root, 0500) e /boot/efi/EFI/BOOT/.BOOTX64.EFI (root:root, best-effort 0700 su VFAT), quindi crea la voce NVRAM Boot0002 e la mette per prima nel BootOrder. Il BOOTX64.EFI originale rimane Boot0001.
make
Questo compila i tre prodotti. Non esiste una suite di test nel repository. Un make eseguito sullo stesso host su un'istanza AL2023 che in seguito eseguirà ./deploy -y non costituisce una prova di runtime pulito.
Dopo il riavvio dovresti trovarti nello userspace stock di stage-2: il kernel, /proc/cmdline e il percorso dell'initrd che un normale avvio BLS avrebbe utilizzato.