52 lines
2.6 KiB
Python
Executable File
52 lines
2.6 KiB
Python
Executable File
#!/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.
|