Intro

After several months of development and quality testing, we are proud to announce the release of BloodHound 3.0! With this release, we are including 3 new attack primitives, several performance improvements in the GUI and in SharpHound, and support for Neo4j 4.0.

Shout outs to the following folks who directly or indirectly made material contributions to this release: Tim McGuffin (@NotMedic), Michael Grafnetter (@MGrafnetter), Will Schroeder (@harmj0y), Lee Christensen (@tifkin_), Sean Metcalf (@PyroTek3), Dirk-jan Mollema (@_dirkjan), and Mark Gamache (@markgamacheNerd).

This is a major version release, which means we are introducing compatibility-breaking features with this release — SharpHound2 and your BloodHound 2.x databases will not be compatible with BloodHound 3.0, so make sure you are using the latest SharpHound. BloodHound 3.0 is compatible with Neo4j 4.0, and nodes are now uniquely identified by their SID, not by their name.

New Attack Primitives

With BloodHound 3.0, we are including three new attack primitives: GMSA control, OU control, and SID history. The configurations related to these new attack primitives are all readable, by default, by any domain-authenticated user, and each attack primitive is abusable with practical tooling. Attackers can find new attack paths that rely on these attacks to find previously unseen attack paths to DA (or whatever your objective may be), and defenders can use BloodHound to audit and remediate the same attack paths before an attacker can find and execute them.

Here’s how each new attack primitive works:

New Attack Primitive: GMSA control

Group Managed Service Accounts (GMSAs) are special service accounts in Active Directory that address many concerns around least privilege and credential hygiene. The passwords for GMSAs are managed by Domain Controllers, automatically changed every 30 days (by default), and comprised of 128 characters (read: impossible to guess).

The crux of GMSAs is that admins need to specify who is allowed to read the clear-text password for the GMSA. For example, let’s say our user Dwight Hohnstein can read the password for a SQL GMSA. In the BloodHound GUI, you may see this as an attack path from Dwight to the SQL computer:

If we can get ourselves into the context of the DHOHNSTEIN user, we can retrieve the clear-text password for GMSA-SQL01, and then laterally move to SQL01.CONTOSO.LOCAL. Several tools existed already for retrieving GMSA passwords, but none that would allow you to remain completely memory resident. For that reason, Rohan created GMSAPasswordReader, a C# capability for doing precisely what it sounds like: reading GMSA passwords. Here’s an example of using GMSAPassword.exe with Cobalt Strike’s execute-assembly function to retrieve the NT hash for GMSA-SQL01:

Now with the NT hash of the GMSA account’s password, you can impersonate the user (using, for example, overpass-the-hash) and laterally move to SQL01.CONTOSO.LOCAL.

For further reading on GMSAs, see Michael Grafnetter’s excellent writeup here.

New Attack Primitive: OU control

Every so often, AD administrators will define ACEs on OUs that apply to the OU itself, or the OU and descendent OUs, but not to descendent user, group, and computer objects. Historically, we had seen control of OUs through the lense of GPOs being linked to OUs, and the possibilities of linking evil GPOs to OUs that you control. There are several problems with that, most critically that you need to be able to stand up an evil GP server to correctly host your evil GP files — doing so through a command line has so far proven to be too difficult to accomplish practically. Then it hit us like a ton of bricks: with control of the OU, you can just push an ACE onto the OU that will inherit down to its descendent objects!

For example, let’s say Justin Bui has full control of our Workstation Admins OU, which contains the user object for Josh Prager:

The attack here is fairly simple: from the context of JBUI, we can add a new ACE to the Workstation Admins OU that will inherit down to JPRAGER. This is made practical by a great cmdlet in PowerView called New-ADObjectAccessControlEntry, written by Lee Christensen (@tifkin_). Once that new ACE is in place, we can abuse the JPRAGER user from the context of JBUI the same way we’ve been able to since the BloodHound 1.3 ACL update: reset his password, or do a targeted kerberoasting attack.

When you apply an ACE to an OU and set it to inherit down to descendent objects, you can choose to have it apply to all objects, objects of a certain class, and even control whether it applies to direct children of the OU or all descendents. For a full example of how to do generic or object-specific ACEs on an OU, see the edge help modal in the BloodHound GUI:

New Attack Primitive: SID history

Finally, we’re also including SID history as a new attack primitive in BloodHound 3.0. As a red teamer, you may first think of golden tickets that abuse the SID history functionality, but in fact we are looking at users, computers, and groups that already have SIDs listed out in the SIDHistory parameter on their object in AD. Those parameters may be legitimately populated when an object is migrated from one Active Directory domain to another — in order to maintain the rights and privileges held by that principal, the object in the new domain will contain the SIDs for any group that principal belonged to in the old domain.

