
Буткит UEFI GRUB2, который устанавливает предзагрузочный сетевой имплант через загрузочный параметр NVRAM, выполняет цепочную загрузку UKI, запускает пэйлоад dracut и выполняет kexec штатного ядра.
slot2 — это двухстадийный UEFI GRUB2 буткит, обеспечивающий постоянство сетевого импланта, работающего до загрузки ОС, на Amazon Linux 2023 в AWS EC2 UEFI x86_64.
автор: cenobyte [email protected] 2026
https://github.com/cenobyte-vincit/slot2
slot2 — это буткит для Amazon Linux 2023 на EC2. Прошивка UEFI AWS EC2 загружает его первой. Встроенный имплант выполняется в UKI буткита (Unified Kernel Image: единый EFI-файл с ядром буткита и initrd) до загрузки штатной ОС, включая сеть, а затем с помощью kexec запускается штатное ядро, которое использовалось бы при обычной загрузке. Поднимается настоящая, штатная операционная система.
Постоянство обеспечивается через UEFI NVRAM load option и два файла: ESP-файл буткита и UKI буткита; не используется и не требуется вспомогательный пользовательский сервис/руткит, и это не заменённый вендорский загрузчик. В slot2 98-payload.sh — имплант, используемый для C2 до загрузки, инфильтрации/экфильтрации и произвольной записи на диск с целью внедрения полезной нагрузки (например, RAT или руткитов на основе ядра) в файловые системы цели. Имплант в этом дереве — демонстрация: он записывает /root/HELLO.TXT и поднимает сеть для установления интернет/сетевого соединения, которое в реальной операции могло бы быть сетевой инфильтрацией или экфильтрацией.
Прошивка UEFI не выбирает ядро сама. Она перебирает BootOrder из NVRAM load options; каждая запись — пронумерованный слот (Boot0001, Boot0002, ...), указывающий на один EFI-исполняемый файл на ESP. На EC2 Boot0001 присутствует всегда: это запись Amazon EBS, запускающая штатный \EFI\BOOT\BOOTX64.EFI. slot2 добавляет Boot0002, указывающий на второй файл на той же ESP, и ставит Boot0002 первым в BootOrder. Прошивка по-прежнему использует Boot0001 как запасной вариант.
Этот второй файл должен быть чем-то, что прошивка может выполнить, и должен добраться до UKI буткита в корневой файловой системе, которую прошивка не видит. Используется GRUB, потому что он умеет читать GPT и XFS, находить UKI и выполнять цепочную загрузку (chainload). Образ создаётся через grub2-mkimage, это не пакетный Amazon GRUB; штатный BOOTX64.EFI остаётся там, где его разместил вендор. Единственная задача GRUB здесь — передать управление UKI.
Затем ядро UKI запускает 98-payload.sh, после чего 99-kexec-stock.sh с помощью kexec запускает штатное ядро и initrd, которые использовала бы обычная загрузка BLS.
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
Если kexec завершится неудачей, этап 1 продолжит работу на ядре UKI. Машина остаётся загружаемой.
Имплант — это 98-payload.sh, dracut hook из фазы pre-pivot внутри UKI буткита. Это не пользовательский сервис, запускаемый после загрузки. Реализация в этом дереве — демонстрация: перемонтировать /sysroot в режим чтения-записи, записать /root/HELLO.TXT, поднять сетевые интерфейсы, DHCP, затем wget ifconfig.me (бюджет 5 секунд). Сбой сети не блокирует kexec.
На этапе 1 настоящий корень находится в /sysroot (обычно XFS, перемонтируется в rw). /boot — это /sysroot/boot. Дополнительные тома EBS не монтируются, если их не смонтирует сам хук. В минимальный initrd включены busybox udhcpc и wget. ip(8) — это бинарник из настоящего корня, запускаемый через загрузчик initrd.
Хост выполнения — это целевая система (экземпляр EC2, на котором запускается deploy, а затем он перезагружается в буткит).
uefi или uefi-preferred/boot/efi (автомонтирование через systemd подойдёт; deploy сам его вызовет)libefivar и libefiboot (deploy слинкован динамически; обе библиотеки входят в штатную ОС)ARM64 / Graviton не тестировались и поэтому не поддерживаются (пока?).
Amazon Linux 2023 x86_64.
./install-dependencies.sh/boot/vmlinuz-$(uname -r) и /boot/initramfs-$(uname -r).img текущего ядра (эти файлы упаковываются в UKI)cc, make, pkg-config, grub2-mkimage, objcopy, kexec, openssl, xxd./install-dependencies.sh — это начальная настройка. Он устанавливает перечисленные выше пакеты dnf (плюс grub2-efi-x64-modules, systemd-boot-unsigned, efivar-devel, dracut) и загружает зафиксированные бинарники busybox udhcpc и wget.
На сборочном хосте:
./install-dependencies.sh
make
Простой make создаёт uki.efi, BOOTX64.EFI и deploy. Он не записывает ни ESP, ни /var/lib/systemd/boot, ни NVRAM. Магическое значение trailer и SOURCE_DATE_EPOCH описаны в ARCHITECTURE.md.
Скопируйте поставляемый ELF deploy на целевую систему. Компилятор не нужен. uki.efi и BOOTX64.EFI уже находятся внутри trailer.
scp deploy user@target-host:~/
На том же экземпляре AL2023 копирование необязательно; запустите ./deploy из дерева сборки.
При следующей перезагрузке прошивка Boot0002 загружает PE с ESP, PE выполняет цепочную загрузку UKI, запускается полезная нагрузка, затем kexec запускает штатное ядро BLS (ARCHITECTURE.md). Если deploy выводит EFI variables are not supported on this system, текущая загрузка — BIOS; см. Требования.
deploy требует прав root. Без аргументов он выводит смещения trailer и NVRAM и ничего не записывает. -y устанавливает образы и NVRAM, затем затирает и удаляет этот исполняемый файл. Любой другой аргумент выводит справку по использованию.
./deploy # dump only: trailer offsets and NVRAM; no writes
./deploy -y # plant, then wipe and unlink this binary
reboot
При успешном запуске с -y процесс планирует затирание собственного исполняемого файла (/dev/urandom, truncate, unlink) после своего завершения, поэтому ls deploy должен завершиться ошибкой. Установленные UKI и GRUB-образ буткита остаются.
-y записывает /var/lib/systemd/boot/uki.efi (root:root, 0500) и /boot/efi/EFI/BOOT/.BOOTX64.EFI (root:root, по возможности 0700 на VFAT), затем создаёт запись NVRAM Boot0002 и ставит её первой в BootOrder. Штатный BOOTX64.EFI остаётся Boot0001.
make
Эта команда собирает три продукта. В дереве нет набора тестов. make на том же экземпляре AL2023, где позже будет запущен ./deploy -y, не является доказательством чистой работы в рантайме.
После перезагрузки вы должны оказаться в штатном пользовательском пространстве этапа 2: ядро, /proc/cmdline и путь initrd, которые использовала бы обычная загрузка BLS.
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 записывает указанные ниже пути по умолчанию. NVRAM BootOrder и Boot0002 — это состояние прошивки, а не файлы.
Если вы меняете имя PE на ESP или путь к UKI, держите mk-bootx64-efi.sh, deploy.c и запись NVRAM синхронизированными (см. ARCHITECTURE.md).
amzn / 2023) и Boot0001 в стиле EC2. Встроенные проверки PE требуют AMD64 (0x8664). ARM64 / Graviton (пока?) не поддерживается.open с помощью руткит-LKM выходит за рамки этого проекта.deploy — best-effort. Это не безопасное стирание на SSD или NVMe. Для полноценного боевого применения и более высокой степени OPSEC рекомендуется собственный deploy.c5a.xlarge и t3.nano.| Путь | Роль |
|---|
/var/lib/systemd/boot/uki.efi | UKI этапа 1 (ядро, initrd буткита, cmdline) |
/boot/efi/EFI/BOOT/.BOOTX64.EFI | GRUB2 PE буткита; его загружает прошивка Boot0002 |
/boot/efi/EFI/BOOT/BOOTX64.EFI | Штатный PE (не тронут); запасной Boot0001 |
/boot/vmlinuz-*, /boot/initramfs-*.img, /boot/loader/entries/ | Штатное ядро, initrd и BLS; то, что загружает kexec |