diff --git a/lib/msf/core/exploit/auto_check.rb b/lib/msf/core/exploit/auto_check.rb index efd17e17a9..644d08405f 100644 --- a/lib/msf/core/exploit/auto_check.rb +++ b/lib/msf/core/exploit/auto_check.rb @@ -16,10 +16,24 @@ module Exploit::Remote::AutoCheck ]) end + def run + with_prepended_auto_check do + super + end + end + def exploit + with_prepended_auto_check do + super + end + end + + private + + def with_prepended_auto_check unless datastore['AutoCheck'] print_warning('AutoCheck is disabled, proceeding with exploitation') - return super + return yield end print_status('Executing automatic check (disable AutoCheck to override)') @@ -30,14 +44,14 @@ module Exploit::Remote::AutoCheck case (checkcode = check) when Exploit::CheckCode::Vulnerable, Exploit::CheckCode::Appears print_good(checkcode.message) - super + yield when Exploit::CheckCode::Detected print_warning(checkcode.message) - super + yield when Exploit::CheckCode::Safe if datastore['ForceExploit'] print_warning("#{checkcode.message} #{warning_msg}") - return super + return yield end fail_with(Module::Failure::NotVulnerable, @@ -45,19 +59,18 @@ module Exploit::Remote::AutoCheck when Exploit::CheckCode::Unsupported if datastore['ForceExploit'] print_warning("#{checkcode.message} #{warning_msg}") - return super + return yield end fail_with(Module::Failure::BadConfig, "#{checkcode.message} #{error_msg}") else if datastore['ForceExploit'] print_warning("#{checkcode.message} #{warning_msg}") - return super + return yield end fail_with(Module::Failure::Unknown, "#{checkcode.message} #{error_msg}") end end - end end diff --git a/modules/auxiliary/admin/wemo/crockpot.rb b/modules/auxiliary/admin/wemo/crockpot.rb index 383f10db34..ab8ec41dc0 100644 --- a/modules/auxiliary/admin/wemo/crockpot.rb +++ b/modules/auxiliary/admin/wemo/crockpot.rb @@ -6,6 +6,7 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::Remote::HttpClient + prepend Msf::Exploit::Remote::AutoCheck def initialize(info = {}) super(update_info(info, @@ -42,8 +43,7 @@ class MetasploitModule < Msf::Auxiliary ]) register_advanced_options([ - OptBool.new('DefangedMode', [true, 'Run in defanged mode', true]), - OptBool.new('ForceExploit', [true, 'Override check result', false]) + OptBool.new('DefangedMode', [true, 'Run in defanged mode', true]) ]) end @@ -72,15 +72,6 @@ class MetasploitModule < Msf::Auxiliary return end - checkcode = check - - unless datastore['ForceExploit'] - unless checkcode == Exploit::CheckCode::Appears - print_error("#{checkcode[1]}. Set ForceExploit to override.") - return - end - end - case action.name when 'Cook' print_status("Cooking on #{datastore['TEMP']} for #{datastore['TIME']}m") diff --git a/spec/lib/msf/core/exploit/remote/auto_check_spec.rb b/spec/lib/msf/core/exploit/remote/auto_check_spec.rb index 7620e91898..300c953df2 100644 --- a/spec/lib/msf/core/exploit/remote/auto_check_spec.rb +++ b/spec/lib/msf/core/exploit/remote/auto_check_spec.rb @@ -9,15 +9,15 @@ RSpec.shared_examples "An AutoCheck module which can be overridden" do |opts| context "when ForceExploit is enabled" do before(:each) do subject.datastore['ForceExploit'] = true - subject.exploit + subject.send(opts[:method]) end it "calls the check method" do expect(subject).to have_received(:check) end - it 'calls the original exploit' do - expect(subject).to have_received(:original_exploit_call) + it "calls the original #{opts[:method ]} method" do + expect(subject).to have_received(:"original_#{opts[:method]}_call") end end end @@ -27,15 +27,94 @@ RSpec.shared_examples "An AutoCheck module which can be overridden" do |opts| subject.datastore['ForceExploit'] = false end - it "it doesn't call the original exploit" do - expect { subject.exploit }.to raise_error(opts[:expected_error]) do - expect(subject).to_not have_received(:original_exploit_call) + it "it doesn't call the original #{opts[:method ]} method" do + expect { subject.send(opts[:method]) }.to raise_error(opts[:expected_error]) do + expect(subject).to_not have_received(:"original_#{opts[:method]}_call") end end end end end +RSpec.shared_examples "An AutoChecked method" do |opts| + subject { mock_module_with_prepend_autocheck.new } + + before(:each) do + allow(subject).to receive(:check).and_return(check_result) + allow(subject).to receive(:"original_#{opts[:method]}_call").and_call_original + end + + context 'when AutoCheck is disabled' do + let(:check_result) { ::Msf::Exploit::CheckCode::Vulnerable } + + before(:each) do + subject.datastore['AutoCheck'] = false + subject.send(opts[:method]) + end + + it "doesn't call the check method" do + expect(subject).to_not have_received(:check) + end + + it "correctly calls the #{opts[:method]} method" do + expect(subject).to have_received(:"original_#{opts[:method]}_call") + end + end + + context 'when AutoCheck is enabled' do + before(:each) do + subject.datastore['AutoCheck'] = true + end + + context 'when the check method returns vulnerable' do + let(:check_result) { ::Msf::Exploit::CheckCode::Vulnerable } + + before(:each) do + subject.send(opts[:method]) + end + + it "calls the check method" do + expect(subject).to have_received(:check) + end + + it "calls the original #{opts[:method]} method" do + expect(subject).to have_received(:"original_#{opts[:method]}_call") + end + end + + context 'when the check method returns appears' do + let(:check_result) { ::Msf::Exploit::CheckCode::Appears } + + before(:each) do + subject.send(opts[:method]) + end + + it "calls the check method" do + expect(subject).to have_received(:check) + end + + it "calls the original #{opts[:method]} method" do + expect(subject).to have_received(:"original_#{opts[:method]}_call") + end + end + + it_behaves_like "An AutoCheck module which can be overridden", + method: opts[:method], + check_code: ::Msf::Exploit::CheckCode::Safe, + expected_error: "The target is not exploitable. Enable ForceExploit to override check result." + + it_behaves_like "An AutoCheck module which can be overridden", + method: opts[:method], + check_code: ::Msf::Exploit::CheckCode::Unsupported, + expected_error: "This module does not support check. Enable ForceExploit to override check result." + + it_behaves_like "An AutoCheck module which can be overridden", + method: opts[:method], + check_code: ::Msf::Exploit::CheckCode::Unknown, + expected_error: "Cannot reliably check exploitability. Enable ForceExploit to override check result." + end +end + RSpec.describe Msf::Exploit::Remote::AutoCheck do let(:mock_module_with_prepend_autocheck) do context_described_class = described_class @@ -46,6 +125,14 @@ RSpec.describe Msf::Exploit::Remote::AutoCheck do # mocked end + def run + original_run_call + end + + def original_run_call + # Helper for verifying the original run function was called + end + def exploit original_exploit_call end @@ -69,80 +156,12 @@ RSpec.describe Msf::Exploit::Remote::AutoCheck do end context 'when the mixin is prepended' do + describe '#run' do + it_behaves_like 'An AutoChecked method', method: :run + end + describe '#exploit' do - subject { mock_module_with_prepend_autocheck.new } - - before(:each) do - allow(subject).to receive(:check).and_return(check_result) - allow(subject).to receive(:original_exploit_call).and_call_original - end - - context 'when AutoCheck is disabled' do - let(:check_result) { ::Msf::Exploit::CheckCode::Vulnerable } - - before(:each) do - subject.datastore['AutoCheck'] = false - subject.exploit - end - - it "doesn't call the check method" do - expect(subject).to_not have_received(:check) - end - - it "correctly calls the exploit method" do - expect(subject).to have_received(:original_exploit_call) - end - end - - context 'when AutoCheck is enabled' do - before(:each) do - subject.datastore['AutoCheck'] = true - end - - context 'when the check method returns vulnerable' do - let(:check_result) { ::Msf::Exploit::CheckCode::Vulnerable } - - before(:each) do - subject.exploit - end - - it "calls the check method" do - expect(subject).to have_received(:check) - end - - it 'calls the original exploit' do - expect(subject).to have_received(:original_exploit_call) - end - end - - context 'when the check method returns appears' do - let(:check_result) { ::Msf::Exploit::CheckCode::Appears } - - before(:each) do - subject.exploit - end - - it "calls the check method" do - expect(subject).to have_received(:check) - end - - it 'calls the original exploit' do - expect(subject).to have_received(:original_exploit_call) - end - end - - it_behaves_like "An AutoCheck module which can be overridden", - check_code: ::Msf::Exploit::CheckCode::Safe, - expected_error: "The target is not exploitable. Enable ForceExploit to override check result." - - it_behaves_like "An AutoCheck module which can be overridden", - check_code: ::Msf::Exploit::CheckCode::Unsupported, - expected_error: "This module does not support check. Enable ForceExploit to override check result." - - it_behaves_like "An AutoCheck module which can be overridden", - check_code: ::Msf::Exploit::CheckCode::Unknown, - expected_error: "Cannot reliably check exploitability. Enable ForceExploit to override check result." - end + it_behaves_like 'An AutoChecked method', method: :exploit end end end