secubox-deb/packages/secubox-antirootkit/api/quarantine.py
CyberMind-FR b94ece7b68 fix(antirootkit): shlex.quote c2_ip and unit in quarantine plan (Task 9)
nft_block and disable_unit interpolated c2_ip/unit raw, unlike path,
letting a crafted unit or c2_ip smuggle shell metacharacters into the
plan strings an operator copies/pastes and runs. Quote both like path.
Also strengthens the no-side-effects test to monkeypatch os.chmod and
shutil.copy alongside os.system/subprocess.run, and adds a test
asserting metacharacters in c2_ip/unit come out shell-quoted.

Co-Authored-By: Gerald KERMA <devel@cybermind.fr>
2026-07-28 09:01:41 +02:00

50 lines
1.8 KiB
Python

# SPDX-License-Identifier: LicenseRef-CMSD-1.0
# Copyright (c) 2026 CyberMind — Gérald Kerma <devel@cybermind.fr>
# Source-Disclosed License — All rights reserved except as expressly granted.
# See LICENCE-CMSD-1.0.md for terms.
"""
SecuBox-Deb :: antirootkit quarantine preparation (manual, alert-only)
Computes the PLAN for neutralizing a confirmed-malicious binary as data —
a dict of shell command strings the operator may choose to run separately.
`prepare()` NEVER executes anything: no os.system, no subprocess, no
os.chmod, no file writes, no kill. The only allowed side effect is calling
the injected `sha_fn`, which in production would hash the file and in
tests is a fake.
"""
import shlex
def prepare(
path: str,
c2_ip: str | None = None,
unit: str | None = None,
sha_fn=None,
) -> dict:
"""Return the planned quarantine steps for `path` as data (not executed).
Keys:
chmod -- str, `chmod 000 <path>` (revoke all permissions)
copy -- str, `cp -a <path> /root/quarantine/` (evidence copy)
sha256 -- str | None, hex digest via sha_fn(path) if provided, else None
nft_block -- str | None, nft rule dropping egress to c2_ip if given, else None
disable_unit -- str | None, systemctl disable --now <unit> if given, else None
"""
quoted_path = shlex.quote(path)
return {
"chmod": f"chmod 000 {quoted_path}",
"copy": f"cp -a {quoted_path} /root/quarantine/",
"sha256": sha_fn(path) if sha_fn is not None else None,
"nft_block": (
f"nft add rule inet filter output ip daddr {shlex.quote(c2_ip)} drop"
if c2_ip is not None
else None
),
"disable_unit": (
f"systemctl disable --now {shlex.quote(unit)}" if unit is not None else None
),
}