
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 rende persistente un impianto 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 impianto incorporato viene eseguito nella UKI del bootkit (Unified Kernel Image: un unico file EFI con kernel e initrd del bootkit) prima che il sistema operativo di serie si avvii, rete inclusa; poi kexec viene usato per avviare il kernel di serie che un avvio normale avrebbe usato. Il sistema operativo che si avvia è quello reale, di serie.
La persistenza avviene tramite un'opzione di avvio nella NVRAM UEFI e due file: un file ESP del bootkit e una UKI del bootkit; non viene usato/richiesto alcun servizio userspace di supporto/rootkit, né un bootloader del vendor sostituito. In slot2, 98-payload.sh è l'impianto usato per C2/infil/exfil pre-avvio e scritture arbitrarie su disco per inserire payload come RAT o rootkit basati su kernel nei filesystem del target. L'impianto 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 un'exfil di rete.
Il firmware UEFI non sceglie un kernel da solo. Scorre un BootOrder di opzioni di avvio in 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 la \EFI\BOOT\BOOTX64.EFI di serie. 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 di root, che il firmware non può vedere. Si usa GRUB perché sa leggere GPT e XFS, trovare la UKI e caricarla a catena. L'immagine è una grub2-mkimage personalizzata, non il GRUB Amazon impacchettato; la BOOTX64.EFI di serie resta dove l'ha messa il vendor. L'unico compito di GRUB qui è passare il controllo alla UKI.
Il kernel della UKI esegue quindi 98-payload.sh; poi 99-kexec-stock.sh usa kexec per avviare il kernel e l'initrd di serie che un avvio BLS normale avrebbe usato.
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 stadio 1 continua sul kernel della UKI. La macchina resta avviabile.
L'impianto è 98-payload.sh, un hook dracut pre-pivot dentro la 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 ifconfig.me (budget di 5s). Un fallimento di rete non blocca kexec.
Lo stadio 1 ha la root reale in /sysroot (tipicamente XFS, rimontata rw). /boot è /sysroot/boot. I volumi EBS extra non vengono montati a meno che l'hook non li monti. L'initrd minimale include busybox udhcpc e wget. 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 vengono fornite con il sistema operativo di serie)ARM64 / Graviton non è testato e quindi non supportato (ancora?).
Amazon Linux 2023 x86_64.
./install-dependencies.sh/boot/vmlinuz-$(uname -r) e /boot/initramfs-$(uname -r).img del kernel in esecuzione (quei file vengono impacchettati nella UKI)cc, make, pkg-config, grub2-mkimage, objcopy, kexec, openssl, xxd./install-dependencies.sh è il bootstrap. Installa i pacchetti dnf elencati sopra (più grub2-efi-x64-modules, systemd-boot-unsigned, efivar-devel, dracut) e scarica i binari busybox udhcpc e wget bloccati (pinned).
Sull'host di build:
./install-dependencies.sh
make
Un semplice make scrive uki.efi, BOOTX64.EFI e deploy. Non scrive la ESP, /var/lib/systemd/boot o la NVRAM. Il trailer magic e SOURCE_DATE_EPOCH sono in ARCHITECTURE.md.
Copia l'ELF deploy fornito sul target. Nessun compilatore. uki.efi e BOOTX64.EFI sono già dentro il trailer.
scp deploy user@target-host:~/
Su un'istanza AL2023 collocata la copia è opzionale; esegui ./deploy dall'albero di build.
Al riavvio successivo, il firmware, tramite Boot0002, carica la PE sulla ESP, la PE carica a catena la UKI, il payload viene eseguito, poi kexec avvia il kernel BLS di serie (ARCHITECTURE.md). Se deploy stampa EFI variables are not supported on this system, questo avvio è BIOS; vedi Requisiti.
deploy richiede root. Senza argomenti stampa gli offset del trailer e la NVRAM e non scrive nulla. -y installa le immagini e la NVRAM, poi azzera e scollega (unlink) questo eseguibile. Qualsiasi altro argomento stampa l'uso.
./deploy # dump only: trailer offsets and NVRAM; no writes
./deploy -y # plant, then wipe and unlink this binary
reboot
In un'esecuzione -y riuscita, il processo pianifica l'azzeramento del proprio eseguibile (/dev/urandom, truncate, unlink) dopo l'uscita, quindi ls deploy dovrebbe fallire. La UKI installata 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), poi crea Boot0002 nella NVRAM e lo mette per primo nel BootOrder. La BOOTX64.EFI di serie resta Boot0001.
make
Questo compila i tre prodotti. Non c'è una suite di test nell'albero. Eseguire un make su un'istanza AL2023 collocata, che in seguito eseguirà ./deploy -y, non è una prova di runtime pulito.
Dopo il riavvio dovresti essere nello userspace di serie di stadio 2: il kernel, /proc/cmdline e il percorso dell'initrd che un avvio BLS normale avrebbe usato.
cat /root/HELLO.TXT
# expect: stage-1 cmdline with BOOTKIT_MARKER, 98-payload.sh banner,
# pre-OS network breadcrumbs (NIC up, DHCP/udhcpc, default route),
# wget / external_ip=... / result, then
# 99-kexec-stock: resolve=bls:..., kexec -l ok, kexec -e
grep BOOTKIT_MARKER /proc/cmdline || echo "no marker (stage-2 ok)"
# expect: no marker
dmesg | head -3
# expect: stock-style cmdline (BLS options), not BOOTKIT_MARKER=1
uname -r
# expect: the dnf/grubby default on disk
deploy -y scrive i valori predefiniti sotto. BootOrder NVRAM e Boot0002 sono stato del firmware, non file.
Se cambi il nome della PE sulla ESP o il percorso della UKI, tieni in sincrono mk-bootx64-efi.sh, deploy.c e la voce NVRAM (vedi ARCHITECTURE.md).
amzn / 2023) e a un Boot0001 di tipo EC2. I controlli PE incorporati richiedono AMD64 (0x8664). ARM64 / Graviton non è (ancora?) supportato.open tramite un LKM rootkit è fuori scope per questo progetto.deploy è best-effort. Non è una cancellazione sicura su SSD o NVMe. Si consiglia un deploy personalizzato per una completa weaponizzazione e un maggior grado di OPSEC.c5a.xlarge e t3.nano.| Path | Ruolo |
|---|
/var/lib/systemd/boot/uki.efi | UKI di stadio 1 (kernel, initrd del bootkit, cmdline) |
/boot/efi/EFI/BOOT/.BOOTX64.EFI | PE GRUB2 del bootkit; il firmware Boot0002 carica questa |
/boot/efi/EFI/BOOT/BOOTX64.EFI | PE di serie (intoccata); fallback Boot0001 |
/boot/vmlinuz-*, /boot/initramfs-*.img, /boot/loader/entries/ | Kernel, initrd e BLS di serie; ciò che kexec carica |