
Votre outil compagnon de terminal basé sur des modèles pour BloodHound

Une application terminal Python3 qui contient des cyphers Neo4j pour les ensembles de données BloodHound, avec un script pour automatiser leur importation dans BloodHound CE.
Terminal

Rapport HTML

Rapport HTML (suite)

BloodHound est un outil incontournable pour tout testeur d'intrusion. Cependant, sa conception présente certains inconvénients. Je vais couvrir les principaux points douloureux que j'ai rencontrés et ce que cet outil vise à résoudre :
JSON exportés, j'ai besoin des résultats de graphe au format ligne par ligne .txt pour réellement attaquer à partir d'autres outilsCet outil peut apporter une valeur significative tant pour les équipes rouges que bleues.
Reprenez le contrôle de vos données BloodHound avec CypherHound !
grep/cut/awkcustomqueries.json BloodHound Legacy vers BloodHound CE inclusAssurez-vous d'avoir python3 installé et exécutez :
python3 -m pip install -r requirements.txt
Démarrez le programme avec : python3 cypherhound.py -c config.json -y queries.yaml
Le programme lit un fichier de configuration au format json. Un exemple de ce fichier est présenté ci-dessous :
{
"user": "neo4j",
"pwd": "password",
"database": "neo4j"
}
où :
user est votre nom d'utilisateur Neo4jpwd est votre mot de passe Neo4jdatabase est votre base de données Neo4jLe programme lit les requêtes à partir d'un fichier YAML au format ci-dessous. ad-queries.yaml est fourni comme exemple contenant des requêtes liées à Active Directory. msg_template n'est pas requis pour les requêtes de chemins les plus courts, mais elles doivent renvoyer la variable contenant le chemin.
queries:
- group: general
desc: List all AddKeyCredentialLink privileges for owned principals
cypher: |-
MATCH (n {owned: true})-[r:AddKeyCredentialLink]->(m)
RETURN n.name AS n_name, m.name AS m_name, labels(m) AS labels_m, labels(n) AS labels_n
ORDER BY n.name
msg_template: |-
{{ n_name }} ({{ labels_n[0] }}/{{ labels_n[1] }}) has AddKeyCredentialLink over {{ m_name }} ({{
labels_m[0] }}/{{ labels_m[1] }})
Un tableau détaillant les paires clé/valeur est présenté ci-dessous :
params.*)Le programme utilise Jinja2 pour interpréter les cyphers. Définissez des paramètres d'exécution avec la commande set et référencez-les dans le YAML comme {{ params.<key> }}.
CLI
set <key> <value...> # p. ex. set user [email protected]
unset <key> # optionnel
show # optionnel
Exemple YAML
- group: user
desc: List all privileges for this user
cypher: |-
MATCH (n:User)-[r]->(m)
WHERE n.name =~ '((?i){{ params.user }})'
RETURN n.name AS n_name, TYPE(r) AS rel_type, labels(m) AS labels_m, m.name AS m_name
ORDER BY TYPE(r)
msg_template: |-
User {{ n_name }} has {{ rel_type }} over {{ m_name }} ({{ labels_m[0] }}/{{ labels_m[1] }})
Modèles de paramètres courants
Ce dépôt fournit un script query-importer.py pour automatiser l'importation des requêtes dans l'interface BloodHound CE à partir d'un fichier JSON. bh_query_converter.py est également fourni pour convertir un fichier YAML destiné à l'application terminale vers le format JSON attendu par query-importer.py et BloodHound CE. Un exemple du format JSON requis est présenté ci-dessous :
{
"queries": [
{
"name": "List all AddKeyCredentialLink privileges for owned principals",
"description": "List all AddKeyCredentialLink privileges for owned principals - General",
"query": "MATCH p=(n {owned: true})-[r:AddKeyCredentialLink]->(m)\nRETURN p\nORDER BY n.name"
},
{
"name": "List all AddKeyCredentialLink privileges for Users, Domain Users, Authenticated Users, and Everyone groups",
"description": "List all AddKeyCredentialLink privileges for Users, Domain Users, Authenticated Users, and Everyone groups - General",
"query": "MATCH p=(n:Group)-[r:AddKeyCredentialLink]->(m)\nWHERE (n.objectid =~ \"(?i)S-1-5-21-.*-513\" OR n.objectid =~ \"(?i).*-S-1-5-11\" OR n.objectid =~ \"(?i).*-S-1-1-0\" OR n.objectid =~ \"(?i).*-S-1-5-32-545\")\nRETURN p\nORDER BY n.name"
}
]
}
Le menu complet des commandes est présenté ci-dessous :
Documented commands (use 'help -v' for verbose/'help <topic>' for details):
======================================================================================================
alias Manage aliases
clear Clear the terminal.
cls Clear the terminal.
edit Run a text editor and optionally open a file with it
export Run a query and save its results
help List available commands or provide detailed help for a specific command
history View, run, edit, save, or clear previously entered commands
list List queries by group.
macro Manage macros
report Run multiple queries and generate a HTML report
run Execute a query
run_pyscript Run a Python script file inside the console
run_script Run commands in script file that is encoded as either ASCII or UTF-8 text
search Full-text search through stored queries.
set Set a dynamic search parameter (set <TARGET> <VALUE...>)
shell Execute a command as if at the OS prompt
shortcuts List available shortcuts
show Show dynamic search parameters
unset Unset a dynamic search parameter (unset <TARGET>)
Undocumented commands:
======================
exit q quit stop

