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 :
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 :
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" :
Ces volumes sont également visibles via la commande suivante :
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 :
Il faut démarrer les deux autres avant (et attendre quelques secondes) :
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 :).