Listen to this Post

Introduction:
The release of BloodHound’s OpenGraph feature marks a paradigm shift in customizing and expanding attack path discovery within Active Directory environments. This article delves into the new `gopengraph` Go library, which provides security professionals with the toolkit to programmatically generate and ingest custom data, thereby uncovering previously invisible attack paths and deepening their understanding of domain security posture.
Learning Objectives:
- Understand the core concepts and capabilities of the BloodHound OpenGraph specification.
- Learn how to utilize the `gopengraph` library to create custom data collectors and ingesters.
- Master the practical application of generating, validating, and importing custom OpenGraph data into a BloodHound instance.
You Should Know:
1. Understanding the OpenGraph Data Model
The OpenGraph specification is built upon a flexible JSON structure that defines nodes (like users, computers, groups) and the relationships between them. The `gopengraph` library provides structs and helpers to create these objects programmatically.
package main
import (
"github.com/TheManticoreProject/gopengraph"
"log"
)
func main() {
// Create a new graph object
graph := gopengraph.NewGraph()
// Create a User node
userNode := gopengraph.NewNode("User", "[email protected]")
userNode.Properties["name"] = "Alice"
userNode.Properties["enabled"] = true
// Create a Computer node
computerNode := gopengraph.NewNode("Computer", "WS01.DOMAIN.LOCAL")
computerNode.Properties["name"] = "WS01"
computerNode.Properties["operatingsystem"] = "Windows 10"
// Add nodes to the graph
graph.AddNodes(userNode, computerNode)
// Create a relationship: User has AdminTo Computer
rel := gopengraph.NewRelationship("AdminTo", userNode, computerNode)
graph.AddRelationship(rel)
// Marshal the graph to JSON
jsonData, err := graph.ToJSON()
if err != nil {
log.Fatal(err)
}
log.Println(string(jsonData))
}
Step-by-step guide: This Go code demonstrates the fundamental process of building an OpenGraph. First, a new graph container is created. Then, individual nodes are instantiated by specifying their type (e.g., “User”, “Computer”) and a unique ObjectIdentifier. Properties relevant to BloodHound’s analysis, such as `enabled` for a user, are added. Finally, a relationship of type “AdminTo” is established between the user and computer nodes, defining a critical attack path. The `ToJSON()` method serializes the entire structure into the correct format for BloodHound.
2. Ingesting Custom Application Data for Shadow Admins
Many in-house applications have their own permission systems that can create privileged access outside of standard AD groups. Using gopengraph, you can model these.
// ... (graph and node creation as before)
// Assume we have data from a custom HR app where users can reset passwords
customAppNode := gopengraph.NewNode("AZApp", "CustomHRApp")
customAppNode.Properties["name"] = "Custom HR Application"
// A security group for HR
hrGroupNode := gopengraph.NewNode("Group", "[email protected]")
// Relationship: The HR app has a custom role that can reset passwords for the HR group
customRel1 := gopengraph.NewRelationship("AZResetPassword", customAppNode, hrGroupNode)
graph.AddRelationship(customRel1)
// A specific user is a member of the HR group
userMembershipRel := gopengraph.NewRelationship("Member", userNode, hrGroupNode)
graph.AddRelationship(userMembershipRel)
Step-by-step guide: This snippet models a non-standard attack path. It creates a node of a custom type (“AZApp”) representing an internal application. A relationship “AZResetPassword” is defined from this application to an AD group. This tells BloodHound that the application has the power to reset passwords for members of that group. When combined with the standard “Member” relationship, BloodHound can now show a path from the application compromise to control over the user’s account.
3. Automating Data Collection with File Ingestion
Once you have generated a JSON file from your custom collector, you must import it into BloodHound. This is done via the BloodHound user interface or API.
Bash command to start BloodHound and prepare for data upload:
Navigate to your BloodHound directory and start the tool ./BloodHound --no-sandbox
Python script to validate JSON before upload:
import json
def validate_opengraph_json(file_path):
try:
with open(file_path, 'r') as f:
data = json.load(f)
Check for required 'data' top-level key
if 'data' not in data:
return False, "Missing 'data' key"
Basic structure validation
if not isinstance(data['data'], list):
return False, "'data' must be a list"
print("OpenGraph JSON appears valid.")
return True, "Valid"
except json.JSONDecodeError as e:
return False, f"Invalid JSON: {e}"
validate_opengraph_json("my_custom_data.json")
Step-by-step guide: After generating your `custom_data.json` file with a Go script using gopengraph, use a simple Python validator to check its syntax and basic structure. This prevents failed uploads. Then, in the running BloodHound GUI, use the upload feature (often a drag-and-drop interface in the “Upload Data” section) to import the JSON file. BloodHound will process the data and integrate it into the graph database.
4. Leveraging AzureRM and MSGraph API Data
The `gopengraph` library can be integrated with scripts that pull live data from Azure using Microsoft Graph API or AzureRM to find dangerous cloud-based configurations.
PowerShell snippet to get Azure AD app permissions (run this before modeling with gopengraph):
Connect-MgGraph -Scopes "Application.Read.All"
$apps = Get-MgApplication
foreach ($app in $apps) {
$appDisplayName = $app.DisplayName
foreach ($sp in $app.ResourceSpecificApplicationPermissions) {
Write-Output "App: $appDisplayName - Permission: $($sp.Type)"
}
}
Step-by-step guide: This PowerShell command, using the Microsoft Graph PowerShell module, enumerates all applications and their resource-specific permissions. The output from this script can be fed into a Go program using the `gopengraph` library. The Go program would create nodes for each application and service principal, and then create relationships like “Owns”, “MemberOf”, or custom roles based on the high-risk permissions found (e.g., Application.ReadWrite.All), painting a precise picture of the Azure AD attack surface.
5. Hardening Analysis with Custom Queries
After importing custom OpenGraph data, you can use BloodHound’s built-in Cypher query language to find new attack paths.
BloodHound Cypher query to find users who can be compromised via a custom application:
MATCH p=(n)-[r:AZResetPassword|Member1..2]->(m:User {enabled: true})
WHERE n.objectid =~ '(?i)CustomHRApp'
RETURN p
Step-by-step guide: This Cypher query runs inside BloodHound’s “Query” tab. It searches for any path (p) starting from a node with the ID “CustomHRApp”. It follows outgoing relationships that are either “AZResetPassword” (our custom relationship) or “Member”, traversing 1 or 2 hops (1..2), until it reaches an enabled user. This directly visualizes the risk posed by the compromised custom HR application.
6. Validating and Testing Your OpenGraph Implementation
Before deploying a custom collector, test the data it generates against a lab BloodHound instance to ensure accuracy and prevent corruption of your main database.
Docker commands to spin up a test BloodHound environment:
Pull the latest BloodHound community edition container docker pull bloodhoundcommunity/bloodhound:latest Run the container, mapping the web UI port docker run -p 8080:8080 -it bloodhoundcommunity/bloodhound:latest
Using `jq` to parse and verify the structure of your generated JSON:
Check if the JSON is valid and print the first node type cat my_custom_data.json | jq '.data[bash].nodes[bash].label' Count the total number of relationships in the graph cat my_custom_data.json | jq '[.data[].edges[]] | length'
Step-by-step guide: Using Docker, you can quickly instantiate a disposable BloodHound instance for testing. After uploading your custom JSON file to this test instance, use the `jq` command-line tool to perform preliminary validation on the file itself. The first command checks the type of the first node, and the second counts all relationships, giving you a quick sanity check on your data’s volume and structure before you spend time analyzing it in the UI.
7. Scripting Continuous Data Ingestion
For dynamic environments, integrate your gopengraph-based tool into a CI/CD pipeline or scheduled task to keep BloodHound’s data continuously updated.
Example Linux cron job to run a custom collector script daily:
Edit the crontab for the user that runs the collector 0 2 /home/bh-collector/go/bin/custom-collector -output /data/bh_import/custom_data.json
Windows Scheduled Task command (to be set via Task Scheduler GUI or CLI):
schtasks /create /tn "BH-CustomDataCollector" /tr "C:\Collector\custom-collector.exe -output C:\BloodHoundData\custom.json" /sc daily /st 02:00
Step-by-step guide: Automation is key for maintaining an accurate attack graph. On a Linux system, you can add a line to the crontab file (using crontab -e) that executes your compiled Go collector every day at 2 AM. On Windows, the `schtasks` command creates a scheduled task with similar parameters. This ensures that any new custom relationships created in your environment are promptly reflected in BloodHound, allowing for near real-time attack path analysis.
What Undercode Say:
- The OpenGraph specification and its accompanying `gopengraph` library represent a fundamental evolution of BloodHound from a specialized assessment tool into a extensible security platform.
- The ability to model non-AD and custom application permissions closes a critical visibility gap for modern, hybrid enterprises where significant business logic and privilege exist outside pure Active Directory.
The release of `gopengraph` is more than a convenience for developers; it is a strategic enabler. By lowering the barrier to entry for creating custom data collectors, SpecterOps is effectively crowdsourcing the expansion of BloodHound’s coverage. The community can now build connectors for everything from SaaS platforms and DevOps tooling to physical access control systems. This transforms BloodHound from a tool that answers “How am I vulnerable in AD?” to a platform that can answer “How am I vulnerable across my entire digital estate?” The long-term impact will be a more holistic and accurate understanding of enterprise security posture, forcing defenders to think beyond traditional domain boundaries and red teams to develop more sophisticated, multi-faceted attack simulations.
Prediction:
The abstraction of attack path modeling via OpenGraph will catalyze the development of a vibrant third-party ecosystem for BloodHound, similar to the plugin architecture of Metasploit. Within two years, we predict that standardized OpenGraph collectors will be available for all major cloud platforms (AWS IAM Pathing, GCP Resource Manager), IT management suites (ServiceNow, SCCM), and identity providers (Okta, Ping), making unified, multi-platform attack path analysis the new gold standard for enterprise security posture assessment. This will simultaneously push defenders towards more integrated security architectures and force attackers to develop exploits that chain vulnerabilities across on-premise and cloud boundaries.
🎯Let’s Practice For Free:
IT/Security Reporter URL:
Reported By: Remigascou Github – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅


