50 lines
1.9 KiB
Python
50 lines
1.9 KiB
Python
# 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.")
|
|
# }}}
|