Claude 24f816b6a3
Consolidate 22 sibling repos into layered organism structure
Place useful parts of the surrounding repos into sica-fondt by layer, per the
body model (Ada = membrane; brain/endocrine/capabilities/knowledge non-Ada):

- brain/        LLM reasoning + providers (dapr, hermes, MoMoA)
- capabilities/ REPRAG sidecars: hermes tools/skills, dapr tools, parallel
                dispatch, A51 channels, and the OSINT cluster
- knowledge/    LORAG corpus: 754 cyber-skills, agency personas, secure-coding,
                MITRE ATT&CK data
- reference/    defensive threat-reference (C3, shhbruh doc) + AdaYaml parser

License handling: AGPL sources (worldosint, advanced_evolution, mercury,
Reticulum) and GPL DeTTECT are SPEC-only clean-room/port descriptions — no
copyleft code copied. MIT/Apache/data parts copied as working trees.

Safety: shhbruh escape/persistence material and C3 covert-C2 kept as reference
only, not wired into the running organism. See CONSOLIDATION.md.

https://claude.ai/code/session_01UehUqEXXJJCsHoA4voCU5c
2026-06-10 06:53:01 +00:00

181 lines
5.7 KiB
Python

#!/usr/bin/env python3
"""
DCSync Rights Auditor and Hash Analysis Script
Audits AD environments for accounts with DCSync rights and
analyzes dumped credential data. For authorized red team engagements only.
"""
import sys
import os
import re
import json
from datetime import datetime
from collections import defaultdict
REPLICATION_GUIDS = {
"1131f6aa-9c07-11d1-f79f-00c04fc2dcd2": "DS-Replication-Get-Changes",
"1131f6ad-9c07-11d1-f79f-00c04fc2dcd2": "DS-Replication-Get-Changes-All",
"89e95b76-444d-4c62-991a-0facbeda640c": "DS-Replication-Get-Changes-In-Filtered-Set",
}
def parse_secretsdump_output(filepath: str) -> dict:
"""Parse Impacket secretsdump.py output for hash extraction."""
results = {
"ntds_hashes": [],
"kerberos_keys": [],
"cleartext_passwords": [],
"machine_accounts": [],
"user_accounts": [],
"krbtgt_hash": None,
"admin_hash": None
}
try:
with open(filepath, "r") as f:
lines = f.readlines()
except FileNotFoundError:
print(f"File not found: {filepath}")
return results
ntds_pattern = re.compile(r"^(.+?):([\d]+):([a-fA-F0-9]{32}):([a-fA-F0-9]{32}):::")
cleartext_pattern = re.compile(r"^(.+?):CLEARTEXT:(.+)$")
for line in lines:
line = line.strip()
ntds_match = ntds_pattern.match(line)
if ntds_match:
username = ntds_match.group(1)
rid = ntds_match.group(2)
lm_hash = ntds_match.group(3)
nt_hash = ntds_match.group(4)
entry = {
"username": username,
"rid": rid,
"lm_hash": lm_hash,
"nt_hash": nt_hash,
"is_machine": username.endswith("$")
}
results["ntds_hashes"].append(entry)
if entry["is_machine"]:
results["machine_accounts"].append(entry)
else:
results["user_accounts"].append(entry)
if username.lower() == "krbtgt":
results["krbtgt_hash"] = entry
elif username.lower() == "administrator":
results["admin_hash"] = entry
cleartext_match = cleartext_pattern.match(line)
if cleartext_match:
results["cleartext_passwords"].append({
"username": cleartext_match.group(1),
"password": cleartext_match.group(2)
})
return results
def analyze_password_reuse(hashes: list) -> dict:
"""Identify password reuse across accounts."""
hash_groups = defaultdict(list)
for entry in hashes:
if entry["nt_hash"] != "31d6cfe0d16ae931b73c59d7e0c089c0": # Skip empty passwords
hash_groups[entry["nt_hash"]].append(entry["username"])
reuse = {nt_hash: users for nt_hash, users in hash_groups.items() if len(users) > 1}
return reuse
def generate_dcsync_report(results: dict, source_file: str) -> str:
"""Generate DCSync credential analysis report."""
report = [
"=" * 70,
"DCSync Credential Analysis Report",
f"Generated: {datetime.now().isoformat()}",
f"Source: {source_file}",
"=" * 70,
"",
"[Summary]",
f" Total Hashes: {len(results['ntds_hashes'])}",
f" User Accounts: {len(results['user_accounts'])}",
f" Machine Accounts: {len(results['machine_accounts'])}",
f" Cleartext Passwords: {len(results['cleartext_passwords'])}",
""
]
# KRBTGT hash (most critical)
if results["krbtgt_hash"]:
report.append("[CRITICAL] KRBTGT Hash Recovered:")
report.append(f" NT Hash: {results['krbtgt_hash']['nt_hash']}")
report.append(" Impact: Golden Ticket creation possible")
report.append("")
# Administrator hash
if results["admin_hash"]:
report.append("[CRITICAL] Administrator Hash Recovered:")
report.append(f" NT Hash: {results['admin_hash']['nt_hash']}")
report.append(" Impact: Direct Domain Admin access via Pass-the-Hash")
report.append("")
# Password reuse analysis
reuse = analyze_password_reuse(results["user_accounts"])
if reuse:
report.append(f"[HIGH] Password Reuse Detected ({len(reuse)} shared passwords):")
for nt_hash, users in list(reuse.items())[:10]:
report.append(f" Hash ...{nt_hash[-8:]}: {', '.join(users[:5])}")
report.append("")
# Cleartext passwords
if results["cleartext_passwords"]:
report.append(f"[HIGH] Cleartext Passwords Found ({len(results['cleartext_passwords'])}):")
for entry in results["cleartext_passwords"][:10]:
report.append(f" {entry['username']}: [REDACTED]")
report.append("")
report.extend([
"[Persistence Opportunities]",
" 1. Golden Ticket: Use KRBTGT hash for indefinite domain access",
" 2. Silver Tickets: Use machine account hashes for service impersonation",
" 3. Pass-the-Hash: Use NT hashes for immediate lateral movement",
" 4. Password Cracking: Offline cracking of user hashes",
"",
"=" * 70
])
return "\n".join(report)
def main():
"""Main entry point."""
if len(sys.argv) < 2:
print("Usage: python process.py <secretsdump_output.txt>")
return
source_file = sys.argv[1]
results = parse_secretsdump_output(source_file)
if not results["ntds_hashes"]:
print("No NTDS hashes found in the input file.")
return
report = generate_dcsync_report(results, source_file)
print(report)
report_file = f"dcsync_analysis_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
with open(report_file, "w") as f:
f.write(report)
print(f"\nReport saved to: {report_file}")
if __name__ == "__main__":
main()