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

138 lines
5.3 KiB
Python

#!/usr/bin/env python3
# For authorized penetration testing and educational environments only.
# Usage against targets without prior mutual consent is illegal.
# It is the end user's responsibility to obey all applicable local, state and federal laws.
"""BloodHound CE reconnaissance agent using bloodhound Python ingestor and Neo4j."""
import json
import sys
import argparse
import subprocess
from datetime import datetime
try:
from neo4j import GraphDatabase
except ImportError:
print("Install: pip install neo4j")
sys.exit(1)
def collect_bloodhound_data(domain, username, password, dc_ip, method="all"):
"""Run BloodHound Python ingestor to collect AD data."""
cmd = [
"bloodhound-python", "-d", domain, "-u", username, "-p", password,
"-ns", dc_ip, "-c", method, "--zip",
]
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
return {"status": "completed", "output": result.stdout[:1000]}
except FileNotFoundError:
return {"status": "error", "message": "Install: pip install bloodhound"}
except subprocess.TimeoutExpired:
return {"status": "timeout"}
def query_shortest_path_to_da(driver):
"""Find shortest path to Domain Admins."""
with driver.session() as session:
result = session.run(
"MATCH p=shortestPath((u:User)-[*1..]->(g:Group {name: $group})) "
"WHERE u.enabled = true RETURN u.name AS user, length(p) AS hops "
"ORDER BY hops LIMIT 10",
group="DOMAIN ADMINS@DOMAIN.LOCAL",
)
return [{"user": r["user"], "hops": r["hops"]} for r in result]
def query_kerberoastable_users(driver):
"""Find kerberoastable user accounts."""
with driver.session() as session:
result = session.run(
"MATCH (u:User) WHERE u.hasspn = true AND u.enabled = true "
"RETURN u.name AS user, u.serviceprincipalnames AS spns, "
"u.admincount AS admin_count ORDER BY u.admincount DESC"
)
return [{"user": r["user"], "spns": r["spns"],
"admin": r["admin_count"]} for r in result]
def query_unconstrained_delegation(driver):
"""Find computers with unconstrained delegation."""
with driver.session() as session:
result = session.run(
"MATCH (c:Computer) WHERE c.unconstraineddelegation = true "
"RETURN c.name AS computer, c.operatingsystem AS os"
)
return [{"computer": r["computer"], "os": r["os"]} for r in result]
def query_as_rep_roastable(driver):
"""Find AS-REP roastable accounts (no pre-auth required)."""
with driver.session() as session:
result = session.run(
"MATCH (u:User) WHERE u.dontreqpreauth = true AND u.enabled = true "
"RETURN u.name AS user, u.admincount AS admin_count"
)
return [{"user": r["user"], "admin": r["admin_count"]} for r in result]
def run_recon(neo4j_uri, neo4j_user, neo4j_password):
"""Run BloodHound reconnaissance queries."""
driver = GraphDatabase.driver(neo4j_uri, auth=(neo4j_user, neo4j_password))
print(f"\n{'='*60}")
print(f" BLOODHOUND CE RECONNAISSANCE")
print(f" Generated: {datetime.utcnow().isoformat()} UTC")
print(f"{'='*60}\n")
paths = query_shortest_path_to_da(driver)
print(f"--- SHORTEST PATHS TO DOMAIN ADMIN ({len(paths)}) ---")
for p in paths:
print(f" {p['user']}: {p['hops']} hops")
kerb = query_kerberoastable_users(driver)
print(f"\n--- KERBEROASTABLE USERS ({len(kerb)}) ---")
for k in kerb[:10]:
print(f" {k['user']} (admin={k['admin']})")
deleg = query_unconstrained_delegation(driver)
print(f"\n--- UNCONSTRAINED DELEGATION ({len(deleg)}) ---")
for d in deleg:
print(f" {d['computer']}: {d['os']}")
asrep = query_as_rep_roastable(driver)
print(f"\n--- AS-REP ROASTABLE ({len(asrep)}) ---")
for a in asrep:
print(f" {a['user']} (admin={a['admin']})")
driver.close()
return {"paths_to_da": paths, "kerberoastable": kerb,
"unconstrained_delegation": deleg, "asrep_roastable": asrep}
def main():
parser = argparse.ArgumentParser(description="BloodHound CE Recon Agent")
parser.add_argument("--neo4j-uri", default="bolt://localhost:7687", help="Neo4j URI")
parser.add_argument("--neo4j-user", default="neo4j", help="Neo4j username")
parser.add_argument("--neo4j-password", required=True, help="Neo4j password")
parser.add_argument("--collect", action="store_true", help="Run data collection first")
parser.add_argument("--domain", help="AD domain for collection")
parser.add_argument("--ad-user", help="AD username for collection")
parser.add_argument("--ad-pass", help="AD password for collection")
parser.add_argument("--dc-ip", help="Domain controller IP")
parser.add_argument("--output", help="Save report to JSON file")
args = parser.parse_args()
if args.collect and args.domain:
result = collect_bloodhound_data(args.domain, args.ad_user, args.ad_pass, args.dc_ip)
print(json.dumps(result, indent=2))
report = run_recon(args.neo4j_uri, args.neo4j_user, args.neo4j_password)
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2, default=str)
print(f"\n[+] Report saved to {args.output}")
if __name__ == "__main__":
main()