Bring runZero Exposure Management into BloodHound via OpenGraph.
Read our initial blog post.
-
Ensure that you have Docker or Podman (in Docker-compatibility mode). The command “docker compose ls” should not return an error.
-
Git clone the BloodHound source tree:
git clone https://github.com/SpecterOps/BloodHound.git
-
Open a terminal in the
BloodHound/examples/docker-compoosesubdirectory -
Adjust
docker-compose.ymlto enable thepggraph-db driver
bhe_graph_driver=pg
- Adjust bloodhound.config.json to set the graph_driver to “pg”
"graph_driver": "pg",
- Run “docker compose up” to launch BloodHound
- Copy the initial admin password shown in the output
- Login to http://127.0.0.1:8080/ui/login with username admin and your password
- Change the password to something else and remember or save it
- Hurray! At this point you are ready to load and explore data
- Ensure that you have a recent version of Go installed (1.25+)
- Git clone the runZeroHound source tree
git clone https://github.com/runZeroInc/runZeroHound.git
- Ensure that the tool runs:
go run main.go -h
- Login to your runZero Console
- Navigate to Inventory -> Assets
- Under Export, select “As JSON Lines…”
- Wait for this to download to disk
- Open the runZeroHound directory in your terminal
- Run the convert command to create an OpenGraph JSON
go run main.go convert <runZeroInventory.jsonl> opengraph.json
- Use the Quick Upload option on the left and drag your opengraph.json onto it
- Watch the File Ingest history at http://127.0.0.1:8080/ui/administration/file-ingest
- Once import completes, access Explore and then select the Cypher tab
- Enter a test query to verify your data:
match (n:RZNetwork) where n.network_address = '0.0.0.0' return n
- Confirm that this query shows the RZ-NETWORK-PUBLIC subnet node
BloodHound OpenGraph supports custom icons for specific node types. Setting this up requires a bit of API interaction and we plan to add a helper tool to support this in the future.
- RZAsset - Connected devices with IPs, open ports, and system info
- Connected to services via RZHasService and RZRunsOnAsset edges
- Connected to subnets via RZInsideOfSubnet and RZSubnetContains edges
- RZService - Identified services on assets
- Connected to assets via RZHasService and RZRunsOnAsset edges
- RZSubnet - Network subnets with CIDR notation and host counts
- Connected to assets via RZInsideOfSubnet and RZSubnetContains edges
- Subnets assume /24 and /56 masks for IPv4 and IPv6 respectively
- External subnets are connected to an "Internet" node
- RZDomain - Active Directory domain name if available
- Connected to assets via RZPartOfDomain and RZDomainContains edges
- RZVLAN - VLAN IDs if available from asset attributes
- Connected to assets via RZPartOfVLAN and RZVLANContains edges
Asset Nodes:
ip_addresses[]: All resolved IP addressesip_addresses_extra[]: All resolved IP addresseshostname: Primary hostnamenames[]: All resolved namesdomains[]: All resolved domainsservice_ports_tcp[]: Discovered TCP open portsservice_ports_udp[]: Discovered UDP servicesos: Operating system informationhw: Hardware informationmac_addresses[]: All resolved MAC addressesnewest_mac: Newest MAC addressnewest_mac_vendor: Vendor of newest MAC addressnewest_mac_age: Age of newest MAC addresslowest_ttl: Lowest observed TTL valuelowest_rtt: Lowest observed RTT valuealive: Boolean indicating if the device is aliveservices{}: List of discovered servicescredentials[]: List of discovered credentialstags[]: Asset tagsscanned: Last scanned timestampcomments: Asset commentsservice_protocols[]: List of service protocolsservice_products[]: List of service productssoftware_count: Number of installed software itemsvulnerability_count: Number of identified vulnerabilitiesrisk: Risk level as a stringrisk_rank: Numerical risk rankfirst_seen: Timestamp of first sightinglast_seen: Timestamp of last sightingcreated_at: Asset creation timestampupdated_at: Asset last updated timestampsources[]: List of data sourcestags[]: All unique tags (bare and key-values)
Asset nodes also include flattened attributes, prefixed by the source type (runzero, crowdstrike.dev, etc)
Service Nodes:
address: IP address (v4 or v6)port: Port number if relevant (as a string)transport: Underlying transport (tcp, udp, icmp, arp)
Service nodes also include flattened attributes, prefixed by "attr_"
Subnet Nodes:
subnet: CIDR notationnetwork_address: Network addresshost_count: Number of hosts in subnet
Domain Nodes:
domain: Domain namehost_count: Number of hosts in domain
VLAN Nodes:
vlan: VLAN IDhost_count: Number of hosts in VLAN
Please see the Cypher documentation for more details.
match p=(t1:RZAsset)-[:RZInsideOfSubnet]->(a:RZNetwork)-[:RZInsideOfSubnet]->(b:RZNetwork)
where b.network_address = '0.0.0.0'
and a.version = '4'
and t1.os contains 'Windows'
return
match p=(public:RZNetwork)-[:RZSubnetContains]->(hop1:RZNetwork)-[:RZSubnetContains]->(a1:RZAsset)
where
public.network_address = '0.0.0.0'
and hop1.version = '4'
and a1.ip_addresses contains '10.'
return p
match p=(byod:RZAsset)-[:RZInsideOfSubnet]->(net1:RZNetwork)-[:RZSubnetContains]->(mgmt:RZAsset)
where
byod.os contains 'Apple iOS'
AND mgmt.os contains ‘Cisco’
AND mgmt.service_protocols contains 'snmp2'
return p
runZeroHound is not an officially supported runZero product, but we still want to hear your feedback and bug reports. Please open an issue in this repository or email support[at]runZero.com.


