A Python script to generate a bloodhound opengraph of the rights of shares on a remote Windows machine.
Project description
ShareHound: Mapping rights of network shares using bloodhound OpenGraph
A python tool to map the access rights of network shares into a BloodHound OpenGraphs easily
Read the associated blogpost: https://specterops.io/blog/2025/10/30/sharehound-an-opengraph-collector-for-network-shares/
Features
- Map network shares of a domain and their rights in Bloodhound OpenGraph format
- Highly customizable rule matching system based on the ShareQL language
- Multithreaded discovery of shares in Breadth First Search
Quick start cypher queries
To help you get started, here are a set of quick start cypher queries for the most common needs:
Find principals with Full control access to a share
The following query will allow you to find principals with full control access to a share
MATCH (p:Principal)-[r]->(s:NetworkShareSMB)
WHERE (p)-[:CanDelete]->(s)
AND (p)-[:CanDsControlAccess]->(s)
AND (p)-[:CanDsCreateChild]->(s)
AND (p)-[:CanDsDeleteChild]->(s)
AND (p)-[:CanDsDeleteTree]->(s)
AND (p)-[:CanDsListContents]->(s)
AND (p)-[:CanDsListObject]->(s)
AND (p)-[:CanDsReadProperty]->(s)
AND (p)-[:CanDsWriteExtendedProperties]->(s)
AND (p)-[:CanDsWriteProperty]->(s)
AND (p)-[:CanReadControl]->(s)
AND (p)-[:CanWriteDacl]->(s)
AND (p)-[:CanWriteOwner]->(s)
RETURN p,r,s
This will result in a graph similar to this one (I like to call it the Full Control Onion):
graph LR
S-1-5-21-3797563538-650367887-713497691-1106[S-1-5-21-3797563538-650367887-713497691-1106] -->| CanDelete | ExampleShare[ExampleShare]
S-1-5-21-3797563538-650367887-713497691-1106 -->| CanDsControlAccess | ExampleShare
S-1-5-21-3797563538-650367887-713497691-1106 -->| CanDsCreateChild | ExampleShare
S-1-5-21-3797563538-650367887-713497691-1106 -->| CanDsDeleteChild | ExampleShare
S-1-5-21-3797563538-650367887-713497691-1106 -->| CanDsDeleteTree | ExampleShare
S-1-5-21-3797563538-650367887-713497691-1106 -->| CanDsListContents | ExampleShare
S-1-5-21-3797563538-650367887-713497691-1106 -->| CanDsListObject | ExampleShare
S-1-5-21-3797563538-650367887-713497691-1106 -->| CanDsReadProperty | ExampleShare
S-1-5-21-3797563538-650367887-713497691-1106 -->| CanDsWriteExtendedProperties | ExampleShare
S-1-5-21-3797563538-650367887-713497691-1106 -->| CanDsWriteProperty | ExampleShare
S-1-5-21-3797563538-650367887-713497691-1106 -->| CanReadControl | ExampleShare
S-1-5-21-3797563538-650367887-713497691-1106 -->| CanWriteDacl | ExampleShare
S-1-5-21-3797563538-650367887-713497691-1106 -->| CanWriteOwner | ExampleShare
Find principals with Write access to a share
The following query will allow you to find files by name (case insensitive)
MATCH x=(p:Principal)-[r:CanWriteDacl|CanWriteOwner|CanDsWriteProperty|CanDsWriteExtendedProperties]->(s:NetworkShareSMB)
RETURN x
This will result in a graph similar to this one:
graph LR
S-1-5-21-3797563538-650367887-713497691-1106[S-1-5-21-3797563538-650367887-713497691-1106] -->| CanWriteDacl | ExampleShare[ExampleShare]
S-1-5-21-3797563538-650367887-713497691-1106 -->| CanWriteOwner | ExampleShare
S-1-5-32-544[S-1-5-32-544] -->| CanWriteDacl | SYSVOL[SYSVOL]
S-1-5-32-544 -->| CanWriteOwner | SYSVOL
S-1-5-32-544 -->| CanWriteDacl | ExampleShare
S-1-5-32-544 -->| CanWriteOwner | ExampleShare
Find files by name (case insensitive)
The following query will allow you to find files by name (case insensitive)
MATCH p=(h:NetworkShareHost)-[:HasNetworkShare]->(s:NetworkShareSMB)-[:Contains*0..]->(f:File)
WHERE toLower(f.name) = toLower("flag.txt")
RETURN p
This will result in a graph similar to this one:
graph LR
DC01[DC01] -->| HasNetworkShare | Test[Test]
Test -->| Contains | Dir1[Dir1]
Test -->| Contains | DirA[DirA]
DirA -->| Contains | flag.txtA[flag.txt]
Dir1 -->| Contains | Dir2[Dir2]
Dir2 -->| Contains | flag.txt1[flag.txt]
Find files by extension (case insensitive)
The following query will allow you to find files by extension (case insensitive)
MATCH p=(h:NetworkShareHost)-[:HasNetworkShare]->(s:NetworkShareSMB)-[:Contains*0..]->(f:File)
WHERE toLower(f.extension) = toLower(".vmdk")
RETURN p
This will result in a graph similar to this one:
graph LR
DC01[DC01] -->| HasNetworkShare | Test[Test]
Test -->| Contains | Dir1[Dir1]
Test -->| Contains | DirA[DirA]
DirA -->| Contains | SRV02.vmdkA[SRV02.vmdk]
Dir1 -->| Contains | Dir2[Dir2]
Dir2 -->| Contains | DC01.vmdk1[DC01.vmdk]
Find files by extension (case insensitive)
The following query will allow you to find files by name (case insensitive)
MATCH p=(h:NetworkShareHost)-[:HasNetworkShare]->(s:NetworkShareSMB)-[:Contains*0..]->(f:File)
WHERE toLower(f.name) ENDS WITH ".bat"
RETURN p
This will result in a graph similar to this one:
graph LR
DC01[DC01] -->| HasNetworkShare | Test[Test]
Test -->| Contains | Dir1[Dir1]
Test -->| Contains | DirA[DirA]
DirA -->| Contains | script.batA[script.bat]
Dir1 -->| Contains | Dir2[Dir2]
Dir2 -->| Contains | logon.bat1[logon.bat]
For advanced users
All node types and edges name are defined in the kinds.py file, so that you can easily find the name of these to create custom Cypher queries.
Contributing
Pull requests are welcome. Feel free to open an issue if you want to add other features.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters