15/11/2024

Gestion et configuration des conteneurs BloodHound

Dans ce chapitre, nous allons passer en revue un peu plus en détail la configuration de BloodHound tel que nous venons de l'installer. L'installation simple suffit pour une première découverte, mais il est quand même utile de savoir où et comment sont gérés les conteneurs et leurs configurations (port d'exposition, stockage des données, etc.).

I. Gestion du cycle de vie des conteneurs

Pour créer et démarrer pour la première fois BloodHound, nous avons utilisé la commande "docker-compose". Lorsque vous exécutez cette commande dans un répertoire donné, par défaut, elle y recherche un fichier nommé "docker-compose.yml" ou "docker-compose.yaml". Si votre fichier de configuration à un nom différent ou se situe dans un autre répertoire, vous pouvez spécifier son nom en utilisant l'option "-f" ou" --file". Par exemple :

docker-compose -f /home/user/Downloads/bloodhound.yml up

Également, vous pouvez stopper les conteneurs actifs de BloodHound avec la commande suivante :

docker-compose -f /home/user/Downloads/docker-compose.yml down

Voici le résultat attendu :

Résultat de la commande docker-compose down pour stoper BloodHound
Résultat de la commande "docker-compose" down pour stopper BloodHound.

Nous voyons ici que les trois conteneurs sont stoppés puis supprimés. Pas de panique, les données propres à BloodHound (base de données de l'application et Neo4j) sont stockées dans des volumes situés sur l'hôte et donc persistantes, comme nous allons le voir juste après dans la configuration YAML.

En cas d'arrêt brusque du système hôte, les conteneurs passent dans un état "Exited", vous pourrez alors les voir avec la commande suivante :

Utilisation de l'option "-a" de "docker ps" pour voir les conteneurs non actifs.
Utilisation de l'option "-a" de "docker ps" pour voir les conteneurs non actifs.

II. Étude du docker-compose

Commençons par regarder le contenu du fichier "docker-composer.yml", cela nous renseignera sur la configuration des 3 conteneurs utilisés pour faire tourner BloodHound :

version: '3'
services:
  app-db:
    image: docker.io/library/postgres:13.2
    [...]

  graph-db:
    image: docker.io/library/neo4j:4.4
    [...]

  bloodhound:
    image: docker.io/specterops/bloodhound:${BLOODHOUND_TAG:-latest}
    [...]

volumes:
  neo4j-data:
  postgres-data:

J'ai ici supprimé les commentaires et les détails de configuration pour comprendre la structure globale du fichier. Nous voyons ici la définition de trois conteneurs docker :

  • "app-db" utilisant une image Postgres;
  • "grap-db" utilisant une image Neo4j;
  • "bloodhound" utilisant une image Bloodhound.

Nous voyons également la déclaration de deux volumes ("neo4j-data" et "postgres-data") qui sont, sous docker, des espaces de stockage persistant utilisés par les conteneurs. Cela permet simplement à certaines données de continuer d'exister même si les conteneurs ne tournent plus ou sont supprimés. Vous l'aurez compris, ces données seront donc stockées sur le système hôte, qui exécute les conteneurs.

D'un point de vue sécurité, il est toujours bon de savoir exactement où sont stockées les données que l'on manipule, d'autant plus que les informations concernant les objets d'un Active Directory sont considérées comme sensibles. Dans le cadre d'un audit par exemple, les données manipulées sont celles du client, il convient donc d'être particulièrement vigilant quant à leur confidentialité et leur suppression en fin de prestation.

Sur un système Linux, vous pourrez trouver les deux volumes dans "/var/lib/docker/volumes" :

Visualisation des volumes des containers Bloodhound sur un système Linux
Visualisation des volumes des conteneurs Bloodhound sur un système Linux

Ces volumes sont également visibles via la commande suivante :

Liste des volumes sous docker
Liste des volumes sous docker

Bien sûr, à l'intérieur, nous y verrons les bases de données mentionnées dans les chapitres précédents. Si l'on regarde le détail des configurations de chaque conteneur à présent :

version: '3'
services:
  app-db:
    image: docker.io/library/postgres:13.2
    environment:
      - POSTGRES_USER=${POSTGRES_USER:-bloodhound}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-bloodhoundcommunityedition}
      - POSTGRES_DB=${POSTGRES_DB:-bloodhound}
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test:
        [
          "CMD-SHELL",
          "pg_isready -U ${POSTGRES_USER:-bloodhound} -d ${POSTGRES_DB:-bloodhound} -h 127.0.0.1 -p ${POSTGRES_PORT:-5432}"
        ]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

  graph-db:
    image: docker.io/library/neo4j:4.4
    environment:
      - NEO4J_AUTH=${NEO4J_USER:-neo4j}/${NEO4J_SECRET:-bloodhoundcommunityedition}
      - NEO4J_dbms_allow__upgrade=${NEO4J_ALLOW_UPGRADE:-true}
    ports:
      - 127.0.0.1:${NEO4J_DB_PORT:-7687}:7687
      - 127.0.0.1:${NEO4J_WEB_PORT:-7474}:7474
    volumes:
      - ${NEO4J_DATA_MOUNT:-neo4j-data}:/data
    healthcheck:
      test:
        [
          "CMD-SHELL",
          "wget -O /dev/null -q http://localhost:${NEO4J_WEB_PORT:-7474} || exit 1"
        ]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

  bloodhound:
    image: docker.io/specterops/bloodhound:${BLOODHOUND_TAG:-latest}
    environment:
      - bhe_disable_cypher_qc=${bhe_disable_cypher_qc:-false}
      - bhe_database_connection=user=${POSTGRES_USER:-bloodhound} password=${POSTGRES_PASSWORD:-bloodhoundcommunityedition} dbname=${POSTGRES_DB:-bloodhound} host=app-db
      - bhe_neo4j_connection=neo4j://${NEO4J_USER:-neo4j}:${NEO4J_SECRET:-bloodhoundcommunityedition}@graph-db:7687/
    ports:
      - ${BLOODHOUND_HOST:-127.0.0.1}:${BLOODHOUND_PORT:-8080}:8080
    depends_on:
      app-db:
        condition: service_healthy
      graph-db:
        condition: service_healthy

volumes:
  neo4j-data:
  postgres-data:

Nous pouvons notamment nous intéresser aux directives "ports", qui permettent de configurer les ports d'écoute de chaque service d'un conteneur (utile en cas de conflit avec d'autres outils/services de notre hôte). On peut également regarder la condition "depends_on" du conteneur "bloodhound", qui indique que le conteneur ne démarrera pas si les conteneurs "app-db "et "graph-db" ne sont pas fonctionnels.

Si tous vos conteneurs sont stoppés et que vous souhaitez, manuellement, démarrer le conteneur BloodHound, celui-ci ne démarrera pas :

Démarrage manuel des différents containers dans le mauvais ordre.
Démarrage manuel des différents conteneurs dans le mauvais ordre.

Il faut démarrer les deux autres avant (et attendre quelques secondes) :

Démarrage des conteneurs Docker dans le bon ordre
Démarrage des conteneurs Docker dans le bon ordre

Voilà ! Nous avons fait le tour des éléments que j'estime nécessaire à la manipulation (basique) de la petite infrastructure BloodHound que nous avons sous la main. Ce n'est pas la partie la plus intéressante lorsque l'on veut apprendre à jouer avec BloodHound. Mais croyez-moi, il vaut mieux avoir ces différents éléments en tête lorsque l'on est en pleine mission ou en pleine démonstration et qu'il arrive un pépin :).

author avatar
Mickael Dorigny Co-founder
Co-fondateur d'IT-Connect.fr. Auditeur/Pentester chez Orange Cyberdéfense.
Partagez cet article Partager sur Twitter Partager sur Facebook Partager sur Linkedin Envoyer par mail

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.