CitrixPot: NetScaler / Citrix ADC Gateway honeypot (initial public release)
This commit is contained in:
commit
4491b42714
54 files changed
+4532
No files matched your search
@@ -0,0 +1,52 @@
|
||||
"""Offline reset guards; no Proxmox commands or VM mutation."""
|
||||
import importlib.util
|
||||
import pathlib
|
||||
import tempfile
|
||||
import hashlib
|
||||
|
||||
spec = importlib.util.spec_from_file_location('reset', pathlib.Path(__file__).parent / 'deploy/reset-execution.py')
|
||||
reset = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(reset)
|
||||
config = ('name: decoy-execution\nscsi0: local-lvm:vm-223-disk-0,size=12G\n'
|
||||
'args: -netdev user,id=decoy,restrict=on -object filter-dump,file=/var/lib/vz/honeypot/execution.pcap\n')
|
||||
reset.valid_config(config)
|
||||
for bad in (config.replace('decoy-execution', 'onionatlas'), config.replace('restrict=on', 'restrict=off'), config + 'net0: virtio,bridge=vmbr0\n'):
|
||||
try:
|
||||
reset.valid_config(bad)
|
||||
raise AssertionError('unsafe config accepted')
|
||||
except RuntimeError:
|
||||
pass
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
reset.ROOT = pathlib.Path(temporary)
|
||||
reset.ARCHIVES = reset.ROOT / 'archives'
|
||||
reset.ARCHIVES.mkdir()
|
||||
reset.RESERVE = 0
|
||||
reset.bounds = lambda min_free=0: None
|
||||
file = reset.ARCHIVES / 'evidence'
|
||||
reset.write_file(file, b'inert')
|
||||
try:
|
||||
reset.write_file(file, b'overwrite')
|
||||
raise AssertionError('evidence overwritten')
|
||||
except FileExistsError:
|
||||
pass
|
||||
assert reset.digest(file) == hashlib.sha256(b'inert').hexdigest()
|
||||
print('PASS: reset identity/isolation guards, exclusive evidence writes and hashes')
|
||||
|
||||
# Reset restores only the public CA authorization; idempotent and valid newlines.
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
reset.ROOT = pathlib.Path(temporary)
|
||||
line = 'cert-authority,principals="decoy-admin",restrict,pty ssh-ed25519 AAAATEST public-ca-test'
|
||||
(reset.ROOT / 'admin-ca.authorized').write_text(line + '\n')
|
||||
target = reset.ROOT / 'authorized_keys'
|
||||
target.write_text('existing-public-key\n')
|
||||
def fake_qm(*args, **kwargs):
|
||||
assert args[:3] == ('guest', 'exec', '223')
|
||||
script = args[-1].replace('/root/.ssh/authorized_keys', str(target))
|
||||
exec(script, {})
|
||||
return '{"exited":1,"exitcode":0}'
|
||||
reset.qm = fake_qm
|
||||
reset.install_admin_ca()
|
||||
reset.install_admin_ca()
|
||||
assert target.read_text().splitlines() == ['existing-public-key', line]
|
||||
assert target.stat().st_mode & 0o777 == 0o600
|
||||
print('PASS: public-only certificate authorization survives reset without duplicate keys')
|
||||
Reference in new issue
Block a user