SkillAgentSearch skills...

MSSQLHound

PowerShell collector for adding MSSQL attack paths to BloodHound with OpenGraph

Install / Use

/learn @SpecterOps/MSSQLHound
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

MSSQLHound

<img width="3147" height="711" alt="image" src="https://github.com/user-attachments/assets/476babac-c265-4d2b-bc03-f893fdb7bc1f" />

A PowerShell collector for adding MSSQL attack paths to BloodHound with OpenGraph by Chris Thompson at SpecterOps

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/

Please hit me up on the BloodHound Slack (@Mayyhem), Twitter (@_Mayyhem), or open an issue if you have any questions I can help with!

Table of Contents

Overview

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

System Requirements:

  • 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

Minimum Permissions:

Windows Level:

  • Active Directory domain context with line of sight to a domain controller

MSSQL Server Level:

  • CONNECT SQL (default for new logins)
  • VIEW ANY DATABASE (default for new logins)

Recommended Permissions:

MSSQL Server Level:

  • VIEW ANY DEFINITION permission 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 STATE permission or ##MSS_ServerPerformanceStateReader## role membership (available in versions 2022+) or local Administrators group privileges on the target (fallback for WMI collection)
    • Only used for service account collection

MSSQL Database Level:

  • CONNECT ANY DATABASE server permission (available in versions 2014+) or ##MS_DatabaseConnector## role membership (available in versions 2022+) or login maps to a database user with CONNECT on individual databases
    • Needed to read database principals and their permissions
  • Login maps to msdb database user with db_datareader role or with SELECT permission on:
    • msdb.dbo.sysproxies
    • msdb.dbo.sysproxylogin
    • msdb.dbo.sysproxysubsystem
    • msdb.dbo.syssubsystems
    • Only used for proxy account collection

Usage Info

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 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).

Want to be a bit more aggressive with your pathfinding queries? You can make these edges traversable using the -MakeInterestingEdgesTraversable flag.

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, bu

Related Skills

View on GitHub
GitHub Stars295
CategoryData
Updated10d ago
Forks19

Languages

PowerShell

Security Score

95/100

Audited on Mar 18, 2026

No findings