The OSCP Toolkit: BloodHound + RustHound-CE

You have a foothold. You ran NetExec, validated a credential, and watched NXC print that green [+]. Good. Now what?
Now you're standing in a domain with one low-priv account and no idea where it can take you. This is the exact moment BloodHound exists for. NetExec is how you get a credential. BloodHound is how you find out that credential owns the entire domain and just doesn't know it yet.
This chapter takes you end to end: collect the directory with RustHound-CE, spin up the BloodHound UI, import clean, mark what you own, read what that ownership actually gets you, and let the tool draw you a route from a nobody support account to the DC. We'll run the whole thing against HTB's Support box.
Let's map some paths.
Step one: you can't map what you haven't collected
Here's the thing that trips people up when they first meet BloodHound. BloodHound doesn't collect anything. It never touches the domain. It's a graph engine, not a scanner. Every bit of intel it draws was gathered before you ever opened the UI, by a separate tool called a collector.
The collector is the recon. BloodHound is just the map it draws from it.
So before we get anywhere near attack paths and Kerberoast queries and the shortest path to Domain Admins, we have to feed the thing. That takes two ingredients: a valid domain credential, and a collector to run with it.
Why you need creds first
You cannot point a collector at a domain controller and vacuum up the directory for free. Modern DCs don't allow anonymous LDAP binds, so AD won't tell you a single useful thing until you authenticate. No creds, no collection.
That's exactly why BloodHound sits where it does in the kill chain. It is not your opening move. It's what you fire the second you land a foothold, even the weakest one. One low-priv domain account is the entire entry fee.
NetExec is how you validate that first credential in the first place. The moment NXC prints a green [+], you're holding everything RustHound needs to start pulling the graph. On Support, our foothold is the ldap account, and with that one set of creds we can bind to LDAP and pull the whole directory down.
What the collector actually grabs
When RustHound-CE runs, it isn't just grabbing a user list. It's walking the entire directory and pulling two categories of things:
The nodes, meaning the objects that exist: users, groups, computers, OUs, GPOs, containers, and the domain itself.
The edges, meaning the relationships between them: group memberships, ownership, ACL rights like GenericAll, WriteDACL, WriteOwner, and ForceChangePassword, plus delegation settings and trusts. On top of that it reads the attribute flags that quietly announce an attack primitive, like an account carrying an SPN (Kerberoastable) or one set to not require preauth (AS-REP roastable).
The nodes tell you what exists. The edges tell you how to win. A flat list of 21 users is noise. The graph of who can reset whose password, and which nested group quietly rolls up into Domain Admins, is the actual attack path. That's the whole reason we bother collecting.
Two collectors, and knowing which to grab
Before you run anything, one decision: SharpHound or RustHound. They're not rivals so much as two tools for two situations, and picking the right one is the difference between a complete graph and one with blind spots.
Got a session on a domain-joined box? Reach for SharpHound.
SharpHound is the reference collector, the one BloodHound's data model was built around. When you're running from inside the domain with network reach to the hosts, it doesn't just talk to the DC over LDAP. It reaches out to the individual computers over SMB and RPC and scoops up the stuff that only lives on the machines themselves: who's logged in where, who's a local admin, who has RDP or DCOM or PSRemote rights on each box.
That host-side data is where the nastiest paths hide. A Domain Admin session sitting on a box you already own is a game-ender, and that edge only exists in the graph if your collector actually went and looked at the host. From a local foothold, SharpHound is the one that reliably catches it. External LDAP-only collection can miss it entirely.
Coming in from the outside with just a credential? RustHound-CE.
This is the Support scenario, and it's the more common OSCP one. You're on your Kali box, you've got one domain cred, and you want the directory. RustHound is LDAP-first and absurdly fast, and it does a pile of convenient things automatically that make it my pick for external collection over reaching for bloodhound-python or NXC's LDAP module.
For example, if your account can read LAPS passwords, RustHound reads them for you and hands the local admin password straight back in the collection output. No extra query, no separate tool. It's sitting in your loot the moment collection finishes. That one feature alone earns its spot in my book. One honest caveat: this is legacy LAPS. Windows LAPS, the newer v2, isn't supported by the collector yet, so don't assume silence means the box is clean.
It doesn't stop there. It also pulls ADCS certificate template and CA data, so if there's a vulnerable template lurking, the ESC path shows up in your graph ready for a Certipy chaser. There's an optional FQDN resolver to map computer names to IPs, and beta support for following domain trusts. For a tool you fire once and forget, it front-loads a surprising amount of the next three steps.
So: local access, SharpHound. External with creds, RustHound. On Support we're squarely in the second camp, so Rust it is.
RustHound-CE, the fast collector
SharpHound is the classic collector, the C# one everybody starts with. RustHound-CE is the Rust rewrite built specifically for BloodHound Community Edition, and it is stupid fast because it's LDAP-focused. You point it at the domain, it hammers the LDAP partitions, and it spits out BloodHound-ready JSON in seconds. For OSCP-style boxes where the directory data is what you're after, it's my go-to.
Here's the run against Support:
rusthound-ce -u ldap -p 'supersecurepass' -d support.htb -c All -z
Flag by flag:
-u ldap is the username we're authenticating as. On this box the account is literally named ldap.
-p 'supersecurepass' is the password. Quote it so the shell doesn't choke on special characters.
-d support.htb is the domain FQDN. Notice there's no IP or DC address here. RustHound resolves the controller through DNS, and it resolves because we already dropped support.htb into /etc/hosts back in chapter one. That banner-reading step wasn't busywork, it's what lets this command Just Work.
-c All tells RustHound to collect everything it can.
-z zips the JSON output into a single archive, ready to drag straight into BloodHound.
Reading the output
[INFO] Connected to SUPPORT.HTB Active Directory!
[INFO] Starting data collection...
[INFO] Ldap filter : (objectClass=*)
[INFO] All data collected for NamingContext DC=support,DC=htb
That filter, (objectClass=*), means give me everything. And it repeats that across every LDAP partition in turn:
DC=support,DC=htb is the domain partition, where your users, groups, and computers live. CN=Configuration holds forest-wide config, and it's worth caring about because ADCS enrollment services live in there if you ever go the Certipy route. CN=Schema is the object definitions. DomainDnsZones and ForestDnsZones are the AD-integrated DNS partitions. RustHound walks all five, then parses the pile.
One line to actually stop and read:
[INFO] MachineAccountQuota: 10
MAQ is 10. That means any authenticated user, including our lowly ldap account, can create up to ten machine accounts. Park that in the back of your head. Being able to create machine accounts can become extremely useful when an RBCD path appears later, since it hands you a computer principal you actually control. The collector handed you that on a plate before you even opened BloodHound.
Then the parse summary, your sanity check that collection actually worked:
21 users parsed!
61 groups parsed!
1 computers parsed!
1 ous parsed!
1 domains parsed!
2 gpos parsed!
73 containers parsed!
One computer, one domain. Support is a single DC, so that lines up. If those counts came back at zero, you'd know your bind failed or your creds are dead.
And the payload:
.//20260812230708_support-htb_rusthound-ce.zip created!
RustHound-CE Enumeration Completed! Happy Graphing!
Timestamped zip, done in about two seconds. That archive is the graph. Next we drag it into BloodHound CE and let it draw.
Step two: fire up the BloodHound UI
The graph is zipped and waiting. Now we need somewhere to drop it. BloodHound CE runs as a local web app, so starting it is one command:
bloodhound-start
It'll ask for sudo because it has to spin up two things, not one. BloodHound is a front end. Neo4j is the brain. Neo4j is the graph database that actually stores your nodes and edges and answers the path queries. BloodHound is just the UI that draws pretty pictures from it. The start script boots both:
Starting Neo4j.
Started neo4j (pid:3701). It is available at http://localhost:7474
That 7474 is Neo4j's own console. You don't need it. Ignore that port, it's the database talking to itself. Wait for the part you actually care about a few lines down:
[*] Web UI: http://127.0.0.1:8080
There it is. BloodHound lives at port 8080 by default. Open a browser and go to http://localhost:8080. If it looks blank or half-loaded the first time, refresh once, the backend sometimes needs a second to finish waking up.
First login is the classic:
user: admin
password: admin
That gets you straight in. Change the password once you're logged in, since a full map of the domain's attack paths isn't something you leave sitting behind admin/admin, but that's your call to make, not something the app nags you about. Then you're staring at an empty graph waiting to be fed.
Empty is expected. We haven't uploaded anything yet. That's step three.
Step three: feed the graph
Time to hand BloodHound the loot. Two things to square away before you upload, one cosmetic and one that will wreck your night if you skip it.
Rename the zip first
RustHound names its output like it's angry at you:
.//20260812230708_support-htb_rusthound-ce.zip
That timestamp-prefixed mess is fine, BloodHound doesn't care what it's called, but future-you digging through a folder of five of these absolutely will. Rename it to something you'll recognize. support-ce.zip, support-rusthound.zip, whatever keeps your engagements straight. Thirty seconds now saves you squinting at timestamps later.
Clear the last box before you import the next one
Quick clarification first, because you'll read conflicting things. BloodHound is designed to merge uploads into its existing database. That's intended behavior, not a bug. Repeated collections of the same domain, and related domains in the same forest, are supposed to coexist and enrich each other. Merging is a feature.
So this next bit isn't a fix for something broken. It's lab hygiene for how we practice. In HTB and OSCP prep you're working one unrelated box at a time, and Support has nothing to do with the box you rooted yesterday. If yesterday's data is still sitting in the database when you import Support, nothing gets corrupted, but you're now staring at a graph full of nodes and paths that have zero bearing on the target in front of you. That's just noise, and noise is the enemy when you're learning to read these graphs.
So for one-box-at-a-time practice, I clear the previous lab before importing the next. Go to Administration, then Database Management, and use the clear-database function to wipe it. Empty database, clean slate, and the only thing on screen is the box you're actually attacking. On a real engagement with related domains you'd leave the merge behavior alone and let it work for you. In the lab, one box in, one box out.
Upload it
Now the actual import. Over on the left, hit Administration, and under Data Collection you'll find File Ingest.
That's your upload point. Drop the renamed zip in, and BloodHound ingests it, unpacking all that JSON into Neo4j and stitching the nodes and edges into a live graph. Give it a moment to chew, and the counts you saw back in the RustHound output (21 users, 61 groups, the lone computer) become clickable, queryable, walkable.
There's a Quick Upload button up in the main menu that does the same job in fewer clicks once you know your way around. File Ingest is the scenic route that shows you what's actually happening, which is where you want to be while it's still new.
Confirming it landed
Head back to the File Ingest tab and check the status line. When the import worked, you'll see it plainly:
ID 130 Complete 7 Files 0 mins
Complete is the word you're looking for. Green dot, "Complete," and a file count that makes sense. RustHound zipped up seven JSON files, and seven is what BloodHound reports swallowing. Numbers match, no errors, we're good. The duration reading 0 mins isn't a bug, Support is a tiny single-DC domain, so ingestion is basically instant.
One thing worth knowing so it doesn't rattle you: sometimes ingest just faceplants for no reason. Status comes back failed, or canceled, no explanation, nothing wrong with your zip. It's a fluke.
Don't start debugging, don't re-run the collector, just hit upload again with the same file. Works about nine times out of ten on the second try. If it fails twice in a row, then start actually looking at it, but a single flukey failure is nothing to chase.
Green and complete? The graph is loaded and live. Now we hunt.
Step four: tell BloodHound what you own
The graph is loaded, but right now BloodHound is showing you the whole domain with no idea where you stand in it. Before you go hunting for paths, you have to plant your flag. You have to tell the tool which accounts you already control.
Head to Explore on the left menu. Up top you've got a Search bar. Type in the account you've compromised, your foothold user, and BloodHound will start matching nodes as you type. Click the name when it surfaces and the user pops onto the graph as a single node.
Now click that node icon and its action menu appears (if a plain click just highlights it, right-click to bring the menu up). You'll see a stack of options: Set as starting node, Set as ending node, Add to Tier Zero, and the one we want, Add to Owned.
What "owned" actually means
"Owned" is BloodHound's word for an account you control. Foothold creds, a cracked hash, a password you found in a share, a LAPS password RustHound handed you back in the collection. Anything you can authenticate as, you own. Marking it here tags the node with a little skull and, more importantly, writes it into BloodHound's brain as a starting point you already possess.
That second part is the whole point. This is the difference between a map and a route. An unmarked graph is just a map of the entire domain, thousands of possible connections, most of which have nothing to do with you. The second you mark a node as owned, BloodHound can answer a far better question: not "what paths exist in this domain," but "what paths exist from where I'm actually standing."
That unlocks the query that makes the tool famous, Shortest Path from Owned Principals. It takes every account you've flagged and traces the fastest route from any of them to Domain Admin. But it can only do that if you've told it what you own first. Skip this step and that query has nothing to work from.
Mark everything, not just the first one
You do this for every account you get your hands on, not just the foothold. Owned is cumulative and it compounds. Crack one user, mark them. That reveals they can reset a second user's password, so you go grab that account and mark them too. Each new owned node reshuffles the graph and lights up paths that were invisible a step ago. A domain you can't crack from one account often falls wide open from three.
So right now, mark your foothold. Then click the node and read its info panel to see exactly what this account can do: its group memberships, its sessions, and its outbound object control, meaning every other principal it has rights over. That panel is your full scope of capability from this one account, laid out in plain sight.
Flag planted. Now we ask BloodHound the only question that matters: how do I get to Domain Admin?
Step five: read your outbound object control
You're marked as owned. BloodHound knows where you stand. Now comes the part that turns a pile of creds into an actual attack plan: assessing your outbound object control.
What outbound object control is
Strip away the jargon and it's a simple question: what can this account do to other things in the domain?
Active Directory runs on permissions. Every object, every user, group, computer, and the domain itself, has an access list saying who's allowed to modify it and how. Outbound object control is the list of rights your account holds over everything else. It's the answer to "what damage can I do from here," written out for you in plain sight.
This is the goldmine. Group memberships tell you who you are. Sessions tell you where you've been. But outbound object control tells you what you can seize next, and that's the stuff that walks you toward Domain Admin.
You find it in the info panel on the right, the same one that opens when you click your user node from the Explore search. Scroll down and you'll see an Outbound Object Control section. That's your hit list.
How the rights show up on the graph
When you expand that control onto the graph, BloodHound draws it as a labeled line running from your user to whatever object you have power over. The label on that line is the permission. GenericAll, WriteDACL, ForceChangePassword, AddKeyCredentialLink, and so on. The arrow points from you to the thing you control.
Here's where it gets good, and where Support shows it off perfectly. Control doesn't only flow straight from user to target. It flows through your group memberships too. Look at the path the graph draws:
SUPPORT@SUPPORT.HTB --MemberOf--> SHARED SUPPORT ACCOUNTS --GenericAll--> DC.SUPPORT.HTB
Read that chain left to right. Our foothold user support is a member of the SHARED SUPPORT ACCOUNTS group. That group holds GenericAll over DC.SUPPORT.HTB, the domain controller itself. And because you inherit every right of every group you belong to, that GenericAll on the DC is yours. A nothing-special support account just turned out to hold total control over the crown jewel, purely by group membership. That is the entire reason we map this instead of guessing.
A full breakdown of what each of these permissions actually is and how you weaponize them is its own beast, and it's coming in a dedicated AD permissions post. For now, you don't need to memorize them. You need to know they're your leverage and where to read what they mean, which is the next bit.
Click the permission to learn how to abuse it
This is the feature that makes BloodHound genuinely beginner-friendly. Click the permission label on the line and the right-hand panel repopulates, this time about the edge itself, not the node.
Two sections matter. General gives you a plain explanation of what the permission is. Windows Abuse (and its Linux counterpart) tells you how to turn it into access, and names tools to do it with. Click the GenericAll on that DC edge and BloodHound spells it out: the right lets you write to the DC's msDS-KeyCredentialLink attribute, which lets you drop Shadow Credentials and authenticate as the machine via Kerberos PKINIT. It even flags the alternatives, that GenericAll on a computer also opens RBCD and an ADCS ESC14 path. It hands you the attack, the technique name, and a link to the how-to.
One thing to keep your head straight about: those suggested tools and techniques are BloodHound's examples, not the law. The panel shows you a way, usually the common one. It is not the only way. GenericAll here could go the Shadow Credentials route, or RBCD, or ESC14, and depending on the box, your tooling, and what's actually reachable, you might reach for something entirely different than what the panel names. BloodHound tells you the door is unlocked. It doesn't get to decide how you walk through it. Treat the suggestions as a starting point and a learning aid, not a script.
So that's the read: mark owned, open the panel, study your outbound control, and click the edges to understand your leverage. You now know, concretely, that support can own the domain controller through a group it happens to sit in. Next we stop reading about it and go do it.
Step six: pathfinding, or letting BloodHound do the walking
In step five you read your outbound control by hand and traced where it led. That works, and you should know how to do it. But BloodHound has a mode that does the tracing for you, and once you've got a target in mind it's the fastest way to a plan: Pathfinding.
What pathfinding actually does
Simple idea. You give BloodHound two points, a start and a destination, and it finds the shortest route between them through every edge in the graph. Instead of you clicking node to node asking "okay, what can this reach, and what can that reach," you just say "I am here, I want to be there, show me the way." BloodHound does the graph math and draws the line.
That's the whole pitch, and it's a big deal on a real domain. Reading outbound control by hand is fine on Support, where the graph is tiny. Drop that approach on an enterprise with forty thousand objects and you'll be there all night. Pathfinding scales. It collapses a sprawling mess of permissions into the one chain that matters.
Running it
Up top, click the Pathfinding tab, right next to Search. Two fields open up:
The top field is your start node. Put your owned user here, SUPPORT@SUPPORT.HTB.
The bottom field is your destination. This is the thing you're trying to reach.
There's a little swap button between them if you ever want to flip direction, and a filter if you want to constrain which edge types it's allowed to use. For now, leave those alone.
The classic: path to Domain Admins
Nine times out of ten, the first destination I punch in is Domain Admins. It's the "can I win this domain, and if so how" query, and it's the single most useful thing pathfinding does. Start typing domai and BloodHound floods you with matches, Domain Admins, Domain Controllers, Domain Users, the domain object itself. Pick DOMAIN ADMINS@SUPPORT.HTB and let it draw.
Here's what it hands back on Support:
SUPPORT --MemberOf--> SHARED SUPPORT ACCOUNTS --GenericAll--> DC.SUPPORT.HTB --DCFor--> SUPPORT.HTB --Contains--> USERS --Contains--> DOMAIN ADMINS
Six hops looks scary the first time. It isn't. Learn to read these paths and you'll see most of it is scenery.
Here's the trick that trips up every beginner: not every edge in a path is an action you take. Walk it left to right. The MemberOf is just a fact, you're in that group. Then comes the one that counts, the GenericAll on DC.SUPPORT.HTB. That's your attack. That's the same edge from step five, the one that lets you drop Shadow Credentials on the domain controller. Everything after it, the DCFor, the two Contains edges, is structural filler. BloodHound is just connecting the dots to prove that owning the DC computer means owning the domain, because Domain Admins literally lives inside that domain.
So a six-hop path resolves to exactly one thing you actually do: abuse that GenericAll on the DC. The rest is BloodHound showing its work. Read every path this way. Find the real attack edges, the ACLs and the abuses, and mentally skip the membership and containment edges that are just topology. A path with five hops and one attack edge is one move, not five.
Other destinations worth trying
Domain Admins is the headliner, but the destination field takes anything:
The domain object (SUPPORT.HTB) or Domain Controllers, when you care about domain-wide compromise more than a specific group. Enterprise Admins, once you're in a multi-domain forest and want the whole thing, not just one domain. A specific box or user, when you're not going for the crown yet, you just need to reach one particular machine for lateral movement or one account whose access you want. Tier Zero / high-value targets, to see every sensitive object you can touch at once.
Point is, pathfinding isn't only a "how do I become god" button. It's a "how do I get from A to any B" button, and B is whatever your current objective happens to be.
Quick teaser while we're here: keep an eye out for my bloodyAD deep dive, coming soon. When it's time to stop looking at these edges and start pulling them, bloodyAD is hands down the best tool going for interacting with AD permissions and objects, and it deserves its own writeup rather than a footnote in this one.
So that's pathfinding. Point it at Domain Admins, read the path, strip it down to the real attack edges, and you've got your route. But pathfinding only answers questions shaped like "from here to there." Sometimes the question you actually want to ask is weirder and more specific than that. For that, we drop down to the raw query language underneath the whole tool.
The last stop: Cypher
Everything so far has been point-and-click. Search, mark owned, run pathfinding. Those cover most of what you'll ever need. But under the whole tool sits a query language, and when the question you want to ask doesn't have a button, this is where you go.
Cypher is the graph query language BloodHound runs on. Think of it as SQL's cousin, except instead of querying rows and tables it queries nodes and the edges between them, which is exactly the shape of an Active Directory attack. Written from scratch it's a whole skill of its own. The good news: you don't have to write any of it to get enormous value, because BloodHound ships with a library of pre-built queries someone already wrote for you.
Click the Cypher tab in the Explore toolbar, then expand Saved Queries. You'll get a categorized, searchable list, Domain Information, Dangerous Privileges, and more. There are dozens. Most you'll never touch. These three earn their keep on nearly every engagement:
Shortest Paths from Owned Objects
This is the query step four was setting up. Remember all that flagging accounts as owned? This is the cash-out. It takes every node you marked as owned and computes the fastest attack paths from your actual position to the high-value targets in the domain.
That "from where I actually stand" framing is what makes it gold. It ignores the thousands of paths that have nothing to do with you and shows only the ones you can start walking right now, with the creds already in your pocket. On a big domain this is frequently the single most useful thing BloodHound does. One click and it filters an ocean of permissions down to your personal to-do list. Own more accounts, re-run it, watch new paths appear.
Shortest Paths to Domain Admins
The mirror image. Pathfinding made you pick a start node. This one doesn't care where you are. It surfaces every short road into Domain Admins from anywhere in the domain, owned or not.
Why bother if you can't walk them yet? Because it tells you what to target next. If some unremarkable user two desks over sits one hop from Domain Admins, that user just became your objective. This query spots the weak links in the domain's armor so you know which account is worth the effort to grab. It's reconnaissance for your reconnaissance.
All Kerberoastable Users
Different flavor entirely, and a beautiful opener on almost any domain. This lists every account with an SPN set, which is every account you can Kerberoast.
Quick why-you-care: any authenticated user can request a service ticket for an SPN-enabled account, and that ticket comes back encrypted with the account's password hash. Pull it, crack it offline, and you've got the plaintext. No special rights, barely any noise, and service accounts are notorious for ancient weak passwords, sometimes on accounts with real privilege. This query hands you the full hit list of who's roastable in one shot. It won't always be your path on Support, but on a huge share of boxes and real domains it's the first thing worth trying.
The permissions that make these pop
The paths these queries draw are strung together by the same object-control edges from step five, and a couple show up constantly:
ForceChangePassword is the cleanest takeover there is. It lets you reset a target user's password without knowing the current one. See this edge pointing at someone useful and that account is effectively yours.
GenericWrite / GenericAll is broad write control, and it opens doors, shadow credentials, RBCD, and my favorite pairing with the query above: targeted Kerberoasting. If you hold GenericWrite over an account, you can slap an SPN onto it yourself, roast it, and crack it, turning a non-roastable account into a roastable one on demand.
And exactly like pathfinding, everything in a Cypher result is clickable. The paths it returns show you the exploit route, the permission that unlocks each hop, and the user or group you need to abuse it, and you can click any node or any edge to pull up that same info panel, General and Windows Abuse, and read exactly what it is and how to use it. Same inspection loop, more targeted questions.
That's the toolkit chapter
That's the whole loop end to end. Collect with RustHound, start the UI, import clean, mark what you own, read your outbound control, pathfind to the crown, and query for the rest. From one low-priv ldap account to owning support.htb, mapped the entire way.
Now the honest part. This is not a comprehensive BloodHound guide, and it was never trying to be. This is an Inferno-style writeup: maximum return, minimum time, get you dangerous fast and get out of your way. There is a lot more here, custom Cypher, edge filtering, ADCS graphing, cross-forest paths, that I deliberately left on the floor so this stayed useful instead of exhaustive. If you walked away knowing how to go from a foothold to a mapped path to Domain Admins, it did its job.
A couple of these threads get their own posts. The AD permissions deep dive breaks down what each of these edges actually is and how you weaponize them one by one. The bloodyAD deep dive covers the best tool going for reaching out and pulling these edges once you've found them. Both coming soon, both linked here when they land. And if you haven't read the NetExec deep dive, and want to learn more just check out the toolkit hub below for all the links to the entire series.
Find. Fix. Fortify.
Toolkit hub for more tool posts https://www.hack2harden.com/the-oscp-toolkit-the-tools-that-actually-carried-me





