Skip to main content
Glama
The-bub

bloodhound

by The-bub
README.md
# Agent BloodHound

Un assistant **Claude** qui répond en langage naturel (FR/EN) à tes questions sur un
audit **Active Directory**. Tu demandes _« quels comptes sont Kerberoastables ? »_ ou
_« un chemin de sansa.stark vers les Domain Admins ? »_, il interroge le graphe et
répond avec des tableaux clairs et les chemins d'attaque.

> **Nouveau sur le sujet ?** **BloodHound** cartographie un Active Directory en graphe
> (utilisateurs, groupes, machines, droits) pour révéler les chemins qu'un attaquant
> emprunterait. **SharpHound** collecte les données (un `.zip` de JSON). Cet agent lit
> ce graphe et l'explique. Usage : test d'intrusion **autorisé** ou labo.

## Capacités

L'agent choisit lui-même l'outil adapté — tu poses juste la question :

- **Credentials** — Kerberoastables, AS-REP roastables, lecteurs LAPS / gMSA.
- **Chemins d'attaque** — vers Domain Admins / tier-0 (`paths_to_tier0`), entre deux
  objets, portée (`blast_radius`). Ne traverse que les edges **abusables** (les edges
  structurels `Contains`/`GPLink` sont exclus → pas de faux chemins).
- **Privilèges** — DCSync, délégations (non contrainte, contrainte, RBCD), abus d'ACL.
- **Triage** — profil de sécurité d'un objet (attributs vérifiés, qui le contrôle,
  distance au tier-0), détails, recherche.
- **Domaine / forêt** — Domain Admins (imbriqués), Domain Controllers, relations de
  confiance, objets tier-0.
- **Owned** — marque des comptes compromis, puis « chemins depuis owned ».

Toutes les requêtes sont **en lecture seule** et **auditées** (`runs/audit.log`).

---

## Prérequis

