A collector for adding MSSQL attack paths to BloodHound with OpenGraph by Chris Thompson at SpecterOps. Available as both a PowerShell script and a cross-platform Go binary (with concurrent collection, SOCKS5 proxy support, and streaming output).
Introductory blog posts:
- https://specterops.io/blog/2025/08/04/adding-mssql-to-bloodhound-with-opengraph/
- https://specterops.io/blog/2026/01/20/updates-to-the-mssqlhound-opengraph-collector-for-bloodhound/
- https://specterops.io/blog/2026/04/23/mssqlhound-now-available-in-go/
Please hit me up on the BloodHound Slack (@Mayyhem), Twitter (@_Mayyhem), or open an issue if you have any questions I can help with!
# 1) Download the source
git clone https://github.com/SpecterOps/MSSQLHound.git
cd MSSQLHound
# 2) Build the binary (Go 1.25+)
go build -o mssqlhound ./cmd/mssqlhoundOn Windows, use .\mssqlhound.exe instead of ./mssqlhound.
Run MSSQLHound with a few common collection patterns:
# Use Windows integrated authentication to query Active Directory for MSSQLSvc SPNs and collect from all discovered MSSQL server instances, ten at a time
./mssqlhound -w 10
# Collect from a specific MSSQL server instance using SQL login credentials
./mssqlhound -t sql.contoso.com -u sa -p password
# Collect through a SOCKS proxy using specified domain controller IP for DNS and LDAP resolution and collect from all discovered MSSQL server instances, 20 at a time
./mssqlhound -u "CONTOSO\sqlaudit" -p "password" -d contoso.com --dc 10.2.10.100 -w 20 --verbose --proxy 127.0.0.1:9050
# Collect from all domain computers using Windows MSSQL login credentials, 25 at a time, then upload schema and results to BloodHound
./mssqlhound -u "CONTOSO\sqlaudit" -p "password" -d contoso.com -w 25 --scan-all-computers -B '<token-id>:<token-key>@https://contoso.bloodhoundenterprise.io'- Quick Start
- Overview
- OPSEC
- Go Version
- Why a Go Port?
- Building
- Go Usage
- Basic Usage
- Multiple Servers
- Full Domain Enumeration
- DNS and Domain Controller Configuration
- SOCKS5 Proxy Support
- Credential Fallback
- Kerberos Authentication
- Pass-the-Hash
- Domain Enum Only (Reconnaissance)
- Collection
- Output and Storage Options
- BloodHound Upload
- Possible Edge Options
- Linked Server Options
- test-epa-matrix Subcommand
- Shell Completion
- Go Command Line Options
- Key Differences from PowerShell Version
- CVE Detection
- Known Limitations and Issues (Go)
- Troubleshooting (Go)
- PowerShell Usage
- PowerShell Command Line Options
- Limitations
- Future Development
- Credits
- MSSQL Graph Model
- MSSQL Nodes Reference
- MSSQL Edges Reference
- Edge Classes and Properties
MSSQL_CoerceAndRelayToMSSQLMSSQL_AddMemberMSSQL_AlterMSSQL_AlterAnyAppRoleMSSQL_AlterAnyDBRoleMSSQL_AlterAnyLoginMSSQL_AlterAnyServerRoleMSSQL_ChangeOwnerMSSQL_ChangePasswordMSSQL_ConnectMSSQL_ConnectAnyDatabaseMSSQL_ContainsMSSQL_ControlMSSQL_ControlDBMSSQL_ControlServerMSSQL_ExecuteAsMSSQL_ExecuteAsOwnerMSSQL_ExecuteOnHostMSSQL_GetAdminTGSMSSQL_GetTGSMSSQL_GrantAnyDBPermissionMSSQL_GrantAnyPermissionMSSQL_HasDBScopedCredMSSQL_HasLoginMSSQL_HasMappedCredMSSQL_HasProxyCredMSSQL_HostForMSSQL_ImpersonateMSSQL_ImpersonateAnyLoginMSSQL_IsMappedToMSSQL_IsTrustedByMSSQL_LinkedAsAdminMSSQL_LinkedToMSSQL_MemberOfMSSQL_OwnsMSSQL_ServiceAccountForMSSQL_TakeOwnership
- Edge Classes and Properties
Collects BloodHound OpenGraph compatible data from one or more MSSQL servers into individual temporary files, then zips them in the current directory
- Example:
mssql-bloodhound-20250724-115610.zip
- PowerShell 4.0 or higher
- Target is running SQL Server 2005 or higher
- BloodHound v8.0.0+ with Postgres backend (to use prebuilt Cypher queries): https://bloodhound.specterops.io/get-started/custom-installation#postgresql
- BloodHound v9.0.0+ with OpenGraph Extension Management enabled to use pathfinding
- For Kerberos authentication (
-k):krb5-userpackage on Linux (sudo apt install krb5-user)
- Active Directory domain context with line of sight to a domain controller
CONNECT SQL(default for new logins)VIEW ANY DATABASE(default for new logins)
VIEW ANY DEFINITIONpermission or##MS_DefinitionReader##role membership (available in versions 2022+)- Needed to read server principals and their permissions
- Without one of these permissions, there will be false negatives (invisible server principals)
VIEW SERVER PERFORMANCE STATEpermission or##MSS_ServerPerformanceStateReader##role membership (available in versions 2022+) or localAdministratorsgroup privileges on the target (fallback for WMI collection)- Only used for service account collection
CONNECT ANY DATABASEserver permission (available in versions 2014+) or##MS_DatabaseConnector##role membership (available in versions 2022+) or login maps to a database user withCONNECTon individual databases- Needed to read database principals and their permissions
- Login maps to
msdbdatabase user withdb_datareaderrole or withSELECTpermission on:msdb.dbo.sysproxiesmsdb.dbo.sysproxyloginmsdb.dbo.sysproxysubsystemmsdb.dbo.syssubsystems- Only used for proxy account collection
This section documents every network connection, authentication event, subprocess, query, and file artifact produced by MSSQLHound so operators can make informed decisions about detection risk.
All TCP connections support SOCKS5 proxy tunneling (--proxy). TLS connections use InsecureSkipVerify=true and cap at TLS 1.2.
| Protocol | Port | Transport | Target | Purpose | Conditions |
|---|---|---|---|---|---|
| TDS (SQL Server) | 1433/tcp (default, configurable) | TCP with optional TLS | Each SQL Server being enumerated | SQL authentication and query execution | Always (core functionality) |
| SQL Browser | 1434/udp | UDP | SQL Server host | Named instance port resolution | Only for named instances without an explicit port. Not proxied through SOCKS5. |
| LDAPS | 636/tcp | TLS | Domain controller | SPN enumeration, principal/SID resolution, computer enumeration | First LDAP method attempted |
| LDAP + StartTLS | 389/tcp | TCP upgraded to TLS | Domain controller | Same as LDAPS | Fallback if LDAPS fails |
| Plain LDAP | 389/tcp | TCP (unencrypted) | Domain controller | Same as LDAPS | Final LDAP fallback |
| DNS | 53/udp | UDP | --dns-resolver or --dc |
SRV records (_ldap._tcp.<domain>), A records, reverse DNS (PTR) |
When domain resolution is needed |
| WinRM | 5985/tcp (HTTP) or 5986/tcp (HTTPS) | HTTP/HTTPS | SQL Server host | Remote PowerShell for EPA configuration | Only test-epa-matrix subcommand |
| WMI/DCOM | 135/tcp + dynamic RPC | TCP | SQL Server host | Enumerate local group members (Win32_GroupUser) |
Windows only. Fails gracefully on other platforms. |
| Mode | Description |
|---|---|
| TDS 8.0 (strict) | Full TLS before any TDS traffic. Uses ALPN tds/8.0. |
| TLS-in-TDS | TLS negotiated inside the TDS PRELOGIN handshake. |
| Force Encryption | Server-mandated encryption after PRELOGIN exchange. |
| Filter | Purpose |
|---|---|
(servicePrincipalName=MSSQLSvc/*) |
Find all MSSQL SPNs in the domain |
(servicePrincipalName=MSSQLSvc/<host>*) (short + FQDN) |
Look up SPNs for a specific server |
(&(objectCategory=computer)(objectClass=computer)) |
Enumerate all domain computers (--scan-all-computers) |
(objectSid=<sid>) |
Resolve a SID to an AD principal |
(sAMAccountName=<name>) |
Resolve an account name to an AD principal |
(&(objectClass=computer)(sAMAccountName=<name>$)) |
Resolve a computer account by name |
All LDAP searches use subtree scope with 1000-result paging.
Each authentication below generates log entries on the target system.
| Event | Target | Method | Details | Conditions |
|---|---|---|---|---|
| SQL Server login | SQL Server | SQL auth (username/password in TDS LOGIN7) | Logged as a login event in SQL Server audit logs | When -u/-p supplied |
| SQL Server login | SQL Server | Windows auth (NTLM SSPI in TDS LOGIN7: Negotiate → Challenge → Authenticate) | Includes Channel Binding Token (CBT) when TLS is active. Logged as a login event in SQL Server audit logs. | When using domain credentials |
| LDAP bind | Domain controller | GSSAPI/SSPI (Kerberos) | Uses current user's Windows security context | Windows only, when no explicit LDAP credentials |
| LDAP bind | Domain controller | NTLM or Simple bind (UPN, DN, or DOMAIN\user) | Logged as an authentication event on the DC | When --ldap-user/--ldap-password supplied or SQL credentials reused |
| WinRM login | SQL Server host | NTLM or Basic auth | Logged as a Windows authentication event | Only test-epa-matrix subcommand |
| WMI/DCOM login | SQL Server host | Current user's Windows credentials | Logged as a DCOM authentication event | Windows only, during local group enumeration |
MSSQLHound spawns local powershell.exe processes as fallbacks when native Go clients fail. All subprocesses run on the operator's machine, not on targets (except WinRM remote execution).
| Executable | Arguments | Purpose | Conditions |
|---|---|---|---|
powershell.exe |
-NoProfile -NonInteractive -Command <script> |
SQL query execution via System.Data.SqlClient |
Windows only. Fallback when Go TDS driver fails with "untrusted domain" error. Not used when --proxy is set. |
powershell.exe |
-NoProfile -NonInteractive -Command <script> |
SPN enumeration via [adsisearcher] (ADSI) |
Windows only. Fallback when Go LDAP client fails. |
powershell.exe |
-NoProfile -NonInteractive -Command <script> |
Domain computer enumeration via [adsisearcher] (ADSI) |
Windows only. Fallback when Go LDAP client fails. |
powershell.exe |
-NoProfile -NonInteractive -Command <script> |
SPN lookup by hostname via [adsisearcher] (ADSI) |
Windows only. Fallback when Go LDAP client fails. |
powershell.exe |
-NoProfile -NonInteractive -EncodedCommand <base64> |
Remote PowerShell via WinRM: EPA registry configuration and SQL service restart on target host | Only test-epa-matrix subcommand. Executes on the remote target via WinRM. |
All queries are read-only. No data is written to any target server.
| Query | Purpose |
|---|---|
SELECT SERVERPROPERTY('ServerName'), SERVERPROPERTY('MachineName'), SERVERPROPERTY('InstanceName'), SERVERPROPERTY('ProductVersion'), SERVERPROPERTY('Edition'), ... |
Server name, version, edition |
SELECT @@VERSION |
Full version string |
SERVERPROPERTY('IsIntegratedSecurityOnly') |
Authentication mode (Windows-only vs mixed) |
| Query | Purpose |
|---|---|
SELECT ... FROM sys.server_principals |
Enumerate logins and server roles |
SELECT ... FROM sys.server_role_members JOIN sys.server_principals |
Map server role membership |
SELECT ... FROM sys.server_permissions |
Enumerate server-level permissions (GRANT, DENY) |
| Query | Purpose |
|---|---|
SELECT ... FROM sys.databases |
List databases with owner SID, trustworthy flag, state |
| Query | Purpose |
|---|---|
SELECT ... FROM [db].sys.database_principals |
Enumerate users and roles per database |
SELECT ... FROM [db].sys.database_role_members |
Map database role membership |
SELECT ... FROM [db].sys.database_permissions |
Enumerate database-level permissions |
MSSQLHound uses a three-tier resolution strategy to identify the domain account running the SQL Server service:
| # | Method | Query / Action | Works On | Conditions |
|---|---|---|---|---|
| 1 | sys.dm_server_services |
SELECT servicename, service_account, startup_type_desc FROM sys.dm_server_services WHERE servicename LIKE 'SQL Server%' AND servicename NOT LIKE 'SQL Server Agent%' |
Windows | SQL 2008 R2+. On Linux this view typically returns only the Agent row, so no engine service account is found. |
| 2 | Registry | EXEC master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE', N'SYSTEM\CurrentControlSet\Services\...', N'ObjectName' |
Windows | Fallback when sys.dm_server_services returns no rows or the user lacks permission. Not available on Linux. |
| 3 | AD SPN lookup | LDAP search for (servicePrincipalName=MSSQLSvc/<host>*) |
Windows & Linux | Fallback when both SQL query methods fail. Resolves the service account from the AD object that owns the MSSQLSvc SPN for the target host. Requires LDAP connectivity to a domain controller. |
If all three methods fail, a warning is logged: Could not determine service account (sys.dm_server_services, registry, and SPN lookup all failed).
| Query | Purpose |
|---|---|
EXEC master.dbo.xp_instance_regread ... 'SuperSocketNetLib', 'ForceEncryption' |
Check Force Encryption setting |
EXEC master.dbo.xp_instance_regread ... 'SuperSocketNetLib', 'ExtendedProtection' |
Check Extended Protection (EPA) setting |
| Query | Purpose |
|---|---|
SELECT ... FROM sys.credentials |
Enumerate server-level credentials |
SELECT ... FROM [db].sys.database_scoped_credentials |
Enumerate database-scoped credentials |
SELECT ... FROM sys.server_principal_credentials |
Map login-to-credential relationships |
SELECT ... FROM msdb.dbo.sysproxies |
Enumerate SQL Agent proxy accounts |
SELECT ... FROM msdb.dbo.sysproxylogin |
Map proxy-to-login authorization |
SELECT ... FROM msdb.dbo.sysproxysubsystem |
Map proxy-to-subsystem relationships |
| Query | Purpose |
|---|---|
SELECT ... FROM sys.servers JOIN sys.linked_logins |
Enumerate linked servers and login mappings |
SELECT ... FROM OPENQUERY([LinkedServer], '...') |
Linked server relationship discovery across chained links (up to 10 levels deep) |
No files are written to any target server. All artifacts are created on the operator's machine.
{system temp or --temp-dir}/
mssql-bloodhound-YYYYMMDD-HHMMSS/
mssql-{hostname}.json Per-server BloodHound data (default port/instance)
mssql-{hostname}_{port}.json Non-default port
mssql-{hostname}_{port}_{instance}.json Named instance
mssql-{hostname}.log Per-server log (only if per-target logging enabled)
computers.json AD computer nodes (unless --skip-ad-nodes)
users.json AD user nodes (unless --skip-ad-nodes)
groups.json AD group nodes (unless --skip-ad-nodes)
{current directory or --zip-dir}/
mssql-bloodhound-YYYYMMDD-HHMMSS.zip Final output (contains all JSON files above)
mssql-logs-YYYYMMDD-HHMMSS.zip Log archive (only if per-target logging enabled)
| Component | Rule |
|---|---|
| Default port (1433) | Omitted from filename |
Default instance (MSSQLSERVER) |
Omitted from filename |
| Separator | Underscore (_) between hostname, port, instance |
| Special characters | \ / : * ? " < > | replaced with _ |
The temporary directory is removed after the zip file is created. The only persistent artifacts are the zip file(s) in --zip-dir (default: current directory).
The original MSSQLHound PowerShell script is an excellent tool for SQL Server security analysis, but has some limitations that motivated this Go port:
- Proxying: PowerShell execution is easily detected. The Go version allows network traffic to be sent into the target environment through a SOCKS proxy to maintain stealth during offensive operations.
- Concurrent Processing: The Go version processes multiple SQL servers simultaneously using worker pools, significantly reducing total enumeration time in large environments
- Streaming Output: Memory-efficient JSON streaming prevents memory exhaustion when collecting from servers with thousands of principals
- Compiled Binary: No PowerShell interpreter overhead, faster startup and execution
- Cross-Platform: Runs on Windows, Linux, and macOS (implicit SSPI is Windows-only; explicit Kerberos with
-kworks cross-platform) - Single Binary: No dependencies, easy to deploy and run
- No PowerShell Required: Can run on systems without PowerShell installed
- PowerShell Fallback: When the native Go SQL driver fails (e.g., certain SSPI configurations), automatically falls back to PowerShell's
System.Data.SqlClientfor maximum compatibility - Full Feature Parity: Produces identical BloodHound-compatible output
- Strongly Typed: Go's type system catches errors at compile time
- Unit Testable: Comprehensive test coverage for edge generation logic
- Modular Architecture: Clean separation between collection, graph generation, and output
- SQL Server Collection: Enumerates server principals (logins, server roles), databases, database principals (users, roles), permissions, and role memberships
- Linked Server Discovery: Maps SQL Server linked server relationships
- Active Directory Integration: Resolves Windows logins to domain principals via LDAP
- BloodHound Output: Produces OpenGraph JSON format compatible with BloodHound CE
- Streaming Output: Memory-efficient streaming JSON writer for large environments
- Automatic Fallback: Falls back to PowerShell for servers with SSPI issues
- LDAP Paging: Handles large domains with thousands of computers/SPNs
go build -o mssqlhound.exe ./cmd/mssqlhoundCollect from a single SQL Server:
# Windows integrated authentication
./mssqlhound -t sql.contoso.com
# SQL authentication
./mssqlhound -t sql.contoso.com -u sa -p password
# Inline credentials (equivalent to the above)
./mssqlhound -t 'sa:password@sql.contoso.com'
# Named instance
./mssqlhound -t 'sql.contoso.com\INSTANCE'
# Custom port
./mssqlhound -t 'sql.contoso.com:1434'
# Inline credentials with named instance
./mssqlhound -t 'sa:password@sql.contoso.com\INSTANCE'
# Inline credentials with SPN format
./mssqlhound -t 'CONTOSO\admin:password@MSSQLSvc/sql.contoso.com:1433'# Comma-separated list
./mssqlhound -t 'server1,server2,server3' -u sa -p password
# Comma-separated with inline credentials
./mssqlhound -t 'sa:password@server1,sa:password@server2,sa:password@server3'
# From file (one server per line, supports user:pass@host per line)
./mssqlhound -t servers.txt
# With concurrent workers
./mssqlhound -t servers.txt -w 20# Scan all computers in the domain (not just those with SQL SPNs)
./mssqlhound --scan-all-computers
# With explicit LDAP credentials (recommended for large domains)
./mssqlhound --scan-all-computers --ldap-user "DOMAIN\username" --ldap-password "password"
# Specifying domain controller IP (also used as DNS resolver)
./mssqlhound --scan-all-computers --dc 10.0.0.1 --ldap-user "DOMAIN\username" --ldap-password "password"# Use a specific DNS resolver for domain lookups
./mssqlhound --scan-all-computers --dns-resolver 10.0.0.1
# Specify DC IP (automatically used as DNS resolver if --dns-resolver is not set)
./mssqlhound --scan-all-computers --dc 10.0.0.1
# Use separate DNS resolver and DC
./mssqlhound --scan-all-computers --dc 10.0.0.1 --dns-resolver 10.0.0.2All network traffic (SQL connections, LDAP queries, EPA tests) can be tunneled through a SOCKS5 proxy:
# Basic SOCKS5 proxy
./mssqlhound -t sql.contoso.com --proxy 127.0.0.1:1080
# With proxy authentication
./mssqlhound -t sql.contoso.com --proxy "socks5://user:pass@127.0.0.1:1080"
# Combined with domain enumeration
./mssqlhound --scan-all-computers --proxy 127.0.0.1:1080 --dc 10.0.0.1Note: SQL Browser (UDP) resolution is not supported through SOCKS5 proxies. Named instances must include explicit ports (e.g., sql.contoso.com\INSTANCE:1433).
When --ldap-user and --ldap-password are not specified, the tool automatically reuses SQL credentials for LDAP authentication if the --user value contains a domain delimiter (\ or @):
# These domain credentials are used for both SQL and LDAP
./mssqlhound --scan-all-computers -u "DOMAIN\admin" -p "password"# Use ccache from KRB5CCNAME env var
./mssqlhound -t sql.contoso.com -k
# Explicit ccache file
./mssqlhound -t sql.contoso.com -k --krb5-credcachefile /tmp/krb5cc_1000
# Use a keytab file
./mssqlhound -t sql.contoso.com -k \
--user "CONTOSO\svc_mssqlhound" \
--krb5-keytabfile /etc/mssqlhound.keytab \
--krb5-realm CONTOSO.COM
# Custom krb5.conf
./mssqlhound -t sql.contoso.com -k --krb5-configfile /etc/krb5_custom.conf# Authenticate with an NT hash instead of a plaintext password
./mssqlhound -t sql.contoso.com -u "CONTOSO\admin" --nt-hash aad3b435b51404eeaad3b435b51404ee
# Combined with domain enumeration
./mssqlhound --scan-all-computers --dc 10.0.0.1 \
-u "CONTOSO\admin" --nt-hash aad3b435b51404eeaad3b435b51404ee# List SQL servers discovered via SPNs without connecting to them
./mssqlhound --domain-enum-only --dc 10.0.0.1 \
--ldap-user "CONTOSO\user" --ldap-password "password"
# List all domain computers (not just SPN holders)
./mssqlhound --domain-enum-only --scan-all-computers --dc 10.0.0.1# Disable non-traversable edges (attack-path-focused output)
./mssqlhound -t sql.contoso.com --disable-nontraversable-edges# Save zip file to a specific directory
./mssqlhound -t sql.contoso.com --zip-dir /data/collections/
# Use a custom temporary directory for intermediate files
./mssqlhound -t servers.txt --temp-dir /tmp/mssqlhound
# Stop collecting after 500MB of data
./mssqlhound -t servers.txt --file-size-limit 500MB
# Save per-target log files in a separate zip archive (useful for debugging)
./mssqlhound -t servers.txt --log-per-target# Shorthand: collect and upload schema + results in one shot
./mssqlhound -t 'sa:password@sql.contoso.com' \
-B '<token-id>:<token-key>@https://bloodhound.contoso.com'
# Shorthand with inline target credentials and domain enumeration
./mssqlhound -t 'CONTOSO\admin:password@sql.contoso.com' -d contoso.com \
-B '<token-id>:<token-key>@https://bloodhound.contoso.com'
# Via environment variables
export BLOODHOUND_URL=https://bloodhound.contoso.com
export BLOODHOUND_TOKEN_ID=<token-id>
export BLOODHOUND_TOKEN_KEY=<token-key>
./mssqlhound -t sql.contoso.com -u sa -p password --upload-results-only
# Explicit long flags
./mssqlhound -t sql.contoso.com -u sa -p password \
--bloodhound-url https://bloodhound.contoso.com \
--token-id <id> --token-key <key> \
--upload-results-only
# Upload the MSSQL schema once to register edge/node types in BloodHound
./mssqlhound \
--bloodhound-url https://bloodhound.contoso.com \
--token-id <id> --token-key <key> \
--upload-schema-only --skip-collection# Disable possible edges (stricter pathfinding, fewer false positives)
./mssqlhound -t sql.contoso.com --disable-possible-edges
# Skip AD node creation (collect only MSSQL nodes, no User/Group/Computer nodes)
./mssqlhound -t sql.contoso.com --skip-ad-nodes# Skip linked server enumeration (faster, less noisy)
./mssqlhound -t sql.contoso.com --skip-linked-servers
# Queue discovered linked servers as additional direct targets for later collection passes
./mssqlhound -t sql.contoso.com --collect-from-linked
# Reduce linked server timeout from the default 300s
./mssqlhound -t sql.contoso.com --linked-timeout 60Tests all combinations of Force Encryption, Force Strict Encryption, and Extended Protection by modifying registry settings via WinRM and restarting the SQL Server service. Requires WinRM access and domain credentials.
# Test all EPA setting combinations (12 combinations for SQL Server 2022+)
./mssqlhound test-epa-matrix -t sql.contoso.com -u "CONTOSO\admin" -p "password"
# Named instance, skip strict encryption combos (for pre-SQL Server 2022)
./mssqlhound test-epa-matrix -t "sql.contoso.com\INST" \
--sql-instance-name INST --skip-strict \
-u "CONTOSO\admin" -p "password"
# Use HTTPS for WinRM
./mssqlhound test-epa-matrix -t sql.contoso.com --winrm-https \
-u "CONTOSO\admin" -p "password"# Bash
source <(mssqlhound completion bash)
# Zsh
source <(mssqlhound completion zsh)
# Fish
mssqlhound completion fish | source
# PowerShell
mssqlhound completion powershell | Out-String | Invoke-Expression| Flag | Description |
|---|---|
-t, --targets |
SQL Server targets: [user:pass@]host, host:port, host\instance, MSSQLSvc/host:port, comma-separated list, or file path (default: enumerate domain MSSQLSvc SPNs) |
-u, --user |
SQL login username |
-p, --password |
SQL login password |
--nt-hash |
NT hash (32 hex chars) for pass-the-hash authentication (mutually exclusive with --password) |
-k, --kerberos |
Use Kerberos authentication (reads ccache from KRB5CCNAME env var or --krb5-credcachefile) |
--krb5-configfile |
Path to krb5.conf (default: /etc/krb5.conf or KRB5_CONFIG env var) |
--krb5-credcachefile |
Path to Kerberos credential cache file (overrides KRB5CCNAME env var) |
--krb5-keytabfile |
Path to Kerberos keytab file |
--krb5-realm |
Kerberos realm (default: derived from domain or krb5.conf) |
| Flag | Description |
|---|---|
-d, --domain |
Domain to use for name and SID resolution |
--dc |
Domain controller hostname or IP (auto-resolved from --domain if omitted; used for LDAP and as DNS resolver if --dns-resolver not specified) |
--dns-resolver |
DNS resolver IP address for domain lookups |
--ldap-user |
Domain user (DOMAIN\user or user@domain) for LDAP queries and EPA testing; not used for SQL login |
--ldap-password |
Password for --ldap-user; used for LDAP bind and EPA NTLM, not for SQL login |
| Flag | Description |
|---|---|
-t, --targets |
Targets (see Authentication above): single, comma-separated, or file path |
-A, --scan-all-computers |
Scan all domain computers, not just those with SQL SPNs |
--skip-private-address |
Skip private IP check when resolving domain computer addresses |
| Flag | Default | Description |
|---|---|---|
--domain-enum-only |
false | Only enumerate SPNs/computers, skip MSSQL collection |
--skip-linked-servers |
false | Don't enumerate linked servers |
--collect-from-linked |
false | Queue discovered linked servers as additional direct targets and collect them in later passes |
--linked-timeout |
300 | Linked server enumeration timeout (seconds) |
--skip-ad-nodes |
false | Skip creating User, Group, Computer nodes |
--disable-nontraversable-edges |
false | Disable non-traversable edges |
--disable-possible-edges |
false | Disable possible edges (makes them non-traversable in schema and edge data) |
-w, --workers |
0 | Number of concurrent workers (0 = sequential processing) |
| Flag | Default | Description |
|---|---|---|
--temp-dir |
system temp | Temporary directory for output files |
--zip-dir |
. |
Directory for the final zip file |
--file-size-limit |
1GB |
Stop enumeration after output files exceed this size |
--log-per-target |
false | Save per-target log files in a separate zip archive |
--memory-threshold |
90 | Stop when memory usage exceeds this percentage |
| Flag | Env Var | Description |
|---|---|---|
-B, --bloodhound |
Upload to BloodHound CE: <token-id>:<token-key>@<bloodhound_url> (uploads schema + results) |
|
--bloodhound-url |
BLOODHOUND_URL |
BloodHound CE instance URL |
--token-id |
BLOODHOUND_TOKEN_ID |
BloodHound API token ID |
--token-key |
BLOODHOUND_TOKEN_KEY |
BloodHound API token key |
--upload-schema-only |
Only upload schema definitions to BloodHound (skip results upload) | |
--upload-results-only |
Only upload collection results to BloodHound (skip schema upload) | |
--skip-collection |
Skip data collection (use with schema upload or upload-only workflows) |
| Flag | Description |
|---|---|
-v, --verbose |
Enable verbose output showing detailed collection progress |
--debug |
Enable debug output (includes EPA/TLS/NTLM diagnostics) |
--proxy |
SOCKS5 proxy address for tunneling all traffic (host:port or socks5://[user:pass@]host:port) |
| Feature | PowerShell | Go |
|---|---|---|
| Concurrency | Single-threaded | Multi-threaded with configurable worker pool |
| Memory Usage | Loads all data in memory | Streaming JSON output |
| Cross-Platform | Windows only | Windows, Linux, macOS |
| SSPI Fallback | N/A (native .NET) | Falls back to PowerShell for problematic servers |
| LDAP Paging | Automatic via .NET | Explicit paging implementation |
| Duplicate Edges | May emit duplicates | De-duplicates edges |
| Aspect | PowerShell | Go |
|---|---|---|
| Domain Validation | Calls Resolve-DomainPrincipal to verify the SID exists in Active Directory |
Creates edges for all domain SIDs (S-1-5-21-*) |
| Orphaned Logins | Skips logins where AD account no longer exists | Includes all logins regardless of AD status |
| Edge Count | Fewer edges (only verified AD accounts) | More edges (all domain-authenticated logins) |
Why Go includes more edges: For security analysis, orphaned SQL logins (where the AD account was deleted but the SQL login remains) still represent valid attack paths. An attacker who can restore or impersonate the deleted account's SID could still authenticate to SQL Server. The Go version captures these potential risks.
| Aspect | PowerShell | Go |
|---|---|---|
| Self-referencing | Creates edge when computer runs SQL as itself (LocalSystem) | Skips self-referencing edges |
Why Go skips self-loops: A HasSession edge from a computer to itself (when SQL Server runs as LocalSystem/the computer account) doesn't provide meaningful attack path information.
| Aspect | PowerShell | Go |
|---|---|---|
| Duplicates | May emit duplicate edges | De-duplicates all edges |
Why Go has fewer edges: The PowerShell version may emit the same AddMember edge multiple times in certain scenarios. Go ensures each unique edge is only emitted once.
The Go version includes automatic PowerShell fallback for servers that fail with the native go-mssqldb driver:
Native connection: go-mssqldb (fast, cross-platform)
↓ fails with "untrusted domain" error
Fallback: PowerShell + System.Data.SqlClient (Windows only, more compatible)
This ensures maximum compatibility while maintaining performance for the majority of servers.
The Go version tries multiple LDAP connection methods in order:
- LDAPS (port 636) - TLS encrypted, most secure
- LDAP + StartTLS (port 389) - Upgrade to TLS
- Plain LDAP (port 389) - Unencrypted (may fail if DC requires signing)
- PowerShell/ADSI Fallback - Windows COM-based fallback
The Go version includes detection for SQL Server vulnerabilities:
Checks if the SQL Server version is vulnerable to CVE-2025-49758 and reports the status:
VULNERABLE- Server is running an affected versionNOT vulnerable- Server has been patched
Native Windows SSPI is only available on Windows. On Linux/macOS, use SQL authentication or explicit Kerberos material with -k (for example KRB5CCNAME, --krb5-credcachefile, or --krb5-keytabfile).
The Go LDAP library's GSSAPI implementation may fail in certain environments with errors like:
LDAP Result Code 49 "Invalid Credentials": 80090346: LdapErr: DSID-0C0906CF,
comment: AcceptSecurityContext error, data 80090346
Common causes:
- Channel binding token (CBT) mismatch between client and server
- Kerberos ticket issues (expired, clock skew, wrong realm)
- Domain controller requires specific LDAP signing/sealing options
Solutions:
-
Use explicit LDAP credentials (recommended for
--scan-all-computers):./mssqlhound --scan-all-computers --ldap-user "DOMAIN\username" --ldap-password "password"
-
Verify Kerberos tickets:
klist # Check current tickets klist purge # Clear and re-acquire tickets
-
Check time synchronization - Kerberos requires clocks within 5 minutes
Active Directory has a default maximum result size of 1000 objects per query. The Go version implements LDAP paging to handle domains with more than 1000 computers or SPNs. If you see "Size Limit Exceeded" errors, ensure you're using the latest version.
Some SQL Server instances with specific SSPI configurations may fail to connect with the native Go driver.
Symptom:
Login failed. The login is from an untrusted domain and cannot be used with Windows authentication
Automatic Handling: The Go version detects this error and automatically retries using PowerShell's System.Data.SqlClient, which handles these edge cases more reliably. This fallback requires PowerShell to be available on the system.
The PowerShell fallback for SQL connections and AD enumeration requires:
- Windows operating system
- PowerShell execution not blocked by security policy
- Access to
System.Data.SqlClient(.NET Framework)
If PowerShell is blocked (e.g., Access is denied error), the fallback will not work. In this case:
- For SQL connections: Some servers may not be reachable
- For AD enumeration: Use explicit LDAP credentials instead
Use --ldap-user and --ldap-password when:
- Full domain computer enumeration (
--scan-all-computers) - GSSAPI often fails with the Go library due to CBT issues - Cross-domain scenarios - When enumerating from a machine in a different domain
- Service account execution - When running as a service account that may have Kerberos delegation issues
- Troubleshooting GSSAPI failures - As a workaround when implicit authentication fails
Example:
# Recommended for large domain enumeration
./mssqlhound --scan-all-computers \
--ldap-user "DOMAIN\svc_mssqlhound" \
--ldap-password "SecurePassword123" \
-w 50Use -v or --verbose to see detailed connection attempts and errors:
./mssqlhound -t sql.contoso.com -u sa -p password -v| Error | Cause | Solution |
|---|---|---|
untrusted domain |
SSPI negotiation failed | Automatic PowerShell fallback; check domain trust |
Size Limit Exceeded |
Too many LDAP results | Update to latest version (has paging) |
80090346 |
GSSAPI/Kerberos failure | Use explicit LDAP credentials |
Strong Auth Required |
DC requires LDAP signing | Will automatically try LDAPS/StartTLS |
Access is denied (PowerShell) |
Execution policy blocked | Use explicit LDAP credentials instead |
The verbose output shows which LDAP connection methods are attempted:
LDAPS:636 GSSAPI: <error>
LDAP:389+StartTLS GSSAPI: <error>
LDAP:389 GSSAPI: <error>
This helps identify whether the issue is TLS-related or authentication-related.
The PowerShell collector is the legacy implementation. Current development is focused on the Go binary above, and the script now lives at powershell_deprecated/MSSQLHound.ps1.
Run MSSQLHound from a box where you aren’t highly concerned about resource consumption. While there are guardrails in place to stop the script if resource consumption is too high, it’s probably a good idea to be careful and run it on a workstation instead of directly on a critical database server, just in case.
If you don't already have a specific target or targets in mind, start by running the script with the -DomainEnumOnly flag set to see just how many servers you’re dealing with in Active Directory. Then, use the -ServerInstance option to run it again for a single server or add all of the servers that look interesting to a file and run it again with the -ServerListFile option.
If you don't do a dry run first and collect from all SQL servers with SPNs in the domain (the default action), expect the script to take a very long time to finish and eat up a ton of disk space if there ar a lot of servers in the environment. Based on limited testing in client environments, the file size for each server before they are all zipped ranges significantly from 2MB to 50MB+, depending on how many objects are on the server.
To populate the MSSQL node glyphs in BloodHound, execute powershell_deprecated/MSSQLHound.ps1 -OutputFormat BloodHound-customnodes (or copy the following) and use the API Explorer page to submit the JSON to the custom-nodes endpoint.
{
"custom_types": {
"MSSQL_DatabaseUser": {
"icon": {
"name": "user",
"color": "#f5ef42",
"type": "font-awesome"
}
},
"MSSQL_Login": {
"icon": {
"name": "user-gear",
"color": "#dd42f5",
"type": "font-awesome"
}
},
"MSSQL_DatabaseRole": {
"icon": {
"name": "users",
"color": "#f5a142",
"type": "font-awesome"
}
},
"MSSQL_Database": {
"icon": {
"name": "database",
"color": "#f54242",
"type": "font-awesome"
}
},
"MSSQL_ApplicationRole": {
"icon": {
"name": "robot",
"color": "#6ff542",
"type": "font-awesome"
}
},
"MSSQL_Server": {
"icon": {
"name": "server",
"color": "#42b9f5",
"type": "font-awesome"
}
},
"MSSQL_ServerRole": {
"icon": {
"name": "users-gear",
"color": "#6942f5",
"type": "font-awesome"
}
}
}
}
There are several new edges that have to be non-traversable because they are not abusable 100% of the time, including when:
- the stored AD credentials might be stale/invalid, but maybe they are!
- MSSQL_HasMappedCred
- MSSQL_HasDBScopedCred
- MSSQL_HasProxyCred
- the server principal that owns the database does not have complete control of the server, but maybe it has other interesting permissions
- MSSQL_IsTrustedBy
- the server is linked to another server using a principal that does not have complete control of the remote server, but maybe it has other interesting permissions
- MSSQL_LinkedTo
- the service account can be used to impersonate domain users that have a login to the server, but we don’t have the necessary permissions to check that any domain users have logins
- MSSQL_ServiceAccountFor
- It would be unusual, but not impossible, for the MSSQL Server instance to run in the context of a domain service account and have no logins for domain users. If you can infer that certain domain users have access to a particular MSSQL Server instance or discover that information through other means (e.g., naming conventions, OSINT, organizational documentation, internal communications, etc.), you can request service tickets for those users to the MSSQL Server if you have control of the service account (e.g., by cracking weak passwords for Kerberoastable service principals).
In the deprecated PowerShell script as currently shipped, these edges are effectively traversable by default because -MakeInterestingEdgesTraversable is initialized on. If you modify the script or explicitly pass the switch as false, that setting controls whether they remain non-traversable.
I also recommend conducting a collection with the -IncludeNontraversableEdges flag enabled at some point if you need to understand what permissions on which objects allow the traversable edges to be created. By default, non-traversable edges are skipped to make querying the data for valid attack paths easier. This is still a work in progress, but look out for the “Composition” item in the edge entity panel for each traversable edges to grab a pastable cypher query to identify the offending permissions.
If the prebuilt Cypher queries are returning failed to translate kinds: unable to map kinds: errors, upload seed_data.json to populate a single fake instance of each new edge class so they can be queried.
For the latest and most reliable information, please execute powershell_deprecated/MSSQLHound.ps1 -Help.
| Option ______________________________________________ |
Values _______________________________________________________________________________________________ |
|---|---|
-Help <switch> |
• Display usage information |
-OutputFormat <string> |
• BloodHound: OpenGraph implementation that collects data in separate files for each MSSQL server, then zips them up and deletes the originals. The zip can be uploaded to BloodHound by navigating to Administration > File Ingest• BloodHound-customnodes: Generate JSON to POST to custom-nodes API endpoint• BloodHound-customnode: Generate JSON for DELETE on custom-nodes API endpoint• BHGeneric: Work in progress to make script compatible with BHOperator |
-ServerInstance <string> |
• A specific MSSQL instance to collect from: • Null: Query the domain for SPNs and collect from each server found • Name/FQDN: <host>• Instance: <host>[:<port>|:<instance_name>]• SPN: <service class>/<host>[:<port>|:<instance_name>] |
-ServerListFile <string> |
• Specify the path to a file containing multiple server instances to collect from in the ServerInstance formats above |
-ServerList <string> |
• Specify a comma-separated list of server instances to collect from in the ServerInstance formats above |
-TempDir <string> |
• Specify the path to a temporary directory where .json files will be stored before being zipped Default: new directory created with [System.IO.Path]::GetTempPath() |
-ZipDir <string> |
• Specify the path to a directory where the final .zip file will be stored • Default: current directory |
-MemoryThresholdPercent <uint> |
• Maximum memory allocation limit, after which the script will exit to prevent availability issues • Default: 90 |
-Credential <PSCredential> |
• Specify a PSCredential object to connect to the remote server(s) |
-UserID <string> |
• Specify a login to connect to the remote server(s) |
-SecureString <SecureString> |
• Specify a SecureString object for the login used to connect to the remote server(s) |
-Password <string> |
• Specify a password for the login used to connect to the remote server(s) |
-Domain <string> |
• Specify a domain to use for name and SID resolution |
-DomainController <string> |
• Specify a domain controller FQDN/IP to use for name and SID resolution |
| -IncludeNontraversableEdges (switch) | • On: • Collect both traversable and non-traversable edges • Off (default): Collect only traversable edges (good for offensive engagements until Pathfinding supports OpenGraph edges) |
| -MakeInterestingEdgesTraversable (switch) | • On: Make the following edges traversable (useful for offensive engagements but prone to false positive edges that may not be abusable): • MSSQL_HasDBScopedCred • MSSQL_HasMappedCred • MSSQL_HasProxyCred • MSSQL_IsTrustedBy • MSSQL_LinkedTo • MSSQL_ServiceAccountFor • Current shipped default: effectively On in the deprecated script |
| -SkipLinkedServerEnum (switch) | • On: Don't enumerate linked servers • Off (default): Enumerate linked servers |
| -CollectFromLinkedServers (switch) | • On: Queue discovered linked servers as additional direct targets and collect them in later passes • Off (default): Discover linked server relationships, but don't add those servers to the processing queue |
| -DomainEnumOnly (switch) | • On: If SPNs are found, don't try and perform a full MSSQL collection against each server • Off (default): If SPNs are found, try and perform a full MSSQL collection against each server |
| -InstallADModule (switch) | • On: Try to install the ActiveDirectory module for PowerShell if it is not already installed • Off (default): Do not try to install the ActiveDirectory module for PowerShell if it is not already installed. Rely on DirectoryServices, ADSISearcher, DirectorySearcher, and NTAccount.Translate() for object resolution. |
-LinkedServerTimeout <uint> |
• Give up enumerating linked servers after X seconds• Default: 300 seconds (5 minutes) |
-FileSizeLimit <string> |
• Stop enumeration after all collected files exceed this size on disk • Supports MB, GB • Default: 1GB |
-FileSizeUpdateInterval <uint> |
• Receive periodic size updates as files are being written for each server • Default: 5 seconds |
-Version <switch> |
• Display version information and exit |
- MSSQLHound can discover linked servers and queue them as additional direct targets, but it still does not perform a full node-and-edge collection through an existing linked-server session.
- MSSQLHound doesn’t check
DENYpermissions broadly. One exception isDENY CONNECT SQL, which is checked to determine whether a principal can remotely log in to the instance at all. - MSSQLHound stops enumerating at the database level. It does not descend into tables, stored procedures, or columns.
- Separate collections in domains that can’t resolve each other’s principals may not merge cleanly when ingested (for example, one
MSSQL_Servernode identified by SID and another by hostname may represent the same server).
- Option to zip after every server (to save disk space)
- Full collection through existing linked-server sessions
- Collect across domains and trusts
- Azure extension for SQL Server
- AZUser/Groups for server logins / database users
- Cross database ownership chaining
- DENY permissions
- EXECUTE permission on xp_cmdshell
- UNSAFE/EXTERNAL_ACCESS permission on assembly (impacted by TRUSTWORTHY)

The entire installation of the MSSQL Server database management system (DBMS) that contains multiple databases and server-level objects
| Property ______________________________________________ |
Definition _______________________________________________________________________________________________ |
|---|---|
| Label: string | • Format: <name>[:<port>|:<instance_name>]• Examples: • SQL.MAYYHEM.COM (default port and instance name)• SQL.MAYYHEM.COM:SQL2012 (named instance) |
| Object ID: string | • Format: <computer_domain_sid>:<port|instance_name>• Example: S-1-5-21-843997178-3776366836-1907643539-1108:1433• Port or instance name should be a part of the identifier in case there are multiple MSSQL Server instances on the same host. • Two or more accounts are permitted to have identical SPNs in Active Directory (https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/setspn), and two or more names may resolve to the same host (e.g., MSSQLSvc/ps1-db:1433 and MSSQLSvc/ps1-db.mayyhem.com:1433) so we will use the domain SID instead of the host portion of the SPN, when available.• MSSQLSvc SPNs may contain an instance name instead of the port, in which case the SQL Browser service ( UDP/1434) is used to determine the listening port for the MSSQL server. In other cases the port is dynamically chosen and the SPN updated when the service [re]starts. The ObjectIdentifier must be capable of storing either value in case there is an instance name in the SPN and the SQL Browser service is not reachable, and prefer instance over port.• The script currently falls back to using the FQDN instead of the SID if the server can't be resolved to a domain object (for example, if it is resolved via DNS or reachable via the MSSQL port but can't be resolved to a principal in another domain). • This format complicates things when trying to merge objects from collections taken from different domains, with different privileges, or when servers are discovered via SQL links. For example, when collecting from hostA.domain1.local, a link to hostB.domain2.local:1433 is discovered. The collector can't resolve principals in domain2, so its ObjectIdentifier is the hostname:port instead. However, hostB.domain2.local is reachable on port 1433 and after connecting, the collector determines that its instance name is SQLHOSTB. Later, a collection is done on HostB from within domain2, so its ObjectIdentifier is either sid:port or sid:instanceName, depending on what's in the SPNs. |
| Databases: List<string> | • Names of databases contained in the SQL Server instance |
| Extended Protection: string ( Off | Allowed | Required | Allowed/Required) |
• Allowed and required both prevent authentication relay to MSSQL (using service binding if Force Encryption is No, using channel binding if Force Encryption is Yes). |
| Force Encryption: string ( No | Yes) |
• Does the server require clients to encrypt communications? |
| Has Links From Servers: List<string> | • SQL Server instances that have a link to this SQL Server instance • There is no way to view this using SSMS or other native tools on the target of a link. |
| Instance Name: string | • SQL Server instances are identified using either a port or an instance name. • Default: MSSQLSERVER |
| Is Any Domain Principal Sysadmin: bool | • If a domain principal is a member of the sysadmin server role or has equivalent permissions (securityadmin, CONTROL SERVER, or IMPERSONATE ANY LOGIN), the domain service account running MSSQL can impersonate such a principal to gain control of the server via S4U2Silver. See the MSSQL_GetAdminTGS edge for more information. |
| Is Linked Server Target: bool | • Does any SQL Server instance have a link to this SQL Server instance? • There is no way to view this using SSMS or other native tools on the target of a link. |
| Is Mixed Mode Auth Enabled: bool | • True: both Windows and SQL logins are permitted to access the server remotely • False: only Windows logins are permitted to access the server remotely |
| Linked To Servers: List<string> | • SQL Server instances that this SQL Server instance is linked to |
| Port: uint | • SQL Server instances are identified using either a port or an instance name. • Default: 1433 |
| Service Account: string | • The Windows account running the SQL Server instance |
| Service Principal Names: List<string> | • SPNs associated with this SQL Server instance |
| Version: string | • Result of SELECT @@VERSION |

A type of server principal that can be assigned permissions to access server-level objects, such as the ability to connect to the instance or modify server role membership. These principals can be local to the instance (SQL logins) or mapped to a domain user, computer, or group (Windows logins). Server logins can be added as members of server roles to inherit the permissions assigned to the role.
| Property ______________________________________________ |
Definition _______________________________________________________________________________________________ |
|---|---|
| Label: string | • Format: <name>• Example: MAYYHEM\sqladmin |
| Object ID: string | • Format: <name>@<mssqlserver_object_id>• Example: MAYYHEM\sqladmin@S-1-5-21-843997178-3776366836-1907643539-1108:1433 |
| Active Directory Principal: string | • Name of the AD principal this login is mapped to |
| Active Directory SID: string | • SID of the AD principal this login is mapped to |
| Create Date: datetime | • When the login was created |
| Database Users: List<string> | • Names of each database user this login is mapped to |
| Default Database: string | • The default database used when the login connects to the server |
| Disabled: bool | • Is the account disabled? |
| Explicit Permissions: List<string> | • Server level permissions assigned directly to this login • Does not include all effective permissions such as those granted through role membership |
| Is Active Directory Principal: bool | • If a domain principal has a login, the domain service account running MSSQL can impersonate such a principal to gain control of the login via S4U2Silver. |
| Member of Roles: List<string> | • Names of roles this principal is a direct member of • Does not include nested memberships |
| Modify Date: datetime | • When the principal was last modified |
| Principal Id: uint | • The identifier the SQL Server instance uses to associate permissions and other objects with this principal |
| SQL Server: string | • Name of the SQL Server where this object is a principal |
| Type: string | • ASYMMETRIC_KEY_MAPPED_LOGIN: Used to sign modules within the database, such as stored procedures, functions, triggers, or assemblies and can't be used to connect to the server remotely. I haven't messed with these much but they can be assigned permissions and impersonated. • CERTIFICATE_MAPPED_LOGIN: Used to sign modules within the database, such as stored procedures, functions, triggers, or assemblies and can't be used to connect to the server remotely. I haven't messed with these much but they can be assigned permissions and impersonated. • SQL_LOGIN: This login is local to the SQL Server instance and mixed-mode authentication must be enabled to connect with it • WINDOWS_LOGIN: A Windows account is mapped to this login • WINDOWS_GROUP: A Windows group is mapped to this login |

A type of server principal that can be assigned permissions to access server-level objects, such as the ability to connect to the instance or modify server role membership. Server logins and user-defined server roles can be added as members of server roles, inheriting the role's permissions.
| Property ______________________________________________ |
Definition _______________________________________________________________________________________________ |
|---|---|
| Label: string | • Format: <name>• Example: processadmin |
| Object ID: string | • Format: <name>@<mssqlserver_object_id>• Example: processadmin@S-1-5-21-843997178-3776366836-1907643539-1108:1433 |
| Create Date: datetime | • When the role was created |
| Explicit Permissions: List<string> | • Server level permissions assigned directly to this login • Does not include all effective permissions such as those granted through role membership |
| Is Fixed Role: bool | • Whether or not the role is built-in (i.e., ships with MSSQL and can't be removed) |
| Member of Roles: List<string> | • Names of roles this principal is a direct member of • Does not include nested memberships |
| Members: List<string> | • Names of each principal that is a direct member of this role |
| Modify Date: datetime | • When the principal was last modified |
| Principal Id: uint | • The identifier the SQL Server instance uses to associate permissions and other objects with this principal |
| SQL Server: string | • Name of the SQL Server where this object is a principal |

A collection of database principals (e.g., users and roles) as well as object groups called schemas, each of which contains securable database objects such as tables, views, and stored procedures.
| Property ______________________________________________ |
Definition _______________________________________________________________________________________________ |
|---|---|
| Label: string | • Format: <name>• Example: master |
| Object ID: string | • Format: <mssqlserver_object_id>\<name>• Example: S-1-5-21-843997178-3776366836-1907643539-1108:1433\master |
| Is Trustworthy: bool | • Is the Trustworthy property of this database set to True?• When Trustworthy is True, principals with control of the database are permitted to execute server level actions in the context of the database's owner, allowing server compromise if the owner has administrative privileges.• Example: If sa owns the CM_PS1 database and the database's Trustworthy property is True, then a user in the database with sufficient privileges could create a stored procedure with the EXECUTE AS OWNER statement and leverage the sa account's permissions to execute SQL statements on the server. See the MSSQL_ExecuteAsOwner edge for more information. |
| Owner Login Name: string | • Example: MAYYHEM\cthompson |
| Owner Principal ID: uint | • The identifier the SQL Server instance uses to associate permissions and other objects with this principal |
| SQL Server: string | • Name of the SQL Server where this object is a principal |

A user that has access to the specific database it is contained in. Users may be mapped to a login or may be created without a login. Users can be assigned permissions to access database-level objects, such as the ability to connect to the database, access tables, modify database role membership, or execute stored procedures. Users and user-defined database roles can be added as members of database roles, inheriting the role's permissions.
| Property ______________________________________________ |
Definition _______________________________________________________________________________________________ |
|---|---|
| Label: string | • Format: <name>@<databasename>• Example: MAYYHEM\LOWPRIV@CM_CAS |
| Object ID: string | • Format: <name>@<database_object_id>• Example: MAYYHEM\LOWPRIV@S-1-5-21-843997178-3776366836-1907643539-1117:1433\CM_CAS |
| Create Date: datetime | • When the user was created |
| Database: string | • Name of the database where this user is a principal |
| Default Schema: string | • The default schema used when the user connects to the database |
| Explicit Permissions: List<string> | • Database level permissions assigned directly to this principal • Does not include all effective permissions such as those granted through role membership |
| Member of Roles: List<string> | • Names of roles this principal is a direct member of • Does not include nested memberships |
| Modify Date: datetime | • When the principal was last modified |
| Principal Id: uint | • The identifier the SQL Server instance uses to associate permissions and other objects with this principal |
| Server Login: string | • Name of the login this user is mapped to |
| SQL Server: string | • Name of the SQL Server where this object is a principal |
| Type: string | • ASYMMETRIC_KEY_MAPPED_USER: Used to sign modules within the database, such as stored procedures, functions, triggers, or assemblies and can't be used to connect to the server remotely. I haven't messed with these much but they can be assigned permissions and impersonated. • CERTIFICATE_MAPPED_USER: Used to sign modules within the database, such as stored procedures, functions, triggers, or assemblies and can't be used to connect to the server remotely. I haven't messed with these much but they can be assigned permissions and impersonated. • SQL_USER: This user is local to the SQL Server instance and mixed-mode authentication must be enabled to connect with it • WINDOWS_USER: A Windows account is mapped to this user • WINDOWS_GROUP: A Windows group is mapped to this user |

A type of database principal that can be assigned permissions to access database-level objects, such as the ability to connect to the database, access tables, modify database role membership, or execute stored procedures. Database users, user-defined database roles, and application roles can be added as members of database roles, inheriting the role's permissions.
| Property ______________________________________________ |
Definition _______________________________________________________________________________________________ |
|---|---|
| Label: string | • Format: <name>@<databasename>• Example: db_owner@CM_CAS |
| Object ID: string | • Format: <name>@<database_object_id>• Example: db_owner@S-1-5-21-843997178-3776366836-1907643539-1117:1433\CM_CAS |
| Create Date: datetime | • When the role was created |
| Database: string | • Name of the database where this role is a principal |
| Explicit Permissions: List<string> | • Database level permissions assigned directly to this principal • Does not include all effective permissions such as those granted through role membership |
| Member of Roles: List<string> | • Names of roles this principal is a direct member of • Does not include nested memberships |
| Members: List<string> | • Names of each principal that is a direct member of this role |
| Modify Date: datetime | • When the principal was last modified |
| Principal Id: uint | • The identifier the SQL Server instance uses to associate permissions and other objects with this principal |
| SQL Server: string | • Name of the SQL Server where this object is a principal |

A type of database principal that is not associated with a user but instead is activated by an application using a password so it can interact with the database using the role's permissions.
| Property ______________________________________________ |
Definition _______________________________________________________________________________________________ |
|---|---|
| Label: string | • Format: <name>@<databasename>• Example: TESTAPPROLE@TESTDATABASE |
| Object ID: string | • Format: <name>@<database_object_id>• Example: TESTAPPROLE@S-1-5-21-843997178-3776366836-1907643539-1108:1433\TESTDATABASE |
| Create Date: datetime | • When the principal was created |
| Database: string | • Name of the database where this object is a principal |
| Default Schema: string | • The default schema used when the principal connects to the database |
| Explicit Permissions: List<string> | • Database level permissions assigned directly to this principal • Does not include all effective permissions such as those granted through role membership |
| Member of Roles: List<string> | • Names of roles this principal is a direct member of • Does not include nested memberships |
| Modify Date: datetime | • When the principal was last modified |
| Principal Id: uint | • The identifier the SQL Server instance uses to associate permissions and other objects with this principal |
| SQL Server: string | • Name of the SQL Server where this object is a principal |
This section includes explanations for edges that have their own unique properties. Please refer to the $script:EdgePropertyGenerators variable in powershell_deprecated/MSSQLHound.ps1 for the following details:
- Source and target node classes (all combinations)
- Requirements
- Default fixed roles with the permission
- Traversability
- Entity panel details (dynamically-generated)
- General
- Windows Abuse
- Linux Abuse
- OPSEC
- References
- Composition Cypher (where applicable)
| Property ______________________________________________ |
Definition _______________________________________________________________________________________________ |
|---|---|
| Database: string | • Name of the target database where the source can execute SQL statements as the server-level owning principal |
| Database Is Trustworthy: bool | • True: Database principals that can execute EXECUTE AS OWNER statements can execute actions in the context of the server principal that owns the database• False: The database isn't allowed to access resources beyond the scope of the database |
| Owner Has Control Server: bool | • True: The server principal that owns the database has the CONTROL SERVER permission, allowing complete control of the MSSQL server instance. |
| Owner Has Impersonate Any Login: bool | • True: The server principal that owns the database has the IMPERSONATE ANY LOGIN permission, allowing complete control of the MSSQL server instance. |
| Owner Has Securityadmin: bool | • True: The server principal that owns the database is a member of the securityadmin server role, allowing complete control of the MSSQL server instance. |
| Owner Has Sysadmin: bool | • True: The server principal that owns the database is a member of the sysadmin server role, allowing complete control of the MSSQL server instance. |
| Owner Login Name: string | • The name of the server login that owns the database • Example: MAYYHEM\cthompson |
| Owner Object Identifier: string | • The object identifier of the server login that owns the database |
| Owner Principal ID: uint | • The identifier the SQL Server instance uses to associate permissions and other objects with this principal |
| SQL Server: string | • Name of the SQL Server where this object is a principal |
| Property ______________________________________________ |
Definition _______________________________________________________________________________________________ |
|---|---|
| Domain Principals with ControlServer: List | • Domain principals with logins that have the CONTROL SERVER effective permission, allowing complete control of the MSSQL server instance. |
| Domain Principals with ImpersonateAnyLogin: List | • Domain principals with logins that have the IMPERSONATE ANY LOGIN effective permission, allowing complete control of the MSSQL server instance. |
| Domain Principals with Securityadmin: List | • Domain principals with membership in the securityadmin server role, allowing complete control of the MSSQL server instance. |
| Domain Principals with Sysadmin: List | • Domain principals with membership in the sysadmin server role, allowing complete control of the MSSQL server instance. |
| Property ______________________________________________ |
Definition _______________________________________________________________________________________________ |
|---|---|
| Credential ID: string | • The identifier the SQL Server instance uses to associate other objects with this principal |
| Credential Identity: string | • The domain principal this credential uses to authenticate to resources |
| Credential Name: string | • The name used to identify this credential in the SQL Server instance |
| Create Date: datetime | • When the credential was created |
| Database: string | • Name of the database where this object is a credential |
| Modify Date: datetime | • When the credential was last modified |
| Resolved SID: string | • The domain SID for the credential identity |
| Property ______________________________________________ |
Definition _______________________________________________________________________________________________ |
|---|---|
| Credential ID: uint | • The identifier the SQL Server instance uses to associate other objects with this principal |
| Credential Identity: string | • The domain principal this credential uses to authenticate to resources |
| Credential Name: string | • The name used to identify this credential in the SQL Server instance |
| Create Date: datetime | • When the credential was created |
| Modify Date: datetime | • When the credential was last modified |
| Resolved SID: string | • The domain SID for the credential identity |
| Property ______________________________________________ |
Definition _______________________________________________________________________________________________ |
|---|---|
| Authorized Principals: List | • Principals that are authorized to use this proxy credential |
| Credential ID: string | • The identifier the SQL Server instance uses to associate other objects with this principal |
| Credential Identity: string | • The domain principal this credential uses to authenticate to resources |
| Credential Name: string | • The name used to identify this credential in the SQL Server instance |
| Description: string | • User-provided description of the proxy that uses this credential |
| Is Enabled: bool | • Is the proxy that uses this credential enabled? |
| Proxy ID: uint | • The identifier the SQL Server instance uses to associate other objects with this proxy |
| Proxy Name: string | • The name used to identify this proxy in the SQL Server instance |
| Resolved SID: string | • The domain SID for the credential identity |
| Resolved Type: string | • The class of domain principal for the credential identity |
| Subsystems: List | • Subsystems this proxy is configured with (e.g., CmdExec, PowerShell) |
| Property ______________________________________________ |
Definition _______________________________________________________________________________________________ |
|---|---|
| Data Access: bool | • True (enabled): • The linked server can be used in distributed queries • You can SELECT, INSERT, UPDATE, DELETE data through the linked server• Four-part naming queries work: [LinkedServer].[Database].[Schema].[Table]• OPENQUERY() statements work against this linked server• False (disabled): • The linked server connection still exists but cannot be used for data queries • Attempts to query through it will fail with an error • The linked server can still be used for other purposes like RPC calls (if RPC is enabled) |
| Data Source: string | • Format: <linked_server_hostname>[\instancename]• Examples: SITE-DB or CAS-PSS\CAS |
| Local Login: List | • The login(s) on the source that can use the link and connect to the linked server using the Remote Login |
| Path: string | • The link used to collect the information needed to create this edge |
| Product: string | • A user-defined name of the product used by the remote server • Examples: SQL Server, Oracle, Access |
| Provider: string | • The driver or interface that SQL Server uses to communicate with the remote data source |
| Remote Current Login: string | • Displays the login context that is actually used on the remote linked server based on the results of the SELECT SYSTEM_USER SQL statement on the remote linked server• If impersonation is used, it is likely that this value will be the login used for collection • If not, this should match Remote Login |
| Remote Has Control Server: bool | • Does the login context on the remote server have the CONTROL SERVER permission? |
| Remote Has Impersonate Any Login: bool | • Does the login context on the remote server have the IMPERSONATE ANY LOGIN permission? |
| Remote Is Mixed Mode: bool | • Is mixed mode authentication (for both Windows and SQL logins) enabled on the remote server? |
| Remote Is Securityadmin: bool | • Is the login context on the remote server a member of the securityadmin server role? |
| Remote Is Sysadmin: bool | • Is the login context on the remote server a member of the sysadmin server role? |
| Remote Login: string | • The SQL Server authentication login that exists on the remote server that connections over this link are mapped to • The password for this login must be saved on the source server • Will be null if impersonation is used, in which case the login context being used on the source server is used to connect to the remote linked server |
| Remote Server Roles: List | • Server roles the remote login context is a member of |
| RPC Out: bool | • Can the source server call stored procedures on remote server? |
| Uses Impersonation: bool | • Does the linked server attempt to use the current user's Windows credentials to authenticate to the remote server? • For SQL Server authentication, a login with the exact same name and password must exist on the remote server. • For Windows logins, the login must be a valid login on the linked server. • This requires Kerberos delegation to be properly configured • The user's actual Windows identity is passed through to the remote server |
Please refer to the $script:EdgePropertyGenerators variable in powershell_deprecated/MSSQLHound.ps1 for the following details:
- Source and target node classes (all combinations)
- Requirements
- Default fixed roles with the permission
- Traversability
- Entity panel details (dynamically-generated)
- General
- Windows Abuse
- Linux Abuse
- OPSEC
- References
- Composition Cypher (where applicable)
All edges based on permissions may contain the With Grant property, which means the source not only has the permission but can grant it to other principals.
- Original PowerShell version by Chris Thompson (@_Mayyhem) at SpecterOps
- Go port by Javier Azofra at Siemens Healthineers and Chris Thompson