SadProcessor here, happy to be back on the Insinuator to share with you some of my latest BloodHound adventures and experiments…
TL;DR Well too bad for you…
Before diving into a bit of code and some BloodHound data manipulation,
I would like to thank the BruCon Crew for having me over last week for BruCON0x0B.
I had the pleasure of delivering a 4h BloodHound & Cypher workshop in the lovely city of Gent [in a fantastic training room], and I am pleased with the interaction & feedback I had with the attendees.
I was also very happy to see almost as many Blues as Reds in the room [as well as regular security folks!!], all together having a play with BloodHound & Cypher.
BloodHound was originally designed out of a red team’s need for an AD reconnaissance tool allowing to quickly find attack paths to desired targets during engagements. And it does a great job at it.
But putting BloodHound in the hands of Blue Teams and Security Consultants can help greatly reduce the attack surface before the Red Team comes into play. This will only add value to your red team exercises.
If your car has really old tires, you don’t really need a crash test dummy to come and confirm you wont survive the crash…
I believe BloodHound is great tool for AD auditing in general, and in this post I will share a simple technique that I have successfully used on AD Hardening projects in order to quickly identify sensitive nodes in the BloodHound graph, domain-wide and at scale… and this without even looking at the graph.
Before getting into some PowerShell, I will quickly explain what we are going to do with a simple example.
Let’s say we have the following pseudo-graph in BloodHound:
What we are looking at is actually an overlapping equivalent of the following:
Once we look at it this way, we can easily count how many times a node appears on the total number of path to a specified target…
Doing so gives us a kind of weight for each node on the graph, and we can calculate which node have the most impact on the total number of paths to a specific target.
To achieve this type of data manipulation in Bloodhound “without looking”, you can use the REST API and a bit of Cypher wrapped in the scripting language of your choosing [I chose PowerShell so it runs everywhere… just like BloodHound].
First we will authorize unauthenticated requests to the REST API by uncommenting the following line in neo4j.conf
Note: This other setting being commented restricts it to localhost only [and this is what we want].
Please make sure to consider all security implications of having an open BloodHound database on your network before uncommenting this line.
If this is not for your lab or for localhost only, make sure to implement some kind of authentication,
as you probably don’t want this to be an open-bar…
Once this is done, we can send Cypher to the REST API with the following PowerShell Code.
The REST API returns JSON, so the PowerShell Invoke-RestMethod Cmdlet [aka irm] is a perfect tool for the job… It will automatically convert it to a nice object for you, and you can simply dot properties to expand objects and manipulate them further
[Instructions for calls in Bash or Python can be found here if you prefer [but c’mon bruh…dat PoSh…]]
Using this snippet, I have written a small Cmdlet called Invoke-Cypher that you can use to send any Cypher query to neo4j REST API [and build all kinds of automation around it].
An example of requesting a specific Node would look something like this:
The Node type [aka Label] is in $Node.metadata, and all Node properties are in $Node.data
And you can of course change the Cypher query to anything you like… So let’s get back to some BloodHound…
In the following example we are requesting shortest User paths to DA [any-to-one].
We can do so by sending the following query:
[Path from any user to a specific group with any types of edges and with no max length]
and this is what [one of] the returned Path Object looks like.
Notice how some data is returned in the form of URLs.
More calls [irm] to the REST API are then necessary to request these objects.
[but we will leave it for now… more on this later]
In our example, the returned result was a collection 33 objects, so we have 33 unique users with a path to our target
Same as on the overlapping BloodHound Graph [count if you like…]
The interesting bit for our experiment is the nodes property of these objects returned.
When we expand this with $PathCollection.Nodes, PowerShell gives us a list of all the nodes on all the paths.
Nodes are repeated in the list the number of times that they are present in total [like on the ‘non-overlaping’ graph], and using the Group-Object PowerShell Cmdlet we can very simply count them and get this weight we wanted to calculate…
If you followed carefully so far, you might have noticed that node with a count of 33 already…
And you might have guessed this is our target node [here the DA group], since that’s the one that is on all the 33 path we collected.
[472 is the neo4j DB internal object ID. You can also find it in the metadata of the node object itself]
We can now make those calls to the REST API to get the node info, but we already have the weight we were looking for, and we will have to make less calls to get he rest of the info since each node will only be called once [I had to learn this the hard way when testing this in very large envs…]
Anyways, and getting back to that cool active directory auditing technic I mentioned,
I have put all this into a little set of Cmdlet called WatchDog [just a POC for now and still a work in progress]
I have had good results while testing this at customers, but the scale of the AD environment can however be an issue for my code, as the powerShell Group-Object can become a bottleneck for performance when dealing with a lot of paths …
So I added a limit [in Cypher] to the first 10000 shortest paths by default [which should be way enough in most cases] but you can modify it as a Cmdlet parameter if you need.
The first Cmdlet is Invoke-DataDog [a wrapper around Invoke-Cypher].
Function sends several Cypher queries to BH and formats returned result.
You give it a Group name, and it will do the number crunching for you.
The NodeWeight Property of the result object holds Distance, Weight, and Impact [pct of ttl weight] for each node, as well as node type [label].
The second Cmdlet is Invoke-WatchDog [a wrapper around Invoke-DataDog].
You give it a domain name, and it will look for a list of known DA equiv or sensitive groups [RegEx on SID],
it will do the DataDog thing for you, and output an object per group, holding all the data we need for further investigation.
There is finally an Invoke-ReportDog Cmdlet that will generate a brief human-readable summary of the extracted data.
You can simply pipe DataDog or WatchDog output into it and it will create a mini text report for further analysis and deeper investigation [with CypherDog for example…].
A ‘Total Impact‘ is calculated at the end of the report [there’s also a TotalImpact Cmdlet you can pipe Watchdog output into, but I can’t explain everything here… check it out]
This toolset is just a POC, I have tried to optimize performance but I’m sure better can be achieved.
The technic used is of course not solid steel, but it is a cool way to interact with the BloodHound DB, identify key nodes on the path to sensitive groups, and get some global AD metrics out of it at scale.
I hope some of you will find this useful and want to dig deeper into BloodHound & Automation and this also for usage out of the pure Red Team context…
If you are interested in Active Directory Security in general [and are a German speaker], join us at the ERNW-Insight AD Summit on the 19Nov. in Heidelberg for a full day of AD goodness…
[And don’t forget Troopers is also coming fast… we plan to have an amazing AD track there too… and Rachelle & the Crew are already working hard at making it the best year ever… Be there.]
That’s all I had to share for today…
Thanks for reading…
Code for the WatchDog Cmdlets can be found here.
[Material for the Hands-On BloodHound Workshop can be found there if you like]
Catch me on BloodHound Slack if you have any questions or remarks.
Enjoy the weekend, and Make the world a Safer Place…