TIP
Lately I've found that using bloodhoundcli is really easy to use. But below I've included some instructions to manually get BloodHound Community up and running.
BloodHound Community
Install BloodHound Community edition
Reference the custom install for more information.
# Download BloodHound
git clone https://github.com/SpecterOps/BloodHound
# Make a BH directory
mkdir bhce
cd bhce
# Download config files
curl -L -O https://raw.githubusercontent.com/SpecterOps/BloodHound/refs/heads/main/examples/docker-compose/docker-compose.yml
curl -L -O https://raw.githubusercontent.com/SpecterOps/BloodHound/refs/heads/main/examples/docker-compose/bloodhound.config.json
In docker-compose.yml, look for:
- bhe_graph_driver=${GRAPH_DRIVER:-neo4j}
Change neo4j to pg.
Then startup with:
sudo docker-compose up
If you need to do maintenance, shut stuff down with:
sudo docker-compose down
If for some reason you don't get an admin account generated when Docker fires up, take the instance down, and then edit docker-compose.yml and adjust this line so that recreate_default_admin=-true:
- bhe_recreate_default_admin=${bhe_recreate_default_admin:-false}
Parse list of machine names from a cypher query
This used to work on the old (non-Community) edition when you needed to grep a list of endpoints affected by a specific query to create a nice, clean list of machines (one per line). I need to test against Community:
grep -o '"label":"[^"]*"' machine-names.json | cut -d':' -f2 | tr -d '"' | uniq | sort -V
Or it might be this one:
cat comps.json | jq '.data[].Properties.name' | sed 's/"//g' | sort -f > allmachines.txt
This script pulls computer names and dates and converts from Unix timestamp with newest date at the top
jq -r '.data | sort_by(.Properties.whencreated) | reverse[] | "\(.Properties.name) \(.Properties.whencreated | todate)"' 20240918113133_computers.json
Get a list of all users that have a non-empty description (h/t BusyR)
cat *_users.json | jq -r ' .data[].Properties | select ( .enabled == true) | select (.description != null) .name + ":" + .description' | tee users_with_description.txt
Create a txt file with all enabled users (h/t BusyR)
cat *_users.json | jq -r ' .data[].Properties | select ( .enabled == true) | .samaccountname' | tee users.txt
Reset BloodHound password
See this BloodHound Slack advice. You could also go "nuclear" with the next section:
Delete all BloodHound containers and images and start over
Sometimes my BloodHound doesn't seem to start smoothly and/or hangs weirdly so I do the following when my body is filled with rage:
DANGER
I'm ok with this "nuclear" option because my BH VM has nothing but BH on it. So uhh...maybe don't run this stuff if you have docker-y things on your system you care about.
docker rm desktop_app-db_1
docker rm desktop_bloodhound_1
docker rm desktop_graph-db_1
docker rmi neo4j:4.4
docker rmi postgres:16
docker rmi specterops/bloodhound
docker system prune --volumes --force
Admin session enumeration explained
Sometimes I get confused about how local admin sessions are enumerated. A fine friend from the BloodHound Slack clarified:
Assuming you collected with SharpHound collection method All, SharpHound will attempt to collect local groups directly from the hosts in scope. That requires admin rights by default however. It will fallback to creating AdminTo edges based on GPO settings. I believe there is an edge property that reveals if the edge is based on GPO. These edges may be false positives as BloodHound does not take GPO filtering into account, for example
Queries
The BloodHound Query Library is the place to go for good BH queries, but here's a few I like.
Find all computers without SMB signing
MATCH (n:Computer)
WHERE n.smbsigning = False
RETURN n
Find computers with WebClient
MATCH (c:Computer)
WHERE c.webclientrunning = True
RETURN c LIMIT 1000
Find computers with WebClient AND with live sessions
match p=(U:User)<-[:HasSession]-(C:Computer)
where C.webclientrunning = True
return p limit 1000