Generated exploits must NEVER run on the host. Angband uses an isolated QEMU VM for all execution. This document walks through every step from a bare host to a verified demo run.
| Package | Why it's needed | Install |
|---|---|---|
qemu-system-x86 |
VM hypervisor | sudo apt install qemu-system-x86 |
cloud-image-utils |
cloud-localds to create the seed image |
sudo apt install cloud-image-utils |
openssh-client |
ssh-keygen and ssh for guest access |
Usually pre-installed |
python3 + pip |
Angband CLI | sudo apt install python3 python3-pip python3-venv |
gcc |
Compile the generated exploit C code | sudo apt install gcc |
telnet (optional) |
Serial console access for debugging | sudo apt install telnet |
Install everything at once:
sudo apt-get update
sudo apt-get install -y qemu-system-x86 cloud-image-utils openssh-client \
python3 python3-pip python3-venv gcc telnetcd /path/to/angband
python3 -m venv venv
source venv/bin/activate
pip install -e .Verify:
angband --version
# angband, version 0.1.0bash harness/setup.shThis is a one-time operation. It will:
- Check host dependencies -- verifies
qemu-img,cloud-localds, etc. - Download the Ubuntu 24.04 cloud image (~600 MB, cached in
mordor_run/cache/). This file is never modified. - Generate an SSH key pair under
mordor_run/ssh/. - Create a cloud-init seed image (
mordor_run/harness/seed.img) that provisions the guest with:- User
ubuntu(passwordubuntu, passwordless sudo) - Your SSH public key for key-based auth
- Auto-mount of the host repository at
/mnt/angbandvia 9p
- User
- Create a qcow2 overlay snapshot (
mordor_run/harness/disk.qcow2) backed by the base image. All guest writes go into this overlay; the base image stays pristine.
The resulting layout:
mordor_run/
├── cache/
│ └── ubuntu-24.04-server-cloudimg-amd64.img ← pristine base (never modified)
├── harness/
│ ├── disk.qcow2 ← overlay snapshot (all guest writes)
│ └── seed.img ← cloud-init provisioning
└── ssh/
├── id_ed25519 ← private key
└── id_ed25519.pub ← public key
bash harness/launch.shThis will:
- Boot QEMU in the background with KVM acceleration (if available)
- Wait for SSH to become accessible on
localhost:2222 - Report when the VM is ready
First boot takes ~60-90 seconds because cloud-init needs to run.
Subsequent boots (after stop.sh without reset.sh) are faster (~20s).
SSH (preferred):
ssh -o StrictHostKeyChecking=no -i mordor_run/ssh/id_ed25519 -p 2222 ubuntu@localhostSerial console (useful if SSH is down or kernel panics):
bash harness/console.sh
# or: telnet localhost 4444Inside the guest:
ls /mnt/angband/
# Should show the angband repository filesIf the 9p mount is missing:
sudo mount -t 9p -o trans=virtio,version=9p2000.L host0 /mnt/angbandFrom the host:
source venv/bin/activate
# Demo mode (safe walkthrough with vuln_drill)
angband init demo
angband generate
# Or: CVE analysis mode
angband init CVE-2024-1086
angband generateThis creates:
mordor_run/current/exploit.yaml-- scenario configurationmordor_run/current/exploit.c-- generated C sourcemordor_run/current/exploit-- compiled binary (statically linked)
bash run_and_verify.shThis script handles everything:
- Generates the payload (if not already done)
- Waits for the VM to be accessible via SSH
- Mounts 9p inside the guest
- Builds and loads
vuln_drill.koin the guest (demo mode only) - Runs the exploit binary inside the guest
- Extracts
dmesgand/proc/vuln_drilloutput - Verifies success criteria
| Check | File | Expected |
|---|---|---|
| Exploit completed | exploit_run.log |
Contains EXPLOIT COMPLETE |
| Privilege escalation | exploit_run.log |
Contains PRIVILEGE ESCALATION SUCCESSFUL |
| Root achieved | exploit_run.log |
Contains uid=0 euid=0 |
| All stages received | dmesg_tail.log |
Contains vuln_drill: stage <X> received for all 7 stages |
| Correct order | vuln_drill_status.log |
sequence_complete: yes |
| Kernel confirms | dmesg_tail.log |
Contains ESCALATE SUCCESS |
| Check | File | Expected |
|---|---|---|
| Payload completed | exploit_run.log |
Contains EXPLOIT COMPLETE or DEMO COMPLETE |
| Privilege escalation | exploit_run.log |
Contains PRIVILEGE ESCALATION SUCCESSFUL |
| Root achieved | exploit_run.log |
Contains uid=0 euid=0 |
| Kernel panic | serial log | No panic messages |
The CVE-2026-23209 exploit requires user namespaces with network privileges. On Ubuntu, the default kernel restricts these. To test:
# Inside the guest, as sudo:
sudo sysctl -w kernel.unprivileged_userns_clone=1
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0# From host:
source venv/bin/activate
angband init CVE-2026-23209 --target ubuntu-24.04-x86_64
angband generate
# From guest:
scp -P 2222 -i mordor_run/ssh/id_ed25519 localhost:/path/to/angband/mordor_run/current/cve_2026_23209 /tmp/
chmod +x /tmp/cve_2026_23209
/tmp/cve_2026_23209[*] ===== Stage: prep =====
[*] ===== Stage: groom =====
[*] ===== Stage: trigger =====
[+] UAF triggered: net_device freed
[*] ===== Stage: leak =====
[+] KASLR bypass: kernel_base = 0xffffffff...
[*] ===== Stage: primitive =====
[*] PTE reclaim + dirty pagetable write
[*] ===== Stage: escalate =====
[*] modprobe_path overwrite
[+] ROOT ACHIEVED via modprobe_path!
[+] PRIVILEGE ESCALATION SUCCESSFUL
[+] uid=0 euid=0 gid=0 egid=0
SSH into the guest and run commands manually:
ssh -o StrictHostKeyChecking=no -i mordor_run/ssh/id_ed25519 -p 2222 ubuntu@localhost
# Inside the guest:
cd /mnt/angband
# Run the exploit
./mordor_run/current/cve_2026_23209
# Check kernel logs
sudo dmesg | grep 'vuln_drill:'
# Read vuln_drill status
cat /proc/vuln_drill
# Load vuln_drill manually if needed
cd /mnt/angband/module/vuln_drill
make
sudo insmod ./vuln_drill.ko| Action | Command |
|---|---|
| First-time setup | bash harness/setup.sh |
| Boot the VM | bash harness/launch.sh |
| Stop the VM | bash harness/stop.sh |
| Reset to clean state | bash harness/reset.sh |
| Import custom VM | bash harness/import.sh <image> |
| Serial console | bash harness/console.sh |
If you have your own QEMU VM image (installed manually, a custom kernel build, etc.), you can integrate it into the angband pipeline.
Your VM must have:
- SSH server running (OpenSSH)
- A user account with
sudoaccess (passwordless preferred) build-essentialand kernel headers for buildingvuln_drill.ko- Network accessible via QEMU port forwarding
bash harness/import.sh /path/to/your-vm.qcow2 [ssh-port] [ssh-user]Example:
bash harness/import.sh ~/my-kernel-vm.qcow2 2222 testuserThis will:
- Generate angband SSH keys under
mordor_run/ssh/ - Display the public key for you to add to your VM
- Create a qcow2 overlay snapshot (your original image is never modified)
The script prints a public key. You must add it to your VM's
~/.ssh/authorized_keys. If your VM is currently running:
# Copy the key to the VM (adjust port and user as needed)
ssh -p 2222 youruser@localhost \
'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys' \
<<< 'ssh-ed25519 AAAA... (the key printed by import.sh)'Or boot your VM, log in via the console, and paste the key manually.
If your VM is NOT already running, use angband's launcher:
bash harness/launch.shIf your VM IS already running with its own QEMU command, make sure it has:
- SSH port forwarding:
-net user,hostfwd=tcp::2222-:22 - 9p mount (optional but recommended):
-virtfs local,path=/path/to/angband,mount_tag=host0,security_model=passthrough
ssh -o StrictHostKeyChecking=no \
-i mordor_run/ssh/id_ed25519 \
-p 2222 youruser@localhost \
'uname -r && id'Inside the guest:
sudo mkdir -p /mnt/angband
sudo mount -t 9p -o trans=virtio,version=9p2000.L host0 /mnt/angbandIf 9p is not available (e.g., your QEMU was launched without -virtfs),
you can copy the exploit binary via scp instead:
# On the host, after 'angband generate':
scp -i mordor_run/ssh/id_ed25519 -P 2222 \
mordor_run/current/exploit youruser@localhost:/tmp/exploitWith 9p:
bash run_and_verify.shWithout 9p (manual):
# Copy exploit and module to guest
scp -i mordor_run/ssh/id_ed25519 -P 2222 \
mordor_run/current/exploit youruser@localhost:/tmp/
# SSH in and run
ssh -i mordor_run/ssh/id_ed25519 -p 2222 youruser@localhost
cd /tmp && chmod +x exploit && ./exploitIf the VM gets into a bad state (kernel panic, corrupted filesystem, wrong SSH keys), reset it instantly:
bash harness/reset.sh
bash harness/launch.shThis destroys the overlay snapshot and creates a fresh one from the pristine base image. No re-download needed. Cloud-init will re-run on the next boot to provision SSH keys and the 9p mount.
The SSH key was generated after the VM was already provisioned. Fix:
bash harness/stop.sh
bash harness/reset.sh
bash harness/launch.sh- Check if QEMU is running:
cat mordor_run/harness/qemu.pid && ps -p $(cat mordor_run/harness/qemu.pid) - Check QEMU log:
cat mordor_run/harness/qemu.log - Try the serial console:
bash harness/console.sh - If using software emulation (no KVM), boot takes much longer (~3-5 minutes)
Another VM or service is using the port:
ss -tlnp | grep :2222
# Kill the conflicting process, or stop the other VM
bash harness/stop.shEnsure QEMU was launched with the -virtfs flag (handled by launch.sh).
Try mounting manually:
sudo mount -t 9p -o trans=virtio,version=9p2000.L host0 /mnt/angbandThe guest needs kernel headers:
sudo apt-get update
sudo apt-get install -y build-essential linux-headers-$(uname -r)
cd /mnt/angband/module/vuln_drill
make clean && make
sudo insmod ./vuln_drill.koThe overlay is 10 GB. If that's insufficient:
# On the host, after stopping the VM:
qemu-img resize mordor_run/harness/disk.qcow2 +10G
# Then boot and resize the partition inside the guestRemove all generated state (keeps the cached base image):
bash cleanup.shRemove everything including the cached Ubuntu image (~600 MB):
bash cleanup.sh --all