require 'spec_helper' require 'ronin/exploits/mixins/has_payload' require 'ronin/exploits/exploit' require 'ronin/payloads/payload' describe Ronin::Exploits::Mixins::HasPayload do module TestHasPayload class TestPayload < Ronin::Payloads::Payload end class InheritedPayload < TestPayload end class TestOtherPayload < Ronin::Payloads::Payload end class WithNoPayloadClass < Ronin::Exploits::Exploit include Ronin::Exploits::Mixins::HasPayload end class WithPayloadClass < Ronin::Exploits::Exploit include Ronin::Exploits::Mixins::HasPayload payload_class TestPayload end class InheritesPayloadClass < WithPayloadClass end class InheritesAndOverridesPayloadClass < WithPayloadClass payload_class TestOtherPayload end end describe ".payload_class" do subject { test_class } context "when there is no payload_class set in the Exploit class" do let(:test_class) { TestHasPayload::WithNoPayloadClass } it "must default to Ronin::Payloads::Payload" do expect(subject.payload_class).to be(Ronin::Payloads::Payload) end end context "when the payload_class has been set in the Exploit class" do let(:test_class) { TestHasPayload::WithPayloadClass } it "must contain Ronin::Exploits::Target objects" do expect(subject.payload_class).to be(TestHasPayload::TestPayload) end end context "when the super-class sets the payload_class" do let(:test_class) { TestHasPayload::InheritesPayloadClass } let(:super_class) { test_class.superclass } it "must inherit the targets from the super-class" do expect(subject.payload_class).to be(super_class.payload_class) end context "but the sub-class overrides the payload_class" do let(:test_class) { TestHasPayload::InheritesAndOverridesPayloadClass } it "must override the payload_class" do expect(subject.payload_class).to be(TestHasPayload::TestOtherPayload) end it "must not modify the superclass'es payload_class" do expect(super_class.payload_class).to be(TestHasPayload::TestPayload) end end end end let(:test_class) { TestHasPayload::WithPayloadClass } describe "#initialize" do context "when no payload: keyword argument is given" do subject { test_class.new } it "must set #payload to nil" do expect(subject.payload).to be(nil) end end context "when the payload: keyword argument is given" do subject { test_class.new(payload: payload) } context "and it's a Ronin::Payloads::Payload type object" do context "and the Exploit class has not defined a payload_class" do let(:test_class) { TestHasPayload::WithNoPayloadClass } let(:payload) { TestHasPayload::TestPayload.new } it "must set #payload" do expect(subject.payload).to be(payload) end end context "but the Exploit has defined a payload_class" do let(:test_class) { TestHasPayload::WithPayloadClass } context "and the given payload object is a kind of payload_class" do let(:payload) { test_class.payload_class.new } it "must set #payload" do expect(subject.payload).to be(payload) end end context "and the given payload object inherits from payload_class" do let(:payload) { TestHasPayload::InheritedPayload.new } it "must set #payload" do expect(subject.payload).to be(payload) end end context "but the given payload is not a kind of payload_class" do let(:payload) { TestHasPayload::TestOtherPayload.new } it do expect { test_class.new(payload: payload) }.to raise_error(Ronin::Exploits::IncompatiblePayload,"incompatible payload, must be a #{test_class.payload_class} payload: #{payload.inspect}") end end end end context "and it's a String" do let(:payload) { "the payload" } subject { test_class.new(payload: payload) } it "must set #payload to the String" do expect(subject.payload).to be(payload) end end end end describe "#payload=" do subject { test_class.new } context "and it's a Ronin::Payloads::Payload type object" do context "and the Exploit class has not defined a payload_class" do let(:test_class) { TestHasPayload::WithNoPayloadClass } let(:payload) { TestHasPayload::TestPayload.new } before { subject.payload = payload } it "must set #payload" do expect(subject.payload).to be(payload) end end context "but the Exploit has defined a payload_class" do let(:test_class) { TestHasPayload::WithPayloadClass } context "and the given payload object is a kind of payload_class" do let(:payload) { test_class.payload_class.new } before { subject.payload = payload } it "must set #payload" do expect(subject.payload).to be(payload) end end context "and the given payload object inherits from payload_class" do let(:payload) { TestHasPayload::InheritedPayload.new } before { subject.payload = payload } it "must set #payload" do expect(subject.payload).to be(payload) end end context "but the given payload is not a kind of payload_class" do let(:payload) { TestHasPayload::TestOtherPayload.new } it do expect { subject.payload = payload }.to raise_error(Ronin::Exploits::IncompatiblePayload,"incompatible payload, must be a #{test_class.payload_class} payload: #{payload.inspect}") end end end end context "and it's a String" do let(:payload) { "the payload" } before { subject.payload = payload } it "must set #payload to the String" do expect(subject.payload).to be(payload) end end end describe "#perform_validate" do subject { test_class.new(payload: payload) } context "when #payload is nil" do let(:payload) { nil } it do expect { subject.perform_validate }.to raise_error(Ronin::Exploits::MissingPayload,"exploit requires a payload") end end context "when #payload is a Ronin::Payloads::Payload object" do let(:payload) { TestHasPayload::TestPayload.new } it "must also call the #payload's #validate_params" do expect(payload).to receive(:validate_params) subject.perform_validate end end context "when #payload is not a Ronin::Payloads::Payload object" do let(:payload) { "the payload" } it "must not call the #payload's #validate_params method" do expect(payload).to_not receive(:validate_params) subject.perform_validate end end end describe "#perform_build" do subject { test_class.new(payload: payload) } context "when #payload is a Ronin::Payloads::Payload object" do let(:payload) { TestHasPayload::TestPayload.new } it "must also call the #payload's #perform_build" do expect(payload).to receive(:perform_build) subject.perform_build end end context "when #payload is not a Ronin::Payloads::Payload object" do let(:payload) { "the payload" } it "must not call the #payload's #perform_build method" do expect(payload).to_not receive(:perform_build) subject.perform_build end end end describe "#perform_launch" do subject { test_class.new(payload: payload) } context "when #payload is a Ronin::Payloads::Payload object" do let(:payload) { TestHasPayload::TestPayload.new } it "must also call the #payload's #perform_prelaunch" do expect(payload).to receive(:perform_prelaunch) subject.perform_launch end context "but the Exploit's #launch method raises an exception" do module TestHasPayload class ExploitThatFailsToLaunch < Ronin::Exploits::Exploit include Ronin::Exploits::Mixins::HasPayload payload_class TestPayload def launch raise("error!") end end end let(:test_class) { TestHasPayload::ExploitThatFailsToLaunch } it "must call the #payload's #perform_cleanup method then re-raise the exception" do expect(payload).to receive(:perform_cleanup) expect { subject.perform_launch }.to raise_error("error!") end end end context "when #payload is not a Ronin::Payloads::Payload object" do let(:payload) { "the payload" } it "must not call the #payload's #perform_prelaunch method" do expect(payload).to_not receive(:perform_prelaunch) subject.perform_launch end end end describe "#perform_cleanup" do subject { test_class.new(payload: payload) } context "when #payload is a Ronin::Payloads::Payload object" do let(:payload) { TestHasPayload::TestPayload.new } it "must also call the #payload's #perform_cleanup" do expect(payload).to receive(:perform_cleanup) subject.perform_cleanup end end context "when #payload is not a Ronin::Payloads::Payload object" do let(:payload) { "the payload" } it "must not call the #payload's #perform_cleanup method" do expect(payload).to_not receive(:perform_cleanup) subject.perform_cleanup end end end end