Files
metasploit-gs/lib/msf/core/exploit/sqli/common.rb
T
2023-09-24 17:42:00 -04:00

88 lines
4.4 KiB
Ruby

module Msf::Exploit::SQLi
class Common
include Msf::Module::UI
#
# Creates an instance of an SQL Injection object, users should use the create_dbms method of Msf::Exploit::SQLi instead
#
# @param datastore [DataStore]
# @param framework [Framework]
# @param user_output [Rex::Ui::Text::Output::Stdio]
# @param opts [Hash] a dictionary containing the parameters needed
# @option opts [Integer] truncation_length : [Optional] The number of characters returned, if the query result is truncated
# @option opts [String] concat_separator : [Optional] The separator to use when concatenating rows (default ',')
# @option opts [String] second_concat_separator : [Optional] The separator to use when concatenating columns (default ';')
# @option opts [Boolean] safe : don't use group_concat, safer for large tables if group_concat truncates the result, but more queries will be performed
# @option opts [String] null_replacement : a string that will replace NULL values
# @option opts [Boolean] hex_encode_strings : encode strings as hex numbers, no quotes in the payload
# @option opts [Object] an encoder name, or a hash specifying a custom encoder, see Encoders in DBMS-specific classes
# @param query_proc [Proc] a block that will receive the payload, and should send the request to the target,
# - if it's a regular SQL injection, it should return the part of the response that is the query result (one row)
# - if it's a boolean-based blind SQL injection, it should return `true`, `false`, or a value that evaluates to one of them
# `true` if the query returned a result, false otherwise
# - if it's a time-based blind SQL injection, the return value does not matter, the time the block takes to run is used to leak information.
#
def initialize(datastore, framework, user_output, opts = {}, &query_proc)
raise ArgumentError, 'Missing the block that does the requests' unless block_given?
raise ArgumentError, 'Positional arguments can\'t be nil' if [datastore, framework, user_output].any?(&:nil?)
check_opts(opts)
@query_proc = query_proc
@safe = opts[:safe]
@concat_separator = opts[:concat_separator]
@second_concat_separator = opts[:second_concat_separator] || ';'
@null_replacement = opts[:null_replacement] || ''
@truncation_length = opts[:truncation_length] if opts[:truncation_length] && opts[:truncation_length].is_a?(Integer) && opts[:truncation_length] > 0
@hex_encode_strings = opts[:hex_encode_strings]
@encoder = opts[:encoder]
@datastore = datastore
@framework = framework
@user_output = user_output
end
#
# Queries the block with the given SQL query, without necessarily returning a result (needed for
# example when uploading a file using a time-based SQL injection, as it's not necessary to
# run multiple queries for that purpose), not to be overridden, it is guaranteed that the query
# will run only once.
# @param query [String] The SQL query to execute
# @return [void]
#
def raw_run_sql(query)
vprint_status "{SQLi} Executing (#{query})"
if @hex_encode_strings
query = hex_encode_strings(query)
vprint_status "{SQLi} Encoded to (#{query})"
end
@query_proc.call(query)
end
#
# Queries the block with the given SQL query, and returns the result, this method is overridden in
# blind SQL injection classes, implementing the logic of leaking one bit at a time, and working
# exactly the same as this method.
# @param query [String] The SQL query to execute
# @return [String] The query results
#
def run_sql(query)
raw_run_sql(query)
end
attr_reader :datastore, :framework
attr_accessor :concat_separator, :second_concat_separator, :null_replacement, :truncation_length, :safe
private
#
# This method checks that the required options are present, and have valid values
# @param opts [Hash] the options provided by the user
# @return [void]
#
def check_opts(opts)
raise ArgumentError, 'null_replacement option cannot contain single quotes' if opts[:null_replacement] && opts[:null_replacement].include?("'")
raise ArgumentError, 'truncation_length must be an integer' if opts[:truncation_length] && !opts[:truncation_length].is_a?(Integer)
end
end
end