# src/ctf/steg.py # {{{ imports import shutil import subprocess import tempfile from dataclasses import dataclass from pathlib import Path # }}} # {{{ SteghideCrackResult @dataclass class SteghideCrackResult: success: bool password: str | None = None payload: bytes | None = None error_message: str | None = None # }}} # {{{ crack_steghide def crack_steghide(file_path: Path, wordlist: list[str]) -> SteghideCrackResult: """Tries to extract data from a file using steghide with a wordlist.""" if not shutil.which("steghide"): return SteghideCrackResult(success=False, error_message="steghide executable not found on system PATH.") file_path = Path(file_path).resolve() if not file_path.exists(): return SteghideCrackResult(success=False, error_message=f"File not found: {file_path}") for password in wordlist: password = password.strip() with tempfile.TemporaryDirectory() as tmpdir: out_file = Path(tmpdir) / "extracted_payload" cmd = ["steghide", "extract", "-sf", str(file_path), "-p", password, "-xf", str(out_file), "-f"] try: # Capture standard outputs; timeout to prevent indefinite hangs result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=5) if result.returncode == 0 and out_file.exists(): return SteghideCrackResult( success=True, password=password, payload=out_file.read_bytes() ) except subprocess.TimeoutExpired: pass except Exception as e: return SteghideCrackResult(success=False, error_message=str(e)) return SteghideCrackResult(success=False, error_message="Password not found in wordlist.") # }}}