Skip to content

Commit

Permalink
Add MSSQL session Type
Browse files Browse the repository at this point in the history
  • Loading branch information
zgoldman-r7 committed Feb 9, 2024
1 parent 5975d66 commit 2c60780
Show file tree
Hide file tree
Showing 18 changed files with 1,003 additions and 10 deletions.
16 changes: 14 additions & 2 deletions lib/metasploit/framework/login_scanner/mssql.rb
Expand Up @@ -47,7 +47,16 @@ class MSSQL
# @return [Boolean] Whether to use Windows Authentication instead of SQL Server Auth.
attr_accessor :windows_authentication

# @!attribute use_client_as_proof
# @return [Boolean] If a login is successful and this attribute is true - an MSSQL::Client instance is used as proof
attr_accessor :use_client_as_proof

# @!attribute max_send_size
# @return [Integer] The max size of the data to encapsulate in a single packet
attr_accessor :max_send_size

# @!attribute send_delay
# @return [Integer] The delay between sending packets
attr_accessor :send_delay

validates :windows_authentication,
Expand All @@ -71,6 +80,11 @@ def attempt_login(credential)
client = Rex::Proto::MSSQL::Client.new(framework_module, framework, host, port)
if client.mssql_login(credential.public, credential.private, '', credential.realm)
result_options[:status] = Metasploit::Model::Login::Status::SUCCESSFUL
if use_client_as_proof
result_options[:proof] = client
else
client.disconnect
end
else
result_options[:status] = Metasploit::Model::Login::Status::INCORRECT
end
Expand All @@ -81,8 +95,6 @@ def attempt_login(credential)
elog(e)
result_options[:status] = Metasploit::Model::Login::Status::UNABLE_TO_CONNECT
result_options[:proof] = e
ensure
client.disconnect
end

::Metasploit::Framework::LoginScanner::Result.new(result_options)
Expand Down
11 changes: 11 additions & 0 deletions lib/msf/base/config.rb
Expand Up @@ -228,6 +228,13 @@ def self.postgresql_session_history
self.new.postgresql_session_history
end

# Returns the full path to the MSSQL session history file.
#
# @return [String] path to the history file.
def self.mssql_session_history
self.new.mssql_session_history
end

# Returns the full path to the MySQL session history file.
#
# @return [String] path to the history file.
Expand Down Expand Up @@ -352,6 +359,10 @@ def mysql_session_history
config_directory + FileSep + "mysql_session_history"
end

def mssql_session_history
config_directory + FileSep + "mssql_session_history"
end

def pry_history
config_directory + FileSep + "pry_history"
end
Expand Down
147 changes: 147 additions & 0 deletions lib/msf/base/sessions/mssql.rb
@@ -0,0 +1,147 @@
# -*- coding:binary -*-

require 'rex/post/mssql'

class Msf::Sessions::MSSQL

include Msf::Session::Basic
include Msf::Sessions::Scriptable

# @return [Rex::Post::MSSQL::Ui::Console] The interactive console
attr_accessor :console
# @return [MSSQL::Client] The MSSQL client
attr_accessor :client
attr_accessor :platform, :arch
# @return [String] The address MSSQL is running on
attr_accessor :address
# @return [Integer] The port MSSQL is running on
attr_accessor :port
attr_reader :framework

def initialize(rstream, opts = {})
@client = opts.fetch(:client)
self.console = Rex::Post::MSSQL::Ui::Console.new(self, opts)

super(rstream, opts)
end

def bootstrap(datastore = {}, handler = nil)
session = self
session.init_ui(user_input, user_output)

@info = "MSSQL #{datastore['USERNAME']} @ #{@peer_info}"
end

def execute_file(full_path, args)
if File.extname(full_path) == '.rb'
Rex::Script::Shell.new(self, full_path).run(args)
else
console.load_resource(full_path)
end
end

def process_autoruns(datastore)
['InitialAutoRunScript', 'AutoRunScript'].each do |key|
next if datastore[key].nil? || datastore[key].empty?

args = Shellwords.shellwords(datastore[key])
print_status("Session ID #{self.sid} (#{self.tunnel_to_s}) processing #{key} '#{datastore[key]}'")
self.execute_script(args.shift, *args)
end
end

def type
self.class.type
end

# Returns the type of session.
#
def self.type
'MSSQL'
end

def self.can_cleanup_files
false
end

#
# Returns the session description.
#
def desc
'MSSQL'
end

def address
return @address if @address

@address, @port = client.sock.peerinfo.split(':')
@address
end

def port
return @port if @port

@address, @port = client.sock.peerinfo.split(':')
@port
end

##
# :category: Msf::Session::Interactive implementors
#
# Initializes the console's I/O handles.
#
def init_ui(input, output)
self.user_input = input
self.user_output = output
console.init_ui(input, output)
console.set_log_source(log_source)

super
end

##
# :category: Msf::Session::Interactive implementors
#
# Resets the console's I/O handles.
#
def reset_ui
console.unset_log_source
console.reset_ui
end

def exit
console.stop
end

##
# :category: Msf::Session::Interactive implementors
#
# Override the basic session interaction to use shell_read and
# shell_write instead of operating on rstream directly.
def _interact
framework.events.on_session_interact(self)
framework.history_manager.with_context(name: type.to_sym) do
_interact_stream
end
end

##
# :category: Msf::Session::Interactive implementors
#
def _interact_stream
framework.events.on_session_interact(self)

console.framework = framework
# Call the console interaction of the MSSQL client and
# pass it a block that returns whether or not we should still be
# interacting. This will allow the shell to abort if interaction is
# canceled.
console.interact { interacting != true }
console.framework = nil

# If the stop flag has been set, then that means the user exited. Raise
# the EOFError so we can drop this handle like a bad habit.
raise EOFError if (console.stopped? == true)
end

end
7 changes: 7 additions & 0 deletions lib/msf/core/feature_manager.rb
Expand Up @@ -25,6 +25,7 @@ class FeatureManager
SMB_SESSION_TYPE = 'smb_session_type'
POSTGRESQL_SESSION_TYPE = 'postgresql_session_type'
MYSQL_SESSION_TYPE = 'mysql_session_type'
MSSQL_SESSION_TYPE = 'mssql_session_type'
DEFAULTS = [
{
name: WRAPPED_TABLES,
Expand Down Expand Up @@ -83,6 +84,12 @@ class FeatureManager
requires_restart: true,
default_value: false
}.freeze,
{
name: MSSQL_SESSION_TYPE,
description: 'When enabled will allow for the creation/use of mssql sessions',
requires_restart: true,
default_value: false
}.freeze,
{
name: DNS_FEATURE,
description: 'When enabled, allows configuration of DNS resolution behaviour in Metasploit',
Expand Down
14 changes: 12 additions & 2 deletions lib/msf/core/optional_session.rb
Expand Up @@ -37,16 +37,26 @@ def initialize(info = {})
Msf::OptInt.new('SESSION', [ false, 'The session to run this module on' ]),
Msf::OptString.new('DATABASE', [ false, 'The database to authenticate against', 'postgres']),
Msf::OptString.new('USERNAME', [ false, 'The username to authenticate as', 'postgres']),
]
)
end

if framework.features.enabled?(Msf::FeatureManager::MSSQL_SESSION_TYPE)
register_options(
[
Msf::OptInt.new('SESSION', [ false, 'The session to run this module on' ]),
Msf::OptString.new('DATABASE', [ false, 'The database to authenticate against', 'MSSQL']),
Msf::OptString.new('USERNAME', [ false, 'The username to authenticate as', 'MSSQL']),
Msf::Opt::RHOST(nil, false),
Msf::Opt::RPORT(nil, false)
Msf::Opt::RPORT(1433, false)
]
)
add_info('New in Metasploit 6.4 - This module can target a %grnSESSION%clr or an %grnRHOST%clr')
end
end

def session
return nil unless (framework.features.enabled?(Msf::FeatureManager::SMB_SESSION_TYPE) || framework.features.enabled?(Msf::FeatureManager::POSTGRESQL_SESSION_TYPE) || framework.features.enabled?(Msf::FeatureManager::MYSQL_SESSION_TYPE))
return nil unless (framework.features.enabled?(Msf::FeatureManager::SMB_SESSION_TYPE) || framework.features.enabled?(Msf::FeatureManager::POSTGRESQL_SESSION_TYPE) || framework.features.enabled?(Msf::FeatureManager::MYSQL_SESSION_TYPE) || framework.features.enabled?(Msf::FeatureManager::MSSQL_SESSION_TYPE))

super
end
Expand Down
1 change: 1 addition & 0 deletions lib/rex/post.rb
Expand Up @@ -5,6 +5,7 @@
require 'rex/post/smb'
require 'rex/post/postgresql'
require 'rex/post/mysql'
require 'rex/post/mssql'

module Rex::Post

Expand Down
3 changes: 3 additions & 0 deletions lib/rex/post/mssql.rb
@@ -0,0 +1,3 @@
# -*- coding: binary -*-

require 'rex/post/mssql/ui'
3 changes: 3 additions & 0 deletions lib/rex/post/mssql/ui.rb
@@ -0,0 +1,3 @@
# -*- coding: binary -*-

require 'rex/post/mssql/ui/console'

0 comments on commit 2c60780

Please sign in to comment.