require 'spec_helper' require 'ronin/exploits/mixins/http' require 'ronin/exploits/exploit' describe Ronin::Exploits::Mixins::HTTP do module TestMixinsHTTP class TestExploit < Ronin::Exploits::Exploit include Ronin::Exploits::Mixins::HTTP end class TestExploitWithDefaultHeaders < Ronin::Exploits::Exploit include Ronin::Exploits::Mixins::HTTP def http_headers {'X-Foo' => 'bar'} end end end let(:test_class) { TestMixinsHTTP::TestExploit } describe ".included" do subject { test_class } it "must define a 'http_proxy' param" do expect(subject.params[:http_proxy]).to_not be_nil expect(subject.params[:http_proxy].desc).to eq("The HTTP proxy to use") end it "must define a 'user_agent' param" do expect(subject.params[:user_agent]).to_not be_nil expect(subject.params[:user_agent].type).to be_kind_of(Ronin::Core::Params::Types::Enum) expect(subject.params[:user_agent].type.values).to eq( [ :random, :chrome, :firefox, :safari, :linux, :macos, :windows, :iphone, :ipad, :android ] + Ronin::Support::Network::HTTP::UserAgents::ALIASES.keys ) expect(subject.params[:user_agent].desc).to eq("The HTTP User-Agent to select") end it "must define a 'raw_user_agent' param" do expect(subject.params[:raw_user_agent]).to_not be_nil expect(subject.params[:raw_user_agent].desc).to eq("The raw HTTP User-Agent string to use") end end let(:base_url) { URI.parse("https://www.example.com/base") } subject do test_class.new(params: {base_url: base_url}) end describe "#http_proxy" do let(:proxy) { 'http://example.com:8080' } subject do test_class.new(params: {base_url: base_url, http_proxy: proxy}) end it "must return params[:http_proxy]" do expect(subject.http_proxy).to be(subject.params[:http_proxy]) end end describe "#http_headers" do it "must return an empty Hash by default" do expect(subject.http_headers).to eq({}) end end describe "#http_user_agent" do context "when params[:user_agent] is set" do let(:user_agent) { :random } subject do test_class.new( params: { base_url: base_url, user_agent: user_agent } ) end it "must return params[:user_agent]" do expect(subject.http_user_agent).to be(subject.params[:user_agent]) end end context "when params[:raw_user_agent] is set" do let(:raw_user_agent) { 'Mozilla/5.0 Foo Bar' } subject do test_class.new( params: { base_url: base_url, raw_user_agent: raw_user_agent } ) end it "must return params[:raw_user_agent]" do expect(subject.http_user_agent).to be( subject.params[:raw_user_agent] ) end end context "when both params[:user_agent] and params[:raw_user_agent] are set" do let(:user_agent) { :random } let(:raw_user_agent) { 'Mozilla/5.0 Foo Bar' } subject do test_class.new( params: { base_url: base_url, user_agent: user_agent, raw_user_agent: raw_user_agent } ) end it "must return params[:raw_user_agent]" do expect(subject.http_user_agent).to be( subject.params[:raw_user_agent] ) end end end describe "#http_cookie" do context "when the http_cookie param is set" do let(:cookie) { "foo=1; bar=2" } subject do test_class.new( params: { base_url: base_url, http_cookie: cookie } ) end it "must return params[:http_cookie]" do expect(subject.http_cookie).to eq(cookie) end end end let(:proxy) { URI('https://proxy.example.com:8080') } let(:raw_user_agent) { 'Mozilla/5.0 Foo Bar' } let(:cookie) { "foo=1; bar=2" } let(:user) { 'bob' } let(:password) { 'secret' } subject do test_class.new( params: { base_url: base_url, http_proxy: proxy, raw_user_agent: raw_user_agent, http_cookie: cookie, http_user: user, http_password: password } ) end describe "#http" do it "must call Ronin::Support::Network::HTTP.connect_uri with #params[:base_url], proxy: #http_proxy, headers: #http_headers, user_agent: #http_user_agent, cookie: #http_cookie, user: #http_user, password: #http_password" do expect(Ronin::Support::Network::HTTP).to receive(:connect_uri).with( subject.params[:base_url], proxy: subject.http_proxy, headers: subject.http_headers, user_agent: subject.http_user_agent, cookie: subject.http_cookie, user: subject.http_user, password: subject.http_password ) subject.http end it "must return a Ronin::Support::Network::HTTP instance" do expect(subject.http).to be_kind_of(Ronin::Support::Network::HTTP) end it "must return the same instance each time" do expect(subject.http).to be(subject.http) end context "when #http_headers is overriden" do let(:test_class) { TestMixinsHTTP::TestExploitWithDefaultHeaders } it "must initialize #http.headers to the value of #http_headers" do expect(subject.http.headers).to eq(subject.http_headers) end end end describe "#http_request" do context "when given a request method and a path" do let(:request_method) { :get } let(:path) { '/foo' } it "must call #http.request with the request method and path" do expect(subject.http).to receive(:request).with(request_method,path) subject.http_request(request_method,path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:request).with( request_method, path ) expect(subject).to receive(:print_debug).with( "Sending #{request_method.upcase} request to #{url} ..." ) subject.http_request(request_method,path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_response_status" do context "when given a request method and a path" do let(:request_method) { :get } let(:path) { '/foo' } it "must call #http.response_status with the request method and path" do expect(subject.http).to receive(:response_status).with( request_method, path ) subject.http_response_status(request_method,path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:response_status).with( request_method, path ) expect(subject).to receive(:print_debug).with( "Checking response status for #{request_method.upcase} #{url} ..." ) subject.http_response_status(request_method,path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_ok?" do context "when given a path" do let(:path) { '/foo' } it "must call #http.ok? with :head and the path" do expect(subject.http).to receive(:ok?).with(:head,path) subject.http_ok?(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:ok?).with(:head,path) expect(subject).to receive(:print_debug).with( "Checking if response status for HEAD #{url} is 200 ..." ) subject.http_ok?(path) end after { Ronin::Support::CLI::Printing.debug = false } end end context "when given a request method and a path" do let(:request_method) { :get } let(:path) { '/foo' } it "must call #http.ok? with the request method and the path" do expect(subject.http).to receive(:ok?).with(request_method,path) subject.http_ok?(request_method,path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:ok?).with(request_method,path) expect(subject).to receive(:print_debug).with( "Checking if response status for #{request_method.upcase} #{url} is 200 ..." ) subject.http_ok?(request_method,path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_response_headers" do context "when given a path" do let(:request_method) { :get } let(:path) { '/foo' } it "must call #http.ok? with :head and the path" do expect(subject.http).to receive(:response_headers).with(:head,path) subject.http_response_headers(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:response_headers).with(:head,path) expect(subject).to receive(:print_debug).with( "Requesting response headers for HEAD #{url} ..." ) subject.http_response_headers(path) end after { Ronin::Support::CLI::Printing.debug = false } end end context "when given a request method and a path" do let(:request_method) { :get } let(:path) { '/foo' } it "must call #http.ok? with the request method and the path" do expect(subject.http).to receive(:response_headers).with( request_method, path ) subject.http_response_headers(request_method,path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:response_headers).with( request_method, path ) expect(subject).to receive(:print_debug).with( "Requesting response headers for #{request_method.upcase} #{url} ..." ) subject.http_response_headers(request_method,path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_server_header" do context "when given a path" do let(:path) { '/foo' } it "must call #http.server_header with the path and method: :head" do expect(subject.http).to receive(:server_header).with( path, method: :head ) subject.http_server_header(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:server_header).with( path, method: :head ) expect(subject).to receive(:print_debug).with( "Requesting the 'Server' header for HEAD #{url} ..." ) subject.http_server_header(path) end after { Ronin::Support::CLI::Printing.debug = false } end end context "when given a path and the method: keyword argument" do let(:request_method) { :get } let(:path) { '/foo' } it "must call #http.server_header with the path and the method: keyword argument" do expect(subject.http).to receive(:server_header).with( path, method: request_method ) subject.http_server_header(path, method: request_method) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:server_header).with( path, method: request_method ) expect(subject).to receive(:print_debug).with( "Requesting the 'Server' header for #{request_method.upcase} #{url} ..." ) subject.http_server_header(path, method: request_method) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_powered_by_header" do context "when given a path" do let(:path) { '/foo' } it "must call #http.powered_by_header with the path and method: :head" do expect(subject.http).to receive(:powered_by_header).with( path, method: :head ) subject.http_powered_by_header(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:powered_by_header).with( path, method: :head ) expect(subject).to receive(:print_debug).with( "Requesting the 'X-Powered-By' header for HEAD #{url} ..." ) subject.http_powered_by_header(path) end after { Ronin::Support::CLI::Printing.debug = false } end end context "when given a path and a method: keyword argument" do let(:request_method) { :get } let(:path) { '/foo' } it "must call #http.powered_by_header with the path and the method: keyword argument" do expect(subject.http).to receive(:powered_by_header).with( path, method: request_method, ) subject.http_powered_by_header(path, method: request_method) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:powered_by_header).with( path, method: request_method ) expect(subject).to receive(:print_debug).with( "Requesting the 'X-Powered-By' header for #{request_method.upcase} #{url} ..." ) subject.http_powered_by_header(path, method: request_method) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_response_body" do context "when given a path" do let(:path) { '/foo' } it "must call #http.response_body with :head and the path" do expect(subject.http).to receive(:response_body).with(:get,path) subject.http_response_body(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:response_body).with( :get, path ) expect(subject).to receive(:print_debug).with( "Requesting response body for GET #{url} ..." ) subject.http_response_body(path) end after { Ronin::Support::CLI::Printing.debug = false } end end context "when given a request method and a path" do let(:request_method) { :head } let(:path) { '/foo' } it "must call #http.response_body with request method and the path" do expect(subject.http).to receive(:response_body).with( request_method, path ) subject.http_response_body(request_method,path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:response_body).with( request_method, path ) expect(subject).to receive(:print_debug).with( "Requesting response body for #{request_method.upcase} #{url} ..." ) subject.http_response_body(request_method,path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_copy" do context "when given a path" do let(:path) { '/foo' } it "must call #http.copy with the path" do expect(subject.http).to receive(:copy).with(path) subject.http_copy(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:copy).with(path) expect(subject).to receive(:print_debug).with( "Requesting COPY #{url} ..." ) subject.http_copy(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_delete" do context "when given a path" do let(:path) { '/foo' } it "must call #http.delete with the path" do expect(subject.http).to receive(:delete).with(path) subject.http_delete(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:delete).with(path) expect(subject).to receive(:print_debug).with( "Requesting DELETE #{url} ..." ) subject.http_delete(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_get" do context "when given a path" do let(:path) { '/foo' } it "must call #http.get with the path" do expect(subject.http).to receive(:get).with(path) subject.http_get(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:get).with(path) expect(subject).to receive(:print_debug).with( "Requesting GET #{url} ..." ) subject.http_get(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_get_headers" do context "when given a path" do let(:path) { '/foo' } it "must call #http.get_headers with the path" do expect(subject.http).to receive(:get_headers).with(path) subject.http_get_headers(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:get_headers).with(path) expect(subject).to receive(:print_debug).with( "Requesting headers for GET #{url} ..." ) subject.http_get_headers(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_get_cookies" do context "when given a path" do let(:path) { '/foo' } it "must call #http.get_cookies with the path" do expect(subject.http).to receive(:get_cookies).with(path) subject.http_get_cookies(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:get_cookies).with(path) expect(subject).to receive(:print_debug).with( "Getting cookies for #{url} ..." ) subject.http_get_cookies(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_get_body" do context "when given a path" do let(:path) { '/foo' } it "must call #http.get_body with the path" do expect(subject.http).to receive(:get_body).with(path) subject.http_get_body(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:get_body).with(path) expect(subject).to receive(:print_debug).with( "Requesting body for GET #{url} ..." ) subject.http_get_body(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_head" do context "when given a path" do let(:path) { '/foo' } it "must call #http.head with the path" do expect(subject.http).to receive(:head).with(path) subject.http_head(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:head).with(path) expect(subject).to receive(:print_debug).with( "Requesting HEAD #{url} ..." ) subject.http_head(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_lock" do context "when given a path" do let(:path) { '/foo' } it "must call #http.lock with the path" do expect(subject.http).to receive(:lock).with(path) subject.http_lock(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:lock).with(path) expect(subject).to receive(:print_debug).with( "Requesting LOCK #{url} ..." ) subject.http_lock(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_mkcol" do context "when given a path" do let(:path) { '/foo' } it "must call #http.mkcol with the path" do expect(subject.http).to receive(:mkcol).with(path) subject.http_mkcol(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:mkcol).with(path) expect(subject).to receive(:print_debug).with( "Requesting MKCOL #{url} ..." ) subject.http_mkcol(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_move" do context "when given a path" do let(:path) { '/foo' } it "must call #http.move with the path" do expect(subject.http).to receive(:move).with(path) subject.http_move(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:move).with(path) expect(subject).to receive(:print_debug).with( "Requesting MOVE #{url} ..." ) subject.http_move(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_options" do context "when given a path" do let(:path) { '/foo' } it "must call #http.options with the path" do expect(subject.http).to receive(:options).with(path) subject.http_options(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:options).with(path) expect(subject).to receive(:print_debug).with( "Requesting OPTIONS #{url} ..." ) subject.http_options(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_allowed_methods" do context "when given a path" do let(:path) { '/foo' } it "must call #http.allowed_methods with the path" do expect(subject.http).to receive(:allowed_methods).with(path) subject.http_allowed_methods(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:allowed_methods).with(path) expect(subject).to receive(:print_debug).with( "Checking allowed HTTP methods for #{url} ..." ) subject.http_allowed_methods(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_patch" do context "when given a path" do let(:path) { '/foo' } it "must call #http.patch with the path" do expect(subject.http).to receive(:patch).with(path) subject.http_patch(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:patch).with(path) expect(subject).to receive(:print_debug).with( "Requesting PATCH #{url} ..." ) subject.http_patch(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_post" do context "when given a path" do let(:path) { '/foo' } it "must call #http.post with the path" do expect(subject.http).to receive(:post).with(path) subject.http_post(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:post).with(path) expect(subject).to receive(:print_debug).with( "Requesting POST #{url} ..." ) subject.http_post(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_post_headers" do context "when given a path" do let(:path) { '/foo' } it "must call #http.post_headers with the path" do expect(subject.http).to receive(:post_headers).with(path) subject.http_post_headers(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:post_headers).with(path) expect(subject).to receive(:print_debug).with( "Requesting response headers for POST #{url} ..." ) subject.http_post_headers(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_post_body" do context "when given a path" do let(:path) { '/foo' } it "must call #http.post_body with the path" do expect(subject.http).to receive(:post_body).with(path) subject.http_post_body(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:post_body).with(path) expect(subject).to receive(:print_debug).with( "Requesting response body for POST #{url} ..." ) subject.http_post_body(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_propfind" do context "when given a path" do let(:path) { '/foo' } it "must call #http.propfind with the path" do expect(subject.http).to receive(:propfind).with(path) subject.http_propfind(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:propfind).with(path) expect(subject).to receive(:print_debug).with( "Requesting PROPFIND #{url} ..." ) subject.http_propfind(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_proppatch" do context "when given a path" do let(:path) { '/foo' } it "must call #http.proppatch with the path" do expect(subject.http).to receive(:proppatch).with(path) subject.http_proppatch(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) expect(subject.http).to receive(:proppatch).with(path) expect(subject).to receive(:print_debug).with( "Requesting PROPPATCH #{url} ..." ) subject.http_proppatch(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_put" do context "when given a path" do let(:path) { '/foo' } it "must call #http.put with the path" do expect(subject.http).to receive(:put).with(path) subject.http_put(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:put).with(path) expect(subject).to receive(:print_debug).with( "Requesting PUT #{url} ..." ) subject.http_put(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_trace" do context "when given a path" do let(:path) { '/foo' } it "must call #http.trace with the path" do expect(subject.http).to receive(:trace).with(path) subject.http_trace(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:trace).with(path) expect(subject).to receive(:print_debug).with( "Requesting TRACE #{url} ..." ) subject.http_trace(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end describe "#http_unlock" do context "when given a path" do let(:path) { '/foo' } it "must call #http.unlock with the path" do expect(subject.http).to receive(:unlock).with(path) subject.http_unlock(path) end context "when debug messages are enabled" do before { Ronin::Support::CLI::Printing.debug = true } it "must print a debugging message" do url = subject.url_for(path) allow(subject.http).to receive(:unlock).with(path) expect(subject).to receive(:print_debug).with( "Requesting UNLOCK #{url} ..." ) subject.http_unlock(path) end after { Ronin::Support::CLI::Printing.debug = false } end end end end