#
# ronin-exploits - A Ruby library for ronin-rb that provides exploitation and
# payload crafting functionality.
#
# Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
#
# ronin-exploits is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ronin-exploits is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with ronin-exploits. If not, see .
#
require 'ronin/support/network/http'
require 'ronin/exploits/params/base_url'
module Ronin
module Exploits
module Mixins
#
# Adds HTTP helper methods for communicating with a web server.
#
# @api public
#
# @since 1.0.0
#
module HTTP
#
# Adds the required `base_url` params to the exploit class.
#
# @param [Class] exploit
# The exploit class that included {Mixins::HTTP}.
#
# @api private
#
def self.included(exploit)
exploit.include Params::BaseURL
exploit.param :http_proxy, desc: 'The HTTP proxy to use'
exploit.param :http_user, desc: 'The HTTP Basic-Auth user'
exploit.param :http_password, desc: 'The HTTP Basic-Auth password'
user_agent_ids = [
:random,
:chrome,
:firefox,
:safari,
:linux,
:macos,
:windows,
:iphone,
:ipad,
:android
] + Support::Network::HTTP::UserAgents::ALIASES.keys
exploit.param :user_agent, Core::Params::Types::Enum.new(user_agent_ids), desc: 'The HTTP User-Agent to select'
exploit.param :raw_user_agent, desc: 'The raw HTTP User-Agent string to use'
exploit.param :http_cookie, desc: 'The raw HTTP Cookie to use'
end
#
# The HTTP proxy to use for all HTTP requests.
#
# @return [String, nil]
#
# @api private
#
def http_proxy
params[:http_proxy]
end
#
# The HTTP `Basic-Auth` user to use for all HTTP requests.
#
# @return [String, nil]
#
# @api private
#
def http_user
params[:http_user]
end
#
# The HTTP `Basic-Auth` password to use for all HTTP requests.
#
# @return [String, nil]
#
# @api private
#
def http_password
params[:http_password]
end
#
# Additional default headers to send with every HTTP request.
#
# @return [Hash{Symbol,String => String,Array}]
#
# @api private
#
def http_headers
{}
end
#
# The `User-Agent` to use for HTTP requests.
#
# @return [String, Symbol, :random, nil]
# The `User-Agent` string or an alias name (ex: `:chrome_linux`).
#
# @api private
#
def http_user_agent
params[:raw_user_agent] || params[:user_agent]
end
#
# The `Cookie` to use for HTTP requests.
#
# @return [String, nil]
#
# @api private
#
def http_cookie
params[:http_cookie]
end
#
# @!macro request_kwargs
# @option kwargs [String, nil] :user (http_user)
# The `Basic-Auth` user to authenticate as.
#
# @option kwargs [String, nil] :password (http_password)
# The `Basic-Auth` password to authenticate with.
#
# @option kwargs [String, nil] :query
# The query-string to append to the request path.
#
# @option kwargs [Hash, nil] :query_params
# The query-params to append to the request path.
#
# @option kwargs [String, nil] :body
# The body of the request.
#
# @option kwargs [Hash, String, nil] :form_data
# The form data that may be sent in the body of the request.
#
# @option kwargs [String, nil] :user (http_user)
# The user to authenticate as.
#
# @option kwargs [String, nil] :password (http_password)
# The password to authenticate with.
#
# @option kwargs [Hash{Symbol,String => String}, nil] :headers
# Additional HTTP headers to use for the request.
#
#
# A persistent HTTP connection to the target host and port.
#
# @return [Ronin::Support::Network::HTTP]
# The HTTP connection.
#
# @note
# This method will lazily initialize the HTTP connection on the first
# time this method is called and memoize the HTTP object.
#
def http
@http ||= Support::Network::HTTP.connect_uri(
params[:base_url], proxy: http_proxy,
headers: http_headers,
user_agent: http_user_agent,
cookie: http_cookie,
user: http_user,
password: http_password
)
end
#
# Performs and arbitrary HTTP request.
#
# @param [Symbol, String] method
# The HTTP method to use for the request.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @yield [response]
# If a block is given it will be passed the received HTTP response.
#
# @yieldparam [Net::HTTPRresponse] response
# The received HTTP response object.
#
# @return [Net::HTTPResponse]
# The new HTTP Request object.
#
# @raise [ArgumentError]
# The `:method` option did not match a known `Net::HTTP` request
# class.
#
def http_request(method,path,**kwargs,&block)
if debug?
print_debug "Sending #{method.upcase} request to #{url_for(path)} ..."
end
http.request(method,path,**kwargs,&block)
end
#
# Sends an arbitrary HTTP request and returns the response status.
#
# @param [Symbol, String] method
# The HTTP method to use for the request.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @return [Integer]
# The status code of the response.
#
def http_response_status(method=:head,path,**kwargs)
if debug?
print_debug "Checking response status for #{method.upcase} #{url_for(path)} ..."
end
http.response_status(method,path,**kwargs)
end
#
# Sends a HTTP request and determines if the response status was 200.
#
# @param [Symbol, String] method
# The HTTP method to use for the request.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @return [Boolean]
# Indicates that the response status was 200.
#
def http_ok?(method=:head,path,**kwargs)
if debug?
print_debug "Checking if response status for #{method.upcase} #{url_for(path)} is 200 ..."
end
http.ok?(method,path,**kwargs)
end
#
# Sends an arbitrary HTTP request and returns the response headers.
#
# @param [Symbol, String] method
# The HTTP method to use for the request.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @return [Hash{String => String}]
# The response headers.
#
def http_response_headers(method=:head,path,**kwargs)
if debug?
print_debug "Requesting response headers for #{method.upcase} #{url_for(path)} ..."
end
http.response_headers(method,path,**kwargs)
end
#
# Sends an HTTP request and returns the `Server` header.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @param [:copy, :delete, :get, :head, :lock, :mkcol, :move,
# :options, :patch, :post, :propfind, :proppatch, :put,
# :trace, :unlock] method
# The HTTP method to use for the request.
#
# @!macro request_kwargs
#
# @return [String, nil]
# The `Server` header.
#
def http_server_header(path, method: :head, **kwargs)
if debug?
print_debug "Requesting the 'Server' header for #{method.upcase} #{url_for(path)} ..."
end
http.server_header(path, method: method, **kwargs)
end
#
# Sends an HTTP request and returns the `X-Powered-By` header.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @param [:copy, :delete, :get, :head, :lock, :mkcol, :move,
# :options, :patch, :post, :propfind, :proppatch, :put,
# :trace, :unlock] method
# The HTTP method to use for the request.
#
# @!macro request_kwargs
#
# @return [String, nil]
# The `X-Powered-By` header.
#
def http_powered_by_header(path, method: :head, **kwargs)
if debug?
print_debug "Requesting the 'X-Powered-By' header for #{method.upcase} #{url_for(path)} ..."
end
http.powered_by_header(path, method: method, **kwargs)
end
#
# Sends an arbitrary HTTP request and returns the response body.
#
# @param [Symbol, String] method
# The HTTP method to use for the request.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @return [String]
# The response body.
#
def http_response_body(method=:get, path,**kwargs)
if debug?
print_debug "Requesting response body for #{method.upcase} #{url_for(path)} ..."
end
http.response_body(method, path,**kwargs)
end
#
# Performs a `COPY` request for the given URI.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @yield [response]
# If a block is given it will be passed the received HTTP response.
#
# @yieldparam [Net::HTTPRresponse] response
# The received HTTP response object.
#
# @return [Net::HTTPResponse]
# The new HTTP Request object.
#
def http_copy(path,**kwargs)
if debug?
print_debug "Requesting COPY #{url_for(path)} ..."
end
http.copy(path,**kwargs)
end
#
# Performs a `DELETE` request for the given URI.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @yield [response]
# If a block is given it will be passed the received HTTP response.
#
# @yieldparam [Net::HTTPRresponse] response
# The received HTTP response object.
#
# @return [Net::HTTPResponse]
# The new HTTP Request object.
#
def http_delete(path,**kwargs,&block)
if debug?
print_debug "Requesting DELETE #{url_for(path)} ..."
end
http.delete(path,**kwargs)
end
#
# Performs a `GET` request for the given URI.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @yield [response]
# If a block is given it will be passed the received HTTP response.
#
# @yieldparam [Net::HTTPRresponse] response
# The received HTTP response object.
#
# @return [Net::HTTPResponse]
# The new HTTP Request object.
#
def http_get(path,**kwargs,&block)
if debug?
print_debug "Requesting GET #{url_for(path)} ..."
end
http.get(path,**kwargs)
end
#
# Performs a `GET` request for the given URI and returns the response
# headers.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @return [Hash{String => String}]
# The response headers.
#
def http_get_headers(path,**kwargs)
if debug?
print_debug "Requesting headers for GET #{url_for(path)} ..."
end
http.get_headers(path,**kwargs)
end
#
# Sends an HTTP request and returns the parsed `Set-Cookie`
# header(s).
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @return [Array, nil]
# The parsed `SetCookie` header(s).
#
def http_get_cookies(path,**kwargs)
if debug?
print_debug "Getting cookies for #{url_for(path)} ..."
end
http.get_cookies(path,**kwargs)
end
#
# Performs a `GET` request for the given URI and returns the response
# body.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @return [String]
# The response body.
#
def http_get_body(path,**kwargs)
if debug?
print_debug "Requesting body for GET #{url_for(path)} ..."
end
http.get_body(path,**kwargs)
end
#
# Performs a `HEAD` request for the given URI.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @yield [response]
# If a block is given it will be passed the received HTTP response.
#
# @yieldparam [Net::HTTPRresponse] response
# The received HTTP response object.
#
# @return [Net::HTTPResponse]
# The new HTTP Request object.
#
def http_head(path,**kwargs,&block)
if debug?
print_debug "Requesting HEAD #{url_for(path)} ..."
end
http.head(path,**kwargs,&block)
end
#
# Performs a `LOCK` request for the given URI.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @yield [response]
# If a block is given it will be passed the received HTTP response.
#
# @yieldparam [Net::HTTPRresponse] response
# The received HTTP response object.
#
# @return [Net::HTTPResponse]
# The new HTTP Request object.
#
def http_lock(path,**kwargs,&block)
if debug?
print_debug "Requesting LOCK #{url_for(path)} ..."
end
http.lock(path,**kwargs,&block)
end
#
# Performs a `MKCOL` request for the given URI.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @yield [response]
# If a block is given it will be passed the received HTTP response.
#
# @yieldparam [Net::HTTPRresponse] response
# The received HTTP response object.
#
# @return [Net::HTTPResponse]
# The new HTTP Request object.
#
def http_mkcol(path,**kwargs,&block)
if debug?
print_debug "Requesting MKCOL #{url_for(path)} ..."
end
http.mkcol(path,**kwargs,&block)
end
#
# Performs a `MOVE` request for the given URI.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @yield [response]
# If a block is given it will be passed the received HTTP response.
#
# @yieldparam [Net::HTTPRresponse] response
# The received HTTP response object.
#
# @return [Net::HTTPResponse]
# The new HTTP Request object.
#
def http_move(path,**kwargs,&block)
if debug?
print_debug "Requesting MOVE #{url_for(path)} ..."
end
http.move(path,**kwargs,&block)
end
#
# Performs a `OPTIONS` request for the given URI.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @yield [response]
# If a block is given it will be passed the received HTTP response.
#
# @yieldparam [Net::HTTPRresponse] response
# The received HTTP response object.
#
# @return [Net::HTTPResponse]
# The new HTTP Request object.
#
def http_options(path,**kwargs,&block)
if debug?
print_debug "Requesting OPTIONS #{url_for(path)} ..."
end
http.options(path,**kwargs,&block)
end
#
# Performs a `OPTIONS` HTTP request for the given URI and parses the
# `Allow` response header.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @yield [response]
# If a block is given it will be passed the received HTTP response.
#
# @yieldparam [Net::HTTPRresponse] response
# The received HTTP response object.
#
# @return [Array]
# The allowed HTTP request methods for the given URL.
#
def http_allowed_methods(path,**kwargs,&block)
if debug?
print_debug "Checking allowed HTTP methods for #{url_for(path)} ..."
end
http.allowed_methods(path,**kwargs)
end
#
# Performs a `PATCH` request for the given URI.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @yield [response]
# If a block is given it will be passed the received HTTP response.
#
# @yieldparam [Net::HTTPRresponse] response
# The received HTTP response object.
#
# @return [Net::HTTPResponse]
# The new HTTP Request object.
#
# @see Network::HTTP.patch
#
def http_patch(path,**kwargs,&block)
if debug?
print_debug "Requesting PATCH #{url_for(path)} ..."
end
http.patch(path,**kwargs,&block)
end
#
# Performs a `POST` request for the given URI.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @yield [response]
# If a block is given it will be passed the received HTTP response.
#
# @yieldparam [Net::HTTPRresponse] response
# The received HTTP response object.
#
# @return [Net::HTTPResponse]
# The new HTTP Request object.
#
def http_post(path,**kwargs,&block)
if debug?
print_debug "Requesting POST #{url_for(path)} ..."
end
http.post(path,**kwargs,&block)
end
#
# Performs a `POST` request on the given URI and returns the response
# headers.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @return [Hash{String => String}]
# The response headers.
#
def http_post_headers(path,**kwargs)
if debug?
print_debug "Requesting response headers for POST #{url_for(path)} ..."
end
http.post_headers(path,**kwargs)
end
#
# Performs a `POST` request for the given URI and returns the
# response body.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @return [String]
# The response body.
#
def http_post_body(path,**kwargs)
if debug?
print_debug "Requesting response body for POST #{url_for(path)} ..."
end
http.post_body(path,**kwargs)
end
#
# Performs a `PROPFIND` request for the given URI.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @yield [response]
# If a block is given it will be passed the received HTTP response.
#
# @yieldparam [Net::HTTPRresponse] response
# The received HTTP response object.
#
# @return [Net::HTTPResponse]
# The new HTTP Request object.
#
def http_propfind(path,**kwargs,&block)
if debug?
print_debug "Requesting PROPFIND #{url_for(path)} ..."
end
http.propfind(path,**kwargs,&block)
end
alias http_prop_find http_propfind
#
# Performs a `PROPPATCH` request for the given URI.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @yield [response]
# If a block is given it will be passed the received HTTP response.
#
# @yieldparam [Net::HTTPRresponse] response
# The received HTTP response object.
#
# @return [Net::HTTPResponse]
# The new HTTP Request object.
#
def http_proppatch(path,**kwargs,&block)
if debug?
print_debug "Requesting PROPPATCH #{url_for(path)} ..."
end
http.proppatch(path,**kwargs,&block)
end
alias http_prop_patch http_proppatch
#
# Performs a `PUT` request for the given URI.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @yield [response]
# If a block is given it will be passed the received HTTP response.
#
# @yieldparam [Net::HTTPRresponse] response
# The received HTTP response object.
#
# @return [Net::HTTPResponse]
# The new HTTP Request object.
#
def http_put(path,**kwargs,&block)
if debug?
print_debug "Requesting PUT #{url_for(path)} ..."
end
http.put(path,**kwargs,&block)
end
#
# Performs a `TRACE` request for the given URI.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @yield [response]
# If a block is given it will be passed the received HTTP response.
#
# @yieldparam [Net::HTTPRresponse] response
# The received HTTP response object.
#
# @return [Net::HTTPResponse]
# The new HTTP Request object.
#
def http_trace(path,**kwargs,&block)
if debug?
print_debug "Requesting TRACE #{url_for(path)} ..."
end
http.trace(path,**kwargs,&block)
end
#
# Performs a `UNLOCK` request for the given URI.
#
# @param [String] path
# The path to create the HTTP request for.
#
# @!macro request_kwargs
#
# @yield [response]
# If a block is given it will be passed the received HTTP response.
#
# @yieldparam [Net::HTTPRresponse] response
# The received HTTP response object.
#
# @return [Net::HTTPResponse]
# The new HTTP Request object.
#
def http_unlock(path,**kwargs,&block)
if debug?
print_debug "Requesting UNLOCK #{url_for(path)} ..."
end
http.unlock(path,**kwargs,&block)
end
end
end
end
end