| Outil | Pourquoi | Vérifier / installer |
|---|---|---|
| **Docker** (ou OrbStack) | Bases de BloodHound | `docker --version`. Sinon [Docker Desktop](https://www.docker.com/products/docker-desktop/) / [OrbStack](https://orbstack.dev). **Doit être lancé.** |
| **Python 3.10+** | Faire tourner l'agent | `python3 --version`. Sinon [python.org](https://www.python.org/downloads/) ou `brew install python@3.12`. |
| **Claude Code** (CLI `claude`) | L'agent utilise Claude | Connexion au **1er lancement** — pas de `claude login` séparé à taper. |

## Installation

Trois voies. Toutes ont besoin d'un **BloodHound CE avec des données** : l'**option B**
(`setup.sh`) met tout en place pour toi (et peut charger un jeu de démo) ; les options
**A** et **C** supposent que la base tourne déjà (voir [Charger des données](#charger-des-données)).

### Option A — Plugin Claude Code (marketplace)

À privilégier si tu utilises déjà Claude Code et as un BloodHound CE qui tourne. Le
dépôt est un **plugin distribuable** : serveur MCP `bloodhound` (23 outils lecture
seule, qui crée son propre venv au 1er lancement) + une compétence analyste (`SKILL.md`).

Dans Claude Code :

```text
/plugin marketplace add The-bub/Agent-BloodHound     # depuis GitHub
/plugin install bloodhound@agent-bloodhound
```

(Ou depuis un clone local : `/plugin marketplace add /chemin/vers/Agent-BloodHound`.)

1. `marketplace add` enregistre le catalogue ; `install` copie le plugin et propose un
   **scope** (projet / utilisateur) — confirme-le.
2. Si Claude affiche « Run /reload-plugins to activate », lance `/reload-plugins`.
3. À la **1re requête**, approuve le serveur MCP « bloodhound ». Ce premier appel prend
   ~10 s (création du venv du plugin).

Gérer : `/plugin` (activer / désactiver), `/plugin marketplace update` (nouvelle
version). Neo4j non standard ? Définis `NEO4J_URI` / `NEO4J_USER` / `NEO4J_PASSWORD`
dans l'environnement où tu lances `claude`.

### Option B — En local avec `setup.sh` (turnkey)

À privilégier si tu pars de zéro : monte les bases, l'environnement Python et
(optionnel) les données de démo, puis ouvre Claude Code.

```bash
cd /Users/eliotbedel/Claude/Agent-BloodHound
./setup.sh          # bases + venv + (option) données de démo GOAD
./bloodhound        # démarre tout et ouvre Claude Code (connexion au 1er lancement)
```

`./bloodhound` relance les bases si besoin et ouvre Claude Code dans le dossier (via
`.mcp.json` + `CLAUDE.md`). Discute normalement : Claude appelle les outils et **garde
le contexte**.

### Option C — Python (avancé / scripting)

Pour interroger sans Claude Code (REPL ou one-shot scriptable).

```bash
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt        # ou: pip install -e .  → la commande `bh-agent`

python -m agent.main                              # REPL (garde le contexte)
python -m agent.main -q "Qui peut faire un DCSync ?"      # one-shot
python -m agent.main -q "Détaille le 1er compte" -c       # continue le one-shot
python -m agent.main -q "..." --export                    # + rapport dans runs/
```

Après `pip install -e .`, `bh-agent` remplace `python -m agent.main`. Commandes du
REPL : **`help`**, **`export`** (rapport `runs/`), **`exit`**.

---

## Charger des données

Nécessaire pour les options A et C (l'option B `setup.sh` peut charger la démo à ta
place). Trois méthodes.

### Démo GOAD (recommandé pour débuter)

Vrai jeu d'exemple (labo GOAD, 3 domaines) :

```bash
mkdir -p demo && cd demo
base="https://github.com/m4lwhere/Bloodhound-CE-Sample-Data/raw/main"
curl -fsSLO "$base/ce_branch_bloodhoundpy_essos_20240411011238_bloodhound.zip"
curl -fsSLO "$base/ce_branch_bloodhoundpy_north_20240411011008_bloodhound.zip"
curl -fsSLO "$base/ce_branch_bloodhoundpy_sevenkingdoms_20240411011059_bloodhound.zip"
cd ..
docker compose logs bloodhound | grep "Initial Password"   # mot de passe admin
export BH_ADMIN_PW='COLLE_LE_MOT_DE_PASSE'
python scripts/ce_ingest.py --json-dir demo                 # dézippe tout seul
```

Résultat : ~333 objets / ~3300 relations.

### Ton extract, via l'interface web

Le plus visuel, sans ligne de commande.

1. **Collecte** — lance SharpHound (Windows) ou `bloodhound.py` / AzureHound ; tu
   obtiens un `.zip` (parfois plusieurs).
2. **Connexion** — ouvre **http://localhost:8080**, identifie-toi avec `admin` + le mot
   de passe des logs (`docker compose logs bloodhound | grep "Initial Password"`).
   BloodHound impose un nouveau mot de passe au premier login.
3. **Import** — menu **Administration → File Ingest**, glisse ton (tes) `.zip`.
4. **Attente** — BloodHound parse puis **post-traite** (calcul des edges) ; les
   compteurs montent, le graphe est prêt quand ils se stabilisent.

### Tes fichiers locaux, en ligne de commande

Le plus rapide quand les fichiers sont déjà sur disque. Le script les pousse via l'API
CE : il **dézippe les `.zip` tout seul** et accepte un dossier mêlant `.zip` et `.json`.

```bash
docker compose logs bloodhound | grep "Initial Password"   # mot de passe admin
export BH_ADMIN_PW='COLLE_LE_MOT_DE_PASSE'
python scripts/ce_ingest.py --json-dir /chemin/vers/mes-extraits   # --no-wait pour ne pas attendre
```

---

## Utiliser l'agent

Une fois installé (n'importe quelle option), pose tes questions en langage naturel.
L'agent ne fait pas qu'énumérer : il **explique les vulnérabilités** et **donne les
commandes d'exploitation** (contexte de test autorisé). Les noms ci-dessous viennent
du jeu de démo GOAD.

### Exemples de questions

**Énumération / cartographie**
- Liste les comptes Kerberoastables activés (avec leurs SPN).
- Quels ordinateurs ont une délégation non contrainte ?
- Qui peut faire un DCSync sur chaque domaine ?
- Quels sont les objets tier-0 de la forêt ? Et les Domain Controllers ?

**Chemins d'attaque**
- Chemin le plus court de jon.snow vers les Domain Admins.
- Depuis sansa.stark, quels sont les chemins vers le tier-0 ?
- Existe-t-il un chemin cross-domain de NORTH vers ESSOS ?
- Si je compromets sql_svc@essos.local, qu'est-ce que j'atteins en 2 sauts ?

**Comprendre une vulnérabilité**
- Explique le Kerberoasting et pourquoi ces comptes sont exposés.
- C'est quoi l'unconstrained delegation, et pourquoi WINTERFELL est critique ?
- Quelle différence entre DCSync, Golden Ticket et Silver Ticket ?

**Demander les commandes d'exploitation**
- Donne-moi les commandes pour Kerberoaster jon.snow (Rubeus et impacket).
- Étapes + outils pour abuser l'unconstrained delegation de WINTERFELL.
- Comment cracker le hash récupéré (hashcat) ?

**Triage / priorisation**
- Fais le profil de sécurité de sansa.stark.
- Qui contrôle l'administrateur du domaine (ACL entrantes dangereuses) ?
- Quels sont les 5 comptes les plus intéressants à compromettre en premier, et pourquoi ?

**Owned / post-compromission**
- Marque sql_svc comme owned, puis montre les chemins vers le tier-0.
- Depuis mes comptes owned, quel est le chemin le plus court vers les Domain Admins ?

**Remédiation (blue team)**
- Comment corriger le Kerberoasting sur ces comptes ?
- Quelles priorités de durcissement pour couper les chemins vers les Domain Admins ?

### Rendu

Les actions défilent en grisé, puis la **réponse** dans un panneau : résumé en gras,
listes en **tableaux**, objets critiques (Domain Admins / tier-0) marqués 🔴.

```text
you › Profil de sécurité de sansa.stark, puis ses chemins vers le tier-0 ?
    ⚙ profil sansa.stark
    ↳ profil SANSA.STARK@NORTH.SEVENKINGDOMS.LOCAL · tier-0 à 1 saut
    ⚙ chemins tier-0 depuis sansa.stark
    ↳ 3 chemins
╭─ réponse ─────────────────────────────────────────────────╮
│  🔴 sansa.stark : kerberoastable + unconstrained deleg,    │
│  1 saut du tier-0 (domaine NORTH via CoerceToTGT).         │
│  … (tableau des attributs + chemins) …                     │
╰────────────────────────────────────────────────────────────╯
    ⟳ 4 tours · 14s · $0.12
```

### Contexte & langue

- **Contexte** : le **REPL** et **Claude Code** gardent le fil d'une question à l'autre.
  Chaque `-q` (Python) est en revanche un processus **indépendant** ; pour enchaîner des
  `-q`, ajoute **`-c`** (continue la session), `--new` pour repartir de zéro.
- **Langue** : par défaut, réponse dans la langue de la question. Forcer avec
  `--lang fr` (Python) ou `BH_LANG=fr` (voir Configuration).

---

## Configuration

Variables d'environnement (ou fichier `.env` — voir `.env.example`) :

| Variable | Rôle | Défaut |
|---|---|---|
| `NEO4J_URI` · `NEO4J_USER` · `NEO4J_PASSWORD` | Connexion Neo4j | `bolt://localhost:7687` · `neo4j` · `bloodhoundcommunityedition` |
| `BH_MODEL` | Modèle Claude | `sonnet` |
| `BH_LANG` | Langue des réponses (`auto` / `fr` / `en`) | `auto` |
| `BH_MAX_ROWS` · `BH_QUERY_TIMEOUT` | Cap lignes · timeout requête (s) | `1000` · `30` |
| `BH_SHOW_ROWS` | Afficher les lignes brutes en table | `0` |
| `BH_AUDIT` | Journal `runs/audit.log` | `1` |

## Sécurité

- **Lecture seule** : un validateur (`agent/guardrails.py`) rejette toute requête
  d'écriture ; l'agent n'a pas accès au shell ni aux fichiers de la machine.
- **Audit** : chaque Cypher exécuté est tracé dans `runs/audit.log` (`BH_AUDIT=0` pour
  désactiver).
- **« owned »** est stocké côté application (`runs/owned.json`), jamais écrit en base.
- **Garantie stricte (optionnelle)** — Neo4j Community n'a pas de vrai compte read-only.
  Après ingestion, verrouille la base :
  ```bash
  docker compose -f docker-compose.yml -f docker-compose.readonly.yml up -d graph-db
  ```
  (à ne PAS activer pendant l'ingestion ; reviens avec `docker compose up -d graph-db`).
- Ports Docker bindés sur `127.0.0.1` uniquement. Données d'un test **autorisé** / labo.

## Dépannage

| Symptôme | Solution |
|---|---|
| `Cannot connect to the Docker daemon` | Docker pas lancé. Ouvre Docker Desktop / OrbStack. |
| `Cannot reach Neo4j at bolt://…` | Bases éteintes : `docker compose up -d`, vérifie `docker compose ps`. |
| L'agent dit **0 node** / vide | Données pas (encore) chargées — attends ~30 s après l'import. |
| `port is already allocated` (7687/8080) | Un service occupe le port. Arrête-le ou change le port dans `docker-compose.yml`. |
| `OAuth session expired` | Relance `claude` (il redemande la connexion) ou `claude login`. |
| `ImportError: cannot import name 'pa'` (Neo4j) | Python 3.14 + Neo4j trop récent — déjà épinglé dans `requirements.txt`. |
| `bloodhound` reste `Restarting` | `docker compose logs bloodhound` ; sinon `docker compose down -v` puis `up -d`. |
| Mot de passe admin oublié | `docker compose down -v` puis `up -d` régénère un mot de passe (dans les logs). |

## Comment ça marche

```
extract JSON SharpHound (.zip)
      │  (import via BloodHound CE)
BloodHound CE  ──▶  Neo4j (graphe, bolt :7687)
                          ▲
                          │ Cypher lecture seule (audité)
         ┌────────────────┴─────────────────┐
   serveur MCP « bloodhound »        agent Python (Claude Agent SDK)
   (Claude Code / Desktop / plugin)  (REPL + one-shot)
        └──── mêmes outils : profils, chemins edge-filtrés,
              catalogue de requêtes vérifiées, owned… ────┘
```

BloodHound CE calcule tous les liens à l'import ; l'agent interroge le graphe. Claude
choisit lui-même les outils, itère et rédige — un vrai agent _tool-use_. Deux frontaux
partagent les mêmes outils : le serveur MCP (Claude Code / Desktop / plugin) et l'agent
Python (REPL / scripting).

## Arrêter / nettoyer

```bash
docker compose down        # arrête (garde les données)
docker compose down -v     # arrête ET efface les données
```

## Développement

```bash
pip install -r requirements-dev.txt     # ou: pip install -e ".[dev]"
pytest -q                               # unitaires (intégration auto-skippée)
BH_TEST_NEO4J=1 pytest -q               # + intégration (Neo4j chargé requis)
claude plugin validate . --strict       # valide le plugin / marketplace
```

## Structure du projet

```
bloodhound                    lanceur : démarre tout + ouvre Claude Code
setup.sh                      bootstrap 1re fois (installe + option données démo)
docker-compose.yml            bases BloodHound CE (Neo4j + PostgreSQL + appli)
docker-compose.readonly.yml   overlay lecture seule stricte (optionnel)
scripts/ce_ingest.py          import headless (.json et/ou .zip) via l'API CE

.mcp.json  ·  CLAUDE.md        Claude Code en local (serveur MCP + instructions)
.claude-plugin/  ·  SKILL.md   plugin marketplace (manifestes + compétence)
bin/mcp-server.sh              lanceur MCP du plugin (bootstrap venv, sortie stderr)

agent/
  main.py         agent Python : REPL + one-shot (-q, -c, --export, --lang)
  mcp_server.py   serveur MCP standalone (Claude Code / Desktop / plugin)
  tools.py        outils exposés à Claude (profils, chemins, catalogue, owned…)
  queries.py      edges d'attaque + catalogue de requêtes vérifiées
  neo4j_client.py accès Neo4j lecture seule (+ audit)
  guardrails.py   blocage des requêtes d'écriture
  render.py       affichage type chat (tableaux, couleurs, 🔴)
  report.py       export d'un rapport markdown
  audit.py        journal des requêtes  ·  owned.py  ensemble « owned »
knowledge/        schéma BloodHound + recettes Cypher + Azure (contexte de l'agent)
tests/            tests unitaires + intégration
```

TDQS

B3/5.0

Scored across 23 tools

Disambiguation5/5

Each tool targets a distinct operation: generic graph access (get_schema, run_cypher, search_object, node_details), prebuilt vulnerability queries (kerberoastable, dcsync, rbcd, etc.), path analysis (shortest_path, paths_to_tier0, blast_radius), and ownership tracking (mark_owned, list_owned, paths_from_owned). Even related path tools differ in starting point and goal, so no two tools are easily confused.

Naming Consistency4/5

All names use snake_case and are short, but the pattern is mixed: some are verb-led (get_schema, search_object, mark_owned), others are noun-led or technique names (domain_admins, kerberoastable, dcsync). This is a minor deviation from a strict verb_noun convention, but it remains readable and predictable within the BloodHound domain.

Tool Count4/5

With 23 tools, the server is on the heavier side of the ideal range, but BloodHound's broad feature set (generic queries, attack paths, delegation checks, ownership) justifies the count. Each tool serves a distinct, practical purpose without redundant entries.

Completeness4/5

The server covers core BloodHound workflows: arbitrary read-only queries, node lookups, common attack vector detection, path analysis, and owned-object management. Some expected operations like direct group membership listing or session hunting are absent, but run_cypher allows agents to work around these gaps, so the surface is not severely incomplete.

Maintenance

ActivitySlowing
ResponsivenessNo issues