Le script query-importer.py automatise l'importation des requêtes dans l'interface BloodHound CE à partir d'un fichier JSON. bh_query_converter.py est également fourni pour convertir un fichier YAML destiné à l'application terminale vers le format JSON attendu par query-importer.py et BloodHound CE.
Ce script convertit un fichier YAML destiné à l'application terminale en fichier JSON pour une importation facile dans BloodHound CE via le script query-importer.py. ad-queries.json est fourni comme exemple de ce à quoi ressemble un fichier de sortie et est prêt à être utilisé avec query-importer.py et l'importation des requêtes dans BloodHound CE.
Ce script lit un fichier customqueries.json de BloodHound Legacy et importe toutes les requêtes dans la nouvelle version de BloodHound Community Edition avec vos identifiants API. Il est fourni pour que les requêtes que vous avez créées pour BloodHound Legacy puissent encore être utilisées avec Community Edition.
Ce script supprime toutes les requêtes enregistrées de BloodHound afin de réinitialiser pour de futures importations. Il est destiné à BloodHound CE.
Ce script lit une liste de noms de nœuds à partir d'un fichier .txt et les marque comme possédés (owned) ou de grande valeur (high-value) dans la base de données.
Utilisation
Pour utiliser le script, vous devez préparer deux fichiers :
.txt ligne par ligne contenant les noms de nœuds au format BloodHound
[email protected][email protected]COMPUTER.DOMAIN.LOCALjson contenant votre nom d'utilisateur, mot de passe et base de données Neo4j (exemple ci-dessus)Le script propose les options suivantes :
-h, --help show this help message and exit
-c CONFIG, --config CONFIG
Config file
-l LIST, --list LIST List of node names
-o, --owned Set target nodes as owned
-v, --high-value Set target nodes as high-value
Vous devez spécifier au moins -o ou -v.
Ce script importe les requêtes enregistrées de la SpecterOps BloodHoundQueryLibrary dans BloodHound Community Edition via l'API BloodHound CE.
Queries.json / Queries.zipQueries.json / Queries.zipplatforms (insensible à la casse)/api/v2/saved-queries)429) utilisant Retry-After si présentSpecterOps publie
Queries.jsonetQueries.zipcomme artefacts de version (non stockés dans le dépôt). Les URL de téléchargement de la dernière version sont :
https://github.com/SpecterOps/BloodHoundQueryLibrary/releases/latest/download/Queries.jsonhttps://github.com/SpecterOps/BloodHoundQueryLibrary/releases/latest/download/Queries.zip
Utilisation (fichier local)
python3 scripts/bhql/query-importer.py \
--token-id "<TOKEN_ID>" \
--token-key "<TOKEN_KEY>" \
--queries-file "/path/to/Queries.json" \
--base-url "http://127.0.0.1:8080"
Utilisation (URL directe)
python3 scripts/bhql/query-importer.py \
--token-id "<TOKEN_ID>" \
--token-key "<TOKEN_KEY>" \
--queries-url "https://github.com/SpecterOps/BloodHoundQueryLibrary/releases/latest/download/Queries.json" \
--base-url "http://127.0.0.1:8080"
Utilisation (auto : dernière version)
python3 scripts/bhql/query-importer.py \
--token-id "<TOKEN_ID>" \
--token-key "<TOKEN_KEY>" \
--bhql-latest \
--base-url "http://127.0.0.1:8080"
Importation filtrée par plateforme (exemples)
# Importer uniquement les requêtes qui prennent en charge Active Directory
python3 scripts/bhql/query-importer.py \
--token-id "<TOKEN_ID>" \
--token-key "<TOKEN_KEY>" \
--bhql-latest \
--platforms "Active Directory" \
--base-url "http://127.0.0.1:8080"
# Importer les requêtes pour plusieurs plateformes (une correspondance suffit)
python3 scripts/bhql/query-importer.py \
--token-id "<TOKEN_ID>" \
--token-key "<TOKEN_KEY>" \
--bhql-latest \
--platforms "Active Directory" "Azure" \
--base-url "http://127.0.0.1:8080"
Astuce : Vous pouvez créer un jeton dans BloodHound CE et utiliser son Token ID/Key ici. Si vous souhaitez « repartir de zéro » avant d'importer, utilisez le script de purge inclus (voir
scripts/bloodhound-ce/purge-queries.py).
Reformate un fichier YAML de requêtes BloodHound existant pour que :
Si vous ne voyez pas la fonctionnalité cypherhound fusionnée dans le dépôt original DPAT, veuillez accéder à mon fork DPAT qui l'inclura.
Ce script analyse une exportation brute depuis l'application terminale, spécifiquement le cypher pour lister toutes les appartenances aux groupes utilisateurs, à titre d'exemple de la façon dont la sortie de cet outil peut être analysée. Vous passerez cette exportation comme paramètre au script, ainsi qu'un fichier NTDS.dit et un répertoire de sortie. Il produira alors des fichiers .txt dans le répertoire de sortie pour chaque nom de groupe avec des entrées au format DOMAINE\UTILISATEUR, compatibles avec DPAT. Vous passerez ensuite ce répertoire avec l'argument -g à DPAT, permettant à l'opérateur de produire des statistiques spécifiques à chaque groupe de domaine.
Pour utiliser le script, vous devez préparer deux fichiers :
NTDS.dit avec des lignes au format suivant : domaine\utilisateur:RID:LMhash:NTLMhash:::Utilisation
usage: parse-memberships.py [-m MEMBERSHIPS_FILE] [-d DOMAIN] [-n NTDS_FILE] [-o OUTPUT_DIR] [--netbios NETBIOS] [--encoding ENCODING]
[--debug] [--no-index] [-h]
Map users to groups from memberships file and match against NTDS dump.
options:
-m, --memberships-file MEMBERSHIPS_FILE
Path to memberships file (BloodHound-style lines) (default: None)
-d, --domain DOMAIN FQDN domain (e.g., EXAMPLE.COM) used in the membership regex (default: None)
-n, --ntds-file NTDS_FILE
Path to NTDS dump (DOMAIN\user:hash or pwdump-style) (default: None)
-o, --output-dir OUTPUT_DIR
Directory to write per-group output files (default: None)
--netbios NETBIOS NETBIOS/short domain to prefix when NTDS lines lack a domain (pwdump) (default: None)
--encoding ENCODING Encoding for input files (default: cp1252)
--debug Enable verbose debug output (default: False)
--no-index Name group files after the group instead of numbered files (unsafe chars replaced) (default: False)
-h, --help Show this help message and exit
Ce script analyse l'exportation brute pour lister tous les utilisateurs kerberoastables, fait correspondre les utilisateurs avec les entrées d'un NTDS.dit, et produit un fichier de sortie contenant toutes les entrées de hach des utilisateurs kerberoastables du dump. Vous passez ensuite ce fichier de sortie à DPAT avec l'option -kz pour fournir des statistiques sur les comptes kerberoastables crackés.
Utilisation
usage: parse-kerberoastable.py [-k KERB_FILE] [-n NTDS_FILE] [-d DOMAIN] [-o OUTPUT] [--encoding ENCODING] [--debug] [-h]
Match kerberoastable usernames against an NTDS.dit dump file
options:
-k, --kerb-file KERB_FILE
Path to Kerberoast output file (default: None)
-n, --ntds-file NTDS_FILE
Path to NTDS dump file (default: None)
-d, --domain DOMAIN Domain (e.g., EXAMPLE.COM) for regex matching (default: None)
-o, --output OUTPUT Path to write matches (default: None)
--encoding ENCODING File encoding to use when reading input files (default: cp1252)
--debug Enable verbose debug output (default: False)
-h, --help Show this help message and exit
Neo4j par défautBloodHound 4.3.1 ; certaines arêtes ne fonctionneront pas pour les versions antérieuresLe 15 juillet 2023, j'ai décidé d'apporter quelques modifications au projet. Après cette date, ce projet sera toujours maintenu une version en retard sur la version privée destinée aux sponsors. Assurez-vous de me sponsoriser pour accéder aux derniers cyphers, fonctionnalités et correctifs. En me sponsorisant à ce niveau, vous aurez également accès à des dépôts privés supplémentaires que je n'ai pas encore rendus publics !
AzureSoyez descriptif avec tout problème que vous ouvrez et, si possible, fournissez une sortie (le cas échéant).
| Clé | Description |
|---|
group | Le groupe auquel cette requête appartient ; les groupes sont définis par l'utilisateur, p. ex. "general" |
desc | La description de la requête |
cypher | La requête elle-même au format Neo4j |
msg_template | Template Jinja2 pour la sortie terminal basé sur les variables cypher, utilisez des alias pour les variables Neo4j afin d'éviter que Jinja tente de les interpréter comme des variables imbriquées |
| Clé param | Exemple de valeur | Utilisation dans le cypher |
|---|
params.user | [email protected] | = {{ params.user }} |
params.user_regex | (?i)john\.doe(@example\.com)? | =~ '{{ params.user_regex }}' |
params.group | Domain [email protected] | = {{ params.group }} |
params.prefix | ACME- | STARTS WITH {{ params.prefix }} |