
UEFI GRUB2 ブートキット。NVRAM ブートオプションを介してプリブートのネットワークインプラントをインストールし、UKI をチェーンロードし、dracut ペイロードを実行し、ストックカーネルを kexec します。
slot2: Amazon Linux 2023 on AWS EC2 UEFI x86_64 上で、OS 起動前のネットワーク化されたインプラントを永続化する、2 段階の UEFI GRUB2 ブートキット。
by cenobyte [email protected] 2026
https://github.com/cenobyte-vincit/slot2
slot2 は EC2 上の Amazon Linux 2023 向けのブートキットである。AWS EC2 の UEFI ファームウェアがこれを最初にロードする。組み込まれたインプラントは、ブートキット UKI(Unified Kernel Image: ブートキットのカーネルと initrd を 1 つの EFI ファイルにまとめたもの)内で、ネットワークを含めて、標準 OS が起動する前に実行され、その後 kexec を使って、通常の起動で使われたはずの標準カーネルを起動する。起動してくるオペレーティングシステムは、本物の標準のものである。
永続化は UEFI NVRAM のロードオプションと 2 つのファイル、すなわちブートキットの ESP ファイルとブートキット UKI によって行われる。ユーザー空間のヘルパーやルートキットサービスは使用せず、また必要とせず、ベンダーのブートローダーを置き換えたものでもない。slot2 では、98-payload.sh が、起動前の C2/侵入/持ち出し、および標的のファイルシステム上に RAT やカーネルベースのルートキットなどのペイロードを挿入するための任意のディスク書き込みに使用されるインプラントである。このツリー内のインプラントはデモンストレーションであり、/root/HELLO.TXT を書き込み、ネットワークを立ち上げてインターネット/ネットワーク接続を確立する。実際の作戦では、これがネットワーク経由の侵入や持ち出しになり得る。
UEFI ファームウェアはカーネルを自ら選択するわけではない。NVRAM のロードオプションの BootOrder をたどる。各ロードオプションは番号付きのスロット(Boot0001、Boot0002、…)であり、ESP 上の 1 つの EFI 実行ファイルを指す。EC2 では Boot0001 が常に存在する。これは標準の \EFI\BOOT\BOOTX64.EFI を起動する Amazon EBS のエントリである。slot2 は Boot0002 を追加し、同じ ESP 上の 2 つ目のファイルを指すようにして、BootOrder の先頭に Boot0002 を置く。ファームウェアは依然として Boot0001 をフォールバックとして持つ。
その 2 つ目のファイルは、ファームウェアが実行できるものでなければならず、かつファームウェアからは見えないルートファイルシステム上のブートキット UKI に到達できなければならない。GRUB が使われるのは、GPT と XFS を読み取り、UKI を見つけ、それをチェーンロードできるからである。このイメージはカスタムの grub2-mkimage であり、パッケージ版の Amazon GRUB ではない。標準の BOOTX64.EFI はベンダーが置いた場所にそのまま残る。ここでの GRUB の唯一の役割は、UKI に処理を引き渡すことである。
その後、UKI のカーネルが 98-payload.sh を実行し、続いて 99-kexec-stock.sh が kexec を使って、通常の BLS 起動で使われたはずの標準カーネルと initrd を起動する。
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 であり、ブートキット UKI 内の dracut pre-pivot フックです。これは起動後のユーザー空間サービスではありません。このツリーの実装はデモです: /sysroot を読み書き可能で再マウントし、/root/HELLO.TXT を書き込み、NIC を起動し、DHCP を実行し、その後 wget で ifconfig.me にアクセスします(5秒の予算)。DHCP リースとリゾルバファイルは initrd 内に留まります(/tmp/udhcpc.*.lease、/etc/resolv.conf)。これらは実際のルートには書き込まれません。ネットワーク障害は kexec をブロックしません。
ステージ1では実際のルートが /sysroot にあります(通常は XFS、rw で再マウント)。/boot は /sysroot/boot です。追加の EBS ボリュームは、フックがマウントしない限りマウントされません。スリムな initrd には busybox の udhcpc と wget が含まれています。ip(8) は実際のルートのバイナリであり、initrd ローダー経由で実行されます。
ランタイムホストはターゲットです(deploy を実行し、その後ブートキットで再起動する EC2 インスタンス)。
uefi または uefi-preferred の UEFI をサポートする EC2 インスタンス/boot/efi にマウントされている(systemd automount で問題ありません。deploy がトリガーします)libefivar と libefiboot(deploy は動的リンクされており、両方とも標準 OS に含まれています)ARM64 / Graviton はテストされていないため、サポートされていません(まだ?)。
Amazon Linux 2023 x86_64。
./install-dependencies.sh のための root/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 には書き込みません。トレーラーマジックと SOURCE_DATE_EPOCH については ARCHITECTURE.md に記載されています。
同梱の deploy ELF をターゲットにコピーします。コンパイラは不要です。uki.efi と BOOTX64.EFI はすでにトレーラー内に含まれています。
scp deploy user@target-host:~/
コロケートされた AL2023 インスタンスではコピーは任意です。ビルドツリーから ./deploy を実行してください。
次回の再起動時に、ファームウェアの Boot0002 が ESP PE をロードし、PE が UKI をチェーンロードし、ペイロードが実行され、その後 kexec がストックの BLS カーネルを起動します(ARCHITECTURE.md)。deploy が EFI variables are not supported on this system と出力する場合、このブートは BIOS です。Requirements を参照してください。
deploy には root 権限が必要です。引数なしで実行すると、トレーラーのオフセットと 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、VFAT 上でベストエフォートの 0700)を書き込み、その後 NVRAM Boot0002 を作成して BootOrder の先頭に配置します。既存の BOOTX64.EFI は Boot0001 のまま残ります。
make
これにより3つの製品がビルドされます。ツリー内テストスイートはありません。後で ./deploy -y を実行する AL2023 インスタンス上での同一場所での make は、クリーンなランタイムの証明にはなりません。
再起動後は、通常の BLS ブートで使用されるはずだったカーネル、/proc/cmdline、initrd パスを備えた stage-2 のストックユーザースペースに入っているはずです。
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 はファームウェアの状態であり、ファイルではありません。
| パス | 役割 |
|---|---|
/var/lib/systemd/boot/uki.efi | ステージ1 UKI(カーネル、ブートキット 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 がロードするもの |
ESP の PE 名や UKI のパスを変更する場合は、mk-bootx64-efi.sh、deploy.c、NVRAM エントリを同期させてください(ARCHITECTURE.md を参照)。
amzn / 2023)と EC2 形式の Boot0001 を前提条件としています。埋め込み PE のチェックには AMD64(0x8664)が必要です。ARM64 / Graviton は(まだ?)サポートされていません。open のフィルタリングは、このプロジェクトの対象外です。deploy の自己ワイプはベストエフォートです。SSD や NVMe でのセキュア消去ではありません。完全な武器化とより高い OPSEC のためには、カスタムの deploy を推奨します。c5a.xlarge と t3.nano で開発および検証済みです。