For example, let’s say Josiah Massari’s user object was migrated to the CONTOSO domain from the FABRIKAM domain. In the FABRIKAM domain, Josiah belonged to the Workstation Admins group, which has local admin rights on all workstations in FABRIKAM. In the CONTOSO domain, the user object for Josiah will contain the SID for the Workstation Admins group in FABRIKAM. Now, whenever Josiah authenticates in the enterprise, his kerberos ticket will contain the SID for that group in the ExtraSIDs part of the ticket’s PAC, granting him all the same rights and privileges held by that group.

Bottom line: Josiah effectively remains a member of the Workstation Admins group in FABRIKAM, even though his user object doesn’t necessarily belong to that group anymore. For more details about this, see this excellent blog post from Sean Metcalf: Sneaky Active Directory Persistence #14: SID History.

In the BloodHound GUI, the above situation would look like this:

The abuse here is fairly straightforward. In fact, you can simply think of “HasSIDHistory” as you already think of the “MemberOf” edge. From the context of JMASSARI, you will have admin rights on both workstations in the FABRIKAM domain.

An extremely important caveat here: if the domain trust between the CONTOSO and FABRIKAM domains enforces SID filtering, this attack will not work, as the SIDs in the ExtraSIDs part of JMASSARI’s kerberos ticket PAC will be ignored by the FABRIKAM domain. For more information about SID filtering, see Will Schroeder’s excellent blog post, “A Guide to Attacking Domain Trusts”.

Performance Improvements

There are two major areas we’ve made big performance improvements in: data collection with SharpHound, and data import with the BloodHound GUI. On the SharpHound side, you should see about a 25 to 30% increase in speed for LDAP collection. Host collection is a little bit slower, but with a much better accuracy trade-off. The number of checks to attempts to resolve a host to the right value has increased dramatically from the previous version.

On the data import side, Rohan has completely rebuilt the JSON parsing and import logic, so dragging and dropping files into the GUI will be much, much faster.

If there’s enough interest, Rohan will describe in a future blog post the technical details of how he was able to achieve these speed improvements, as well as the updated methods of getting information from hosts.

Quality of Life Improvements

There are two major changes in how the GUI handles running hard queries, and how the GUI handles rendering graphs with many nodes and edges.

First, whenever you click on a node in the BloodHound GUI, the information tab for that node populates and starts displaying all sorts of information about that object:

Some of those queries are very easy for the database to handle, like getting “password last set” date and time from the user node, or even getting the number of computers a user has group delegated admin rights on. But some of those queries are actually quite expensive, especially as you start to work with databases above a certain size — say, more than 30,000 total nodes. Specifically, any usage of shortestPath() where the start or end node can be any other node (as opposed to a specific node) in the graph will put a huge amount of work on the database.

Historically, we would kick off 3 such queries every time you clicked a user node: derivative local admin rights, transitive object control, and transitive object controllers. We’re not removing those queries, though, we’re just changing the default behavior so that now instead of those queries running every time you click a user node (and putting an extreme amount of work on the database), you’ll have a little “play” button you can click to start that query:

Second, a big pain point with the BloodHound GUI has been with rendering very large graphs comprised of hundreds of nodes and edges. This is due to our reliance on free and open-source graph rendering libraries — all of which are constrained to rendering our graph layouts with the CPU, not the GPU. GPUs are, of course, orders of magnitude faster at rendering graphics than CPUs are, so this is a limitation that we currently had to find a way around, not through.

Our solution was to intercept the data coming back from neo4j, determine whether the amount of data is likely to cause the GUI to hang for a long time, and then provide the user with a choice of how to proceed:

“Cancel” will do exactly what you think. “Save Data” will give you a common dialogue window where you can save the raw graph data in JSON format. “Draw Graph” will proceed with attempting to render the edges and nodes like usual.

Conclusion

We hope you’ll enjoy this release of BloodHound 3.0 with increased performance, new attack primitives, and quality of life improvements. Remember: this is a major release and you must use the latest version of SharpHound as well: SharpHound3. We want to sincerely thank everyone in the beta channel in the BloodHound Slack for helping us test all the moving parts. We also want to again thank Tim McGuffin (@NotMedic), Michael Grafnetter (@MGrafnetter), Will Schroeder (@harmj0y), Lee Christensen (@tifkin_), Sean Metcalf (@PyroTek3), Dirk-jan Mollema (@_dirkjan), and Mark Gamache (@markgamacheNerd) for their direct and indirect contributions to this release. Thank you!

Not in the BloodHound Gang Slack? Get your invite here: https://bloodhoundgang.herokuapp.com/