From 2e3a2b6f6ddef9382c2bf938680a22a3c0ae4695 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre Date: Tue, 18 Apr 2023 16:41:48 -0400 Subject: [PATCH] Combine AWS SSM modules, autodetect platform --- .../sessions/aws_ssm_command_shell_bind.rb | 31 ++++++------ lib/msf/base/sessions/command_shell.rb | 2 +- lib/msf/core/handler/bind_aws_ssm.rb | 6 +-- modules/auxiliary/cloud/aws/enum_ssm.rb | 8 +--- .../singles/cmd/windows/bind_aws_ssm.rb | 48 ------------------- .../shell_bind_aws_ssm.rb} | 27 ++++------- 6 files changed, 31 insertions(+), 91 deletions(-) delete mode 100644 modules/payloads/singles/cmd/windows/bind_aws_ssm.rb rename modules/payloads/singles/{cmd/unix/bind_aws_ssm.rb => generic/shell_bind_aws_ssm.rb} (57%) diff --git a/lib/msf/base/sessions/aws_ssm_command_shell_bind.rb b/lib/msf/base/sessions/aws_ssm_command_shell_bind.rb index 8ced782c97..912857770d 100644 --- a/lib/msf/base/sessions/aws_ssm_command_shell_bind.rb +++ b/lib/msf/base/sessions/aws_ssm_command_shell_bind.rb @@ -23,6 +23,23 @@ module Msf::Sessions # include Msf::Session::Provider::SingleCommandShell + def initialize(conn, opts=nil) + super + + if opts && (ssm_peer_info = opts.fetch(:aws_ssm_host_info)) + case ssm_peer_info['PlatformType'] + when 'Linux' + @platform = 'linux' + when 'MacOS' + @platform = 'osx' + when 'Windows' + @platform = 'win' + end + + @info = "AWS SSM #{ssm_peer_info['ResourceType']} (#{ssm_peer_info['InstanceId']})" + end + end + ## # # Returns the session description. @@ -30,19 +47,5 @@ module Msf::Sessions def desc 'AWS SSM command shell' end - - ## - # Intercept point from Msf::Sessions::CommandShell#shell_read - ## - def shell_read(length=-1, timeout=1) - super(length, timeout) - end - - ## - # Intercept point from Msf::Sessions::CommandShell#shell_write - ## - def shell_write(buf) - super(buf) - end end end diff --git a/lib/msf/base/sessions/command_shell.rb b/lib/msf/base/sessions/command_shell.rb index 2e419ae29b..dd361e5290 100644 --- a/lib/msf/base/sessions/command_shell.rb +++ b/lib/msf/base/sessions/command_shell.rb @@ -130,7 +130,7 @@ Shell Banner: end # Only populate +session.info+ with a captured banner if the shell is responsive and verified - session.info = session_info + session.info = session_info if session.info.blank? session else # Encrypted shells need all information read before anything is written, so we read in the banner here. However we diff --git a/lib/msf/core/handler/bind_aws_ssm.rb b/lib/msf/core/handler/bind_aws_ssm.rb index 7a35e826cd..80ef2fe600 100644 --- a/lib/msf/core/handler/bind_aws_ssm.rb +++ b/lib/msf/core/handler/bind_aws_ssm.rb @@ -238,7 +238,7 @@ module BindAwsSsm end break if ssm_client - # Wait a second before trying again + # Wait a half-second before trying again Rex::ThreadSafe.sleep(0.5) end @@ -284,7 +284,8 @@ module BindAwsSsm elog('Exception raised from BindAwsSsm.handle_connection', error: e) end self.listener_pairs[datastore['EC2_ID']] = chan - handle_connection(chan.lsock, { datastore: datastore }) + + handle_connection(chan.lsock, { datastore: datastore, aws_ssm_host_info: peer_info }) end else wlog('No connection received before the handler completed') @@ -368,7 +369,6 @@ private # notify any waiters we may have. if s register_session(s) - s.info = "AWS SSM #{datastore['ACCESS_KEY_ID']} (#{datastore['EC2_ID']})" end return s diff --git a/modules/auxiliary/cloud/aws/enum_ssm.rb b/modules/auxiliary/cloud/aws/enum_ssm.rb index 1ddc8b5dbd..b0ae94e10e 100644 --- a/modules/auxiliary/cloud/aws/enum_ssm.rb +++ b/modules/auxiliary/cloud/aws/enum_ssm.rb @@ -110,13 +110,9 @@ class MetasploitModule < Msf::Auxiliary next unless datastore['CreateSession'] socket = get_ssm_socket(client, ssm_host['InstanceId']) - if ssm_host['PlatformType'].casecmp?('Windows') - sess = Msf::Sessions::CommandShellWindows.new(socket.lsock) - else - sess = Msf::Sessions::CommandShellUnix.new(socket.lsock) - end + sess = Msf::Sessions::AwsSsmCommandShellBind.new(socket.lsock, { datastore: datastore, aws_ssm_host_info: ssm_host }) - start_session(self, "AWS SSM #{datastore['ACCESS_KEY_ID']} (#{ssm_host['InstanceId']})", datastore, false, socket.lsock, sess) + start_session(self, sess.info, datastore, false, socket.lsock, sess) end rescue Seahorse::Client::NetworkingError => e print_error e.message diff --git a/modules/payloads/singles/cmd/windows/bind_aws_ssm.rb b/modules/payloads/singles/cmd/windows/bind_aws_ssm.rb deleted file mode 100644 index 7c2cac5944..0000000000 --- a/modules/payloads/singles/cmd/windows/bind_aws_ssm.rb +++ /dev/null @@ -1,48 +0,0 @@ -## -# This module requires Metasploit: https://metasploit.com/download -# Current source: https://github.com/rapid7/metasploit-framework -## - -module MetasploitModule - CachedSize = 70 - - include Msf::Payload::Single - include Msf::Sessions::CommandShellOptions - - def initialize(info = {}) - super( - merge_info( - info, - 'Name' => 'Windows Command Shell, Bind SSM (via AWS API)', - 'Description' => 'Creates an interactive shell using AWS SSM', - 'Author' => 'RageLtMan ', - 'License' => MSF_LICENSE, - 'Platform' => 'windows', - 'Arch' => ARCH_CMD, - 'Handler' => Msf::Handler::BindAwsSsm, - 'Session' => Msf::Sessions::CommandShellWindows, - 'PayloadType' => 'cmd', - 'RequiredCmd' => 'generic', - 'Payload' => { - 'Offsets' => {}, - 'Payload' => '' - } - ) - ) - end - - # - # Constructs the payload - # - def generate(_opts = {}) - vprint_good(command_string) - return super + command_string - end - - # - # Returns the command string to use for execution - # - def command_string - '' - end -end diff --git a/modules/payloads/singles/cmd/unix/bind_aws_ssm.rb b/modules/payloads/singles/generic/shell_bind_aws_ssm.rb similarity index 57% rename from modules/payloads/singles/cmd/unix/bind_aws_ssm.rb rename to modules/payloads/singles/generic/shell_bind_aws_ssm.rb index 52d1a9c87d..686b8b6e93 100644 --- a/modules/payloads/singles/cmd/unix/bind_aws_ssm.rb +++ b/modules/payloads/singles/generic/shell_bind_aws_ssm.rb @@ -4,7 +4,7 @@ ## module MetasploitModule - CachedSize = 70 + CachedSize = 0 include Msf::Payload::Single include Msf::Sessions::CommandShellOptions @@ -13,16 +13,14 @@ module MetasploitModule super( merge_info( info, - 'Name' => 'Unix Command Shell, Bind SSM (via AWS API)', + 'Name' => 'Command Shell, Bind SSM (via AWS API)', 'Description' => 'Creates an interactive shell using AWS SSM', 'Author' => 'RageLtMan ', 'License' => MSF_LICENSE, - 'Platform' => 'unix', - 'Arch' => ARCH_CMD, + 'Platform' => '', + 'Arch' => ARCH_ALL, 'Handler' => Msf::Handler::BindAwsSsm, - 'Session' => Msf::Sessions::CommandShellUnix, - 'PayloadType' => 'cmd', - 'RequiredCmd' => 'generic', + 'Session' => Msf::Sessions::AwsSsmCommandShellBind, 'Payload' => { 'Offsets' => {}, 'Payload' => '' @@ -31,18 +29,9 @@ module MetasploitModule ) end - # - # Constructs the payload - # - def generate(_opts = {}) - vprint_good(command_string) - return super + command_string - end + def on_session(session) + super - # - # Returns the command string to use for execution - # - def command_string - '' + session.arch.clear # undo the ARCH_ALL amalgamation end end