mirror of
https://github.com/BenjiTrapp/transportable-detonation-chamber
synced 2026-08-09 12:01:14 +00:00
235 lines
7.7 KiB
Ruby
235 lines
7.7 KiB
Ruby
# -*- mode: ruby -*-
|
|
# vi: set ft=ruby :
|
|
|
|
# Transportable Detonation Chamber - macOS Apple Silicon (QEMU/HVF)
|
|
# Windows 11 ARM VM with Detonator + DetonatorAgent + Fibratus + Rustinel + LitterBox
|
|
#
|
|
# This Vagrantfile targets macOS hosts with Apple Silicon (M1/M2/M3/M4)
|
|
# using the vagrant-qemu provider and a Windows 11 ARM64 guest.
|
|
#
|
|
# Prerequisites:
|
|
# Run the automated setup script:
|
|
# ./scripts/check-prerequisites.sh --fix
|
|
#
|
|
# Or manually install:
|
|
# 1. Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
|
# 2. QEMU: brew install qemu
|
|
# 3. swtpm: brew install swtpm (for TPM 2.0 emulation)
|
|
# 4. Vagrant: brew install --cask vagrant
|
|
# 5. Plugin: vagrant plugin install vagrant-qemu
|
|
# 6. Box: ./scripts/build-box-macos.sh (builds win11-arm box from ISO)
|
|
#
|
|
# Usage:
|
|
# make up # or: VAGRANT_VAGRANTFILE=Vagrantfile.utm vagrant up --provider=qemu
|
|
# make rdp # Connect via RDP
|
|
# make status # Check services
|
|
# make halt # Stop the VM
|
|
# make destroy # Delete the VM
|
|
|
|
# --- Helper: Locate EFI firmware ---
|
|
# Homebrew on Apple Silicon installs to /opt/homebrew, Intel to /usr/local
|
|
def find_efi_firmware
|
|
candidates = [
|
|
"/opt/homebrew/share/qemu/edk2-aarch64-code.fd",
|
|
"/usr/local/share/qemu/edk2-aarch64-code.fd",
|
|
"#{ENV['HOMEBREW_PREFIX']}/share/qemu/edk2-aarch64-code.fd",
|
|
].compact
|
|
|
|
candidates.each do |path|
|
|
return path if File.exist?(path)
|
|
end
|
|
|
|
# Fallback: try to find via brew
|
|
brew_prefix = `brew --prefix 2>/dev/null`.strip rescue "/opt/homebrew"
|
|
efi = "#{brew_prefix}/share/qemu/edk2-aarch64-code.fd"
|
|
return efi if File.exist?(efi)
|
|
|
|
abort <<~ERR
|
|
ERROR: EFI firmware not found. Searched:
|
|
#{candidates.join("\n ")}
|
|
|
|
Install QEMU via Homebrew:
|
|
brew install qemu
|
|
ERR
|
|
end
|
|
|
|
# --- Helper: Locate or create EFI vars file ---
|
|
def ensure_efi_vars(vagrant_dir)
|
|
vars_file = File.join(vagrant_dir, "efivars.fd")
|
|
unless File.exist?(vars_file)
|
|
# Create a 64MB empty file for EFI variable storage
|
|
File.open(vars_file, "wb") { |f| f.write("\x00" * (64 * 1024 * 1024)) }
|
|
end
|
|
vars_file
|
|
end
|
|
|
|
# --- Helper: Set up TPM socket ---
|
|
def tpm_socket_path(vagrant_dir)
|
|
File.join(vagrant_dir, "tpm")
|
|
end
|
|
|
|
EFI_CODE = find_efi_firmware
|
|
|
|
Vagrant.configure("2") do |config|
|
|
# Windows 11 ARM64 box - built by scripts/build-box-macos.sh
|
|
config.vm.box = "win11-arm"
|
|
config.vm.hostname = "detonation-chamber"
|
|
|
|
# Communicator: WinRM over HTTP (port 5985)
|
|
config.vm.communicator = "winrm"
|
|
config.winrm.username = "vagrant"
|
|
config.winrm.password = "vagrant"
|
|
config.winrm.timeout = 1800
|
|
config.winrm.retry_limit = 30
|
|
config.winrm.transport = :plaintext
|
|
config.winrm.basic_auth_only = true
|
|
|
|
# Network: expose service ports
|
|
# Note: vagrant-qemu translates these to QEMU hostfwd rules automatically
|
|
config.vm.network "forwarded_port", guest: 5985, host: 55985, id: "winrm", auto_correct: true
|
|
config.vm.network "forwarded_port", guest: 5000, host: 5000 # Detonator Web UI
|
|
config.vm.network "forwarded_port", guest: 8000, host: 8000 # Detonator REST API
|
|
config.vm.network "forwarded_port", guest: 8080, host: 8080 # DetonatorAgent API
|
|
config.vm.network "forwarded_port", guest: 1337, host: 1337 # LitterBox Web UI
|
|
config.vm.network "forwarded_port", guest: 9000, host: 9000 # Unified Web UI
|
|
config.vm.network "forwarded_port", guest: 8888, host: 8888 # theZoo-WebUI
|
|
config.vm.network "forwarded_port", guest: 3389, host: 53389 # RDP
|
|
|
|
# QEMU provider settings (vagrant-qemu plugin)
|
|
config.vm.provider "qemu" do |qe|
|
|
qe.arch = "aarch64"
|
|
qe.machine = "virt,highmem=on"
|
|
qe.cpu = "host"
|
|
qe.smp = "cpus=4,sockets=1,cores=4,threads=1"
|
|
qe.memory = "8G"
|
|
qe.net_device = "virtio-net-pci"
|
|
|
|
# Apple Hypervisor.framework - native speed on Apple Silicon
|
|
qe.accel = "hvf"
|
|
|
|
# Disk: virtio-blk (must match how the box was built)
|
|
qe.drive_interface = "virtio"
|
|
qe.disk_size = "80G"
|
|
|
|
# Extra QEMU arguments for Windows 11 ARM64 boot
|
|
vagrant_dir = File.join(Dir.pwd, ".vagrant", "machines", "default", "qemu")
|
|
FileUtils.mkdir_p(vagrant_dir)
|
|
efi_vars = ensure_efi_vars(vagrant_dir)
|
|
|
|
extra_args = [
|
|
# EFI firmware (pflash: read-only code + writable vars for NVRAM)
|
|
"-drive", "if=pflash,format=raw,readonly=on,file=#{EFI_CODE}",
|
|
"-drive", "if=pflash,format=raw,file=#{efi_vars}",
|
|
# Display and input devices
|
|
"-device", "virtio-gpu-pci",
|
|
"-device", "qemu-xhci",
|
|
"-device", "usb-kbd",
|
|
"-device", "usb-tablet",
|
|
]
|
|
|
|
# TPM 2.0 support (required for Windows 11 unless bypassed in the box)
|
|
# Uses swtpm if available - if not, the box must have TPM requirement bypassed
|
|
tpm_dir = tpm_socket_path(vagrant_dir)
|
|
swtpm_bin = `which swtpm 2>/dev/null`.strip
|
|
if !swtpm_bin.empty? && File.exist?(swtpm_bin)
|
|
FileUtils.mkdir_p(tpm_dir)
|
|
# swtpm will be started by the provisioning wrapper; add device to QEMU
|
|
extra_args += [
|
|
"-chardev", "socket,id=chrtpm,path=#{tpm_dir}/swtpm-sock",
|
|
"-tpmdev", "emulator,id=tpm0,chardev=chrtpm",
|
|
"-device", "tpm-tis-device,tpmdev=tpm0",
|
|
]
|
|
end
|
|
|
|
qe.extra_qemu_args = extra_args
|
|
end
|
|
|
|
# Increase boot timeout (Windows ARM64 can be slow on first boot)
|
|
config.vm.boot_timeout = 1200
|
|
|
|
# Disable default synced folder (not supported by QEMU user-mode networking)
|
|
config.vm.synced_folder ".", "/vagrant", disabled: true
|
|
|
|
# --- File provisioners: copy project files into VM ---
|
|
config.vm.provision "file", source: "config", destination: "C:\\vagrant_config"
|
|
config.vm.provision "file", source: "webui", destination: "C:\\vagrant\\webui"
|
|
config.vm.provision "file", source: "rules", destination: "C:\\vagrant\\rules"
|
|
|
|
# --- Shell provisioners: install everything ---
|
|
# All scripts detect ARM64 vs x86_64 and handle architecture differences.
|
|
# Tools without native ARM64 builds (Fibratus, Rustinel) run under
|
|
# Windows' x86_64 emulation layer. ETW kernel tracing works but with
|
|
# slight overhead under emulation.
|
|
|
|
config.vm.provision "prerequisites",
|
|
type: "shell",
|
|
path: "scripts/install-prerequisites.ps1",
|
|
privileged: true
|
|
|
|
config.vm.provision "sysmon",
|
|
type: "shell",
|
|
path: "scripts/install-sysmon.ps1",
|
|
privileged: true
|
|
|
|
config.vm.provision "fibratus",
|
|
type: "shell",
|
|
path: "scripts/install-fibratus.ps1",
|
|
privileged: true
|
|
|
|
config.vm.provision "rustinel",
|
|
type: "shell",
|
|
path: "scripts/install-rustinel.ps1",
|
|
privileged: true
|
|
|
|
config.vm.provision "detection-rules",
|
|
type: "shell",
|
|
path: "scripts/install-detection-rules.ps1",
|
|
privileged: true
|
|
|
|
config.vm.provision "detonator",
|
|
type: "shell",
|
|
path: "scripts/install-detonator.ps1",
|
|
privileged: true
|
|
|
|
config.vm.provision "litterbox",
|
|
type: "shell",
|
|
path: "scripts/install-litterbox.ps1",
|
|
privileged: true
|
|
|
|
config.vm.provision "thezoo",
|
|
type: "shell",
|
|
path: "scripts/install-thezoo.ps1",
|
|
privileged: true
|
|
|
|
config.vm.provision "hunt-sleeping-beacons",
|
|
type: "shell",
|
|
path: "scripts/install-hunt-sleeping-beacons.ps1",
|
|
privileged: true
|
|
|
|
config.vm.provision "beaconeye",
|
|
type: "shell",
|
|
path: "scripts/install-beaconeye.ps1",
|
|
privileged: true
|
|
|
|
config.vm.provision "scanner-tools",
|
|
type: "shell",
|
|
path: "scripts/install-scanner-tools.ps1",
|
|
privileged: true
|
|
|
|
config.vm.provision "re-tools",
|
|
type: "shell",
|
|
path: "scripts/install-re-tools.ps1",
|
|
privileged: true
|
|
|
|
config.vm.provision "webui",
|
|
type: "shell",
|
|
path: "scripts/install-webui.ps1",
|
|
privileged: true
|
|
|
|
config.vm.provision "configure",
|
|
type: "shell",
|
|
path: "scripts/configure-services.ps1",
|
|
privileged: true,
|
|
run: "always"
|
|
end
|