#!/usr/bin/env python3 """Run once on Proxmox after trusted cloud-init completes, before deploying payload code.""" import json from pathlib import Path import shlex import subprocess ROOT = Path('/var/lib/vz/honeypot') PCAP = ROOT / 'execution.pcap' if PCAP.exists(): raise SystemExit('Existing capture found: refusing a restart that would truncate evidence') def guest(vm, command): result = json.loads(subprocess.check_output( ['qm', 'guest', 'exec', str(vm), '--', '/bin/sh', '-c', command], text=True)) if result.get('exitcode') != 0: raise RuntimeError(result) return result.get('out-data', '') for vm in (222, 223): guest(vm, 'test -f /var/lib/decoy-bootstrap-complete && cloud-init status --long') keys = {vm: guest(vm, 'cat /etc/ssh/ssh_host_ed25519_key.pub').strip() for vm in (222, 223)} pub = guest(222, 'mkdir -p /root/.ssh; chmod 700 /root/.ssh; ' 'test -f /root/.ssh/decoy_execution_ed25519 || ' 'ssh-keygen -q -t ed25519 -N "" -f /root/.ssh/decoy_execution_ed25519; ' 'cat /root/.ssh/decoy_execution_ed25519.pub').strip() guest(223, 'printf "%s\\n" ' + shlex.quote( 'no-agent-forwarding,no-port-forwarding,no-X11-forwarding ' + pub) + ' >> /root/.ssh/authorized_keys; chmod 600 /root/.ssh/authorized_keys') guest(222, 'printf "%s\\n" ' + shlex.quote('10.0.2.101 ' + keys[223]) + ' > /root/.ssh/known_hosts; chmod 600 /root/.ssh/known_hosts; ' 'cp /root/.ssh/known_hosts /root/.ssh/decoy_execution_known_hosts') config = ('Host decoy-execution\n HostName 10.0.2.101\n User root\n' ' IdentityFile /root/.ssh/decoy_execution_ed25519\n IdentitiesOnly yes\n' ' StrictHostKeyChecking yes\n BatchMode yes\n ConnectTimeout 5\n') guest(222, 'printf "%s" ' + shlex.quote(config) + ' > /root/.ssh/config; chmod 600 /root/.ssh/config') subprocess.run(['qm', 'shutdown', '223', '--timeout', '60'], check=True) ROOT.chmod(0o700) PCAP.touch(mode=0o600, exist_ok=False) # -sandbox applies a QEMU seccomp filter: deny obsolete syscalls and privilege elevation. args = ('-netdev user,id=decoy,restrict=on,hostfwd=tcp:127.0.0.1:19223-:22,' 'guestfwd=tcp:10.0.2.100:19090-cmd:/var/lib/vz/honeypot/forward-collector-telemetry ' '-device virtio-net-pci,netdev=decoy,mac=52:54:00:22:02:23 ' '-object filter-dump,id=decoycap,netdev=decoy,' 'file=/var/lib/vz/honeypot/execution.pcap,maxlen=512 ' '-sandbox on,obsolete=deny,elevateprivileges=deny') subprocess.run(['qm', 'set', '223', '--args', args], check=True) subprocess.run(['qm', 'start', '223'], check=True) for vm, key in keys.items(): print(f'decoy-{vm} {key}') # Public host keys only.