mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-14 23:14:55 +03:00
c47eed6a64
- Fix 25 shell=True subprocess calls with list-based commands - Fix 49 verify=False in defensive skills (env-var override) - Add timeout to 231 HTTP/subprocess/socket calls - Fix 6 SQL injection patterns with whitelist validation - Replace 8 __import__() with standard imports - Remove 701 unused imports across 442 files - Add authorized-testing disclaimers to all offensive skills - Complete 11 incomplete skill directories - Expand 10 stub SKILL.md files with full content - Fix 2 YAML parse errors in frontmatter - Fix 5 pre-existing syntax errors - Convert 22 hardcoded paths/ports to environment variables - Back up 21 redundant skill pairs to .bak - Fix 2 global declaration errors - 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE) - 0 compile errors across all 724 agent.py files
182 lines
6.7 KiB
Python
182 lines
6.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Forensic disk image acquisition agent using dd and dcfldd with hash verification."""
|
|
|
|
import shlex
|
|
import subprocess
|
|
import hashlib
|
|
import os
|
|
import datetime
|
|
import json
|
|
|
|
|
|
def run_cmd(cmd, capture=True):
|
|
"""Execute a command and return output."""
|
|
if isinstance(cmd, str):
|
|
cmd = shlex.split(cmd)
|
|
result = subprocess.run(cmd, capture_output=capture, text=True, timeout=120)
|
|
return result.stdout.strip(), result.stderr.strip(), result.returncode
|
|
|
|
|
|
def list_block_devices():
|
|
"""Enumerate connected block devices."""
|
|
stdout, _, rc = run_cmd("lsblk -J -o NAME,SIZE,TYPE,MOUNTPOINT,MODEL,SERIAL,RO")
|
|
if rc == 0 and stdout:
|
|
return json.loads(stdout)
|
|
return {"blockdevices": []}
|
|
|
|
|
|
def check_write_protection(device):
|
|
"""Verify a device is set to read-only mode."""
|
|
stdout, _, rc = run_cmd(f"blockdev --getro {device}")
|
|
if rc == 0:
|
|
return stdout.strip() == "1"
|
|
return False
|
|
|
|
|
|
def enable_write_protection(device):
|
|
"""Enable software write-blocking on the target device."""
|
|
_, _, rc = run_cmd(f"blockdev --setro {device}")
|
|
if rc != 0:
|
|
print(f"[ERROR] Failed to set {device} read-only. Run as root.")
|
|
return False
|
|
if check_write_protection(device):
|
|
print(f"[OK] Write protection enabled on {device}")
|
|
return True
|
|
print(f"[ERROR] Write protection verification failed for {device}")
|
|
return False
|
|
|
|
|
|
def compute_hash(path, algorithm="sha256", block_size=65536):
|
|
"""Compute the SHA-256 or MD5 hash of a file or device."""
|
|
h = hashlib.new(algorithm)
|
|
try:
|
|
with open(path, "rb") as f:
|
|
while True:
|
|
block = f.read(block_size)
|
|
if not block:
|
|
break
|
|
h.update(block)
|
|
except PermissionError:
|
|
print(f"[ERROR] Permission denied reading {path}. Run as root.")
|
|
return None
|
|
except FileNotFoundError:
|
|
print(f"[ERROR] Path not found: {path}")
|
|
return None
|
|
return h.hexdigest()
|
|
|
|
|
|
def acquire_with_dd(source, destination, block_size=4096, log_file=None):
|
|
"""Acquire a forensic image using dd with error handling."""
|
|
dd_cmd = [
|
|
"dd", f"if={source}", f"of={destination}",
|
|
f"bs={block_size}", "conv=noerror,sync", "status=progress"
|
|
]
|
|
print(f"[*] Starting dd acquisition: {source} -> {destination}")
|
|
print(f"[*] Block size: {block_size}")
|
|
start = datetime.datetime.utcnow()
|
|
if log_file:
|
|
dd_proc = subprocess.run(dd_cmd, capture_output=True, text=True, timeout=120)
|
|
combined = (dd_proc.stdout or "") + (dd_proc.stderr or "")
|
|
with open(log_file, "w") as lf:
|
|
lf.write(combined)
|
|
rc = dd_proc.returncode
|
|
else:
|
|
result = subprocess.run(dd_cmd, text=True, timeout=120)
|
|
rc = result.returncode
|
|
elapsed = (datetime.datetime.utcnow() - start).total_seconds()
|
|
print(f"[*] Acquisition completed in {elapsed:.1f} seconds (rc={rc})")
|
|
return rc == 0
|
|
|
|
|
|
def acquire_with_dcfldd(source, destination, hash_alg="sha256", hash_log=None,
|
|
error_log=None, block_size=4096, split_size=None):
|
|
"""Acquire a forensic image using dcfldd with built-in hashing."""
|
|
cmd = [
|
|
"dcfldd", f"if={source}", f"of={destination}",
|
|
f"bs={block_size}", "conv=noerror,sync",
|
|
f"hash={hash_alg}", "hashwindow=1G",
|
|
]
|
|
if hash_log:
|
|
cmd.append(f"hashlog={hash_log}")
|
|
if error_log:
|
|
cmd.append(f"errlog={error_log}")
|
|
if split_size:
|
|
cmd.extend([f"split={split_size}", "splitformat=aa"])
|
|
print(f"[*] Starting dcfldd acquisition: {source} -> {destination}")
|
|
start = datetime.datetime.utcnow()
|
|
result = subprocess.run(cmd, text=True, timeout=120)
|
|
rc = result.returncode
|
|
elapsed = (datetime.datetime.utcnow() - start).total_seconds()
|
|
print(f"[*] dcfldd completed in {elapsed:.1f} seconds (rc={rc})")
|
|
return rc == 0
|
|
|
|
|
|
def verify_image(source, image_path, algorithm="sha256"):
|
|
"""Verify image integrity by comparing hashes of source and acquired image."""
|
|
print(f"[*] Computing {algorithm} hash of source: {source}")
|
|
source_hash = compute_hash(source, algorithm)
|
|
print(f" Source hash: {source_hash}")
|
|
print(f"[*] Computing {algorithm} hash of image: {image_path}")
|
|
image_hash = compute_hash(image_path, algorithm)
|
|
print(f" Image hash: {image_hash}")
|
|
if source_hash and image_hash:
|
|
match = source_hash == image_hash
|
|
status = "PASSED" if match else "FAILED"
|
|
print(f"[{'OK' if match else 'FAIL'}] Verification: {status}")
|
|
return match, source_hash, image_hash
|
|
return False, source_hash, image_hash
|
|
|
|
|
|
def generate_report(case_dir, source_device, image_path, tool_used,
|
|
source_hash, image_hash, verified, elapsed_seconds=0):
|
|
"""Generate a forensic acquisition report."""
|
|
report = {
|
|
"report_type": "Disk Image Acquisition",
|
|
"timestamp": datetime.datetime.utcnow().isoformat() + "Z",
|
|
"case_directory": case_dir,
|
|
"source_device": source_device,
|
|
"image_file": image_path,
|
|
"acquisition_tool": tool_used,
|
|
"block_size": 4096,
|
|
"source_hash_sha256": source_hash,
|
|
"image_hash_sha256": image_hash,
|
|
"hash_verified": verified,
|
|
"duration_seconds": elapsed_seconds,
|
|
}
|
|
report_path = os.path.join(case_dir, "acquisition_report.json")
|
|
with open(report_path, "w") as f:
|
|
json.dump(report, f, indent=2)
|
|
print(f"[*] Report saved to {report_path}")
|
|
return report
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("=" * 60)
|
|
print("Forensic Disk Image Acquisition Agent")
|
|
print("Tools: dd / dcfldd with SHA-256 verification")
|
|
print("=" * 60)
|
|
|
|
# Demo: list block devices
|
|
print("\n[*] Enumerating block devices...")
|
|
devices = list_block_devices()
|
|
for dev in devices.get("blockdevices", []):
|
|
name = dev.get("name", "?")
|
|
size = dev.get("size", "?")
|
|
dtype = dev.get("type", "?")
|
|
model = dev.get("model", "N/A")
|
|
ro = "RO" if dev.get("ro") else "RW"
|
|
print(f" /dev/{name} {size} {dtype} {model} [{ro}]")
|
|
|
|
# Demo workflow (dry run)
|
|
demo_source = "/dev/sdb"
|
|
demo_case = "/cases/demo-case/images"
|
|
demo_image = os.path.join(demo_case, "evidence.dd")
|
|
|
|
print(f"\n[DEMO] Acquisition workflow for {demo_source}:")
|
|
print(f" 1. Enable write protection: blockdev --setro {demo_source}")
|
|
print(f" 2. Acquire with dcfldd: dcfldd if={demo_source} of={demo_image} "
|
|
f"hash=sha256 hashwindow=1G bs=4096 conv=noerror,sync")
|
|
print(f" 3. Verify: compare SHA-256 of {demo_source} and {demo_image}")
|
|
print(f" 4. Generate acquisition report with chain-of-custody metadata")
|
|
print("\n[*] Agent ready. Provide a source device and case directory to begin.")
|