Files
metasploit-gs/lib/msf/core/db_manager/loot.rb
T

150 lines
4.8 KiB
Ruby

module Msf::DBManager::Loot
#
# Find or create a loot matching this type/data
#
def find_or_create_loot(opts)
report_loot(opts)
end
#
# This methods returns a list of all loot in the database
#
def loots(opts)
::ApplicationRecord.connection_pool.with_connection {
# If we have the ID, there is no point in creating a complex query.
if opts[:id] && !opts[:id].to_s.empty?
return Array.wrap(Mdm::Loot.find(opts[:id]))
end
opts = opts.clone() # protect the original caller's opts
# Remove path from search conditions as this won't accommodate remote data
# service usage where the client and server storage locations differ.
opts.delete(:path)
search_term = opts.delete(:search_term)
data = opts.delete(:data)
wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework)
opts = opts.clone()
opts.delete(:workspace)
opts[:workspace_id] = wspace.id
if search_term && !search_term.empty?
column_search_conditions = Msf::Util::DBManager.create_all_column_search_conditions(Mdm::Loot, search_term)
results = Mdm::Loot.includes(:host).where(opts).where(column_search_conditions)
else
results = Mdm::Loot.includes(:host).where(opts)
end
# Compare the deserialized data from the DB to the search data since the column is serialized.
unless data.nil?
results = results.select { |loot| loot.data == data }
end
results
}
end
alias_method :loot, :loots
def report_loot(opts)
return if not active
::ApplicationRecord.connection_pool.with_connection {
wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework)
opts = opts.clone()
opts.delete(:workspace)
path = opts.delete(:path) || (raise RuntimeError, "A loot :path is required")
host = nil
addr = nil
# Report the host so it's there for the Proc to use below
if opts[:host]
if opts[:host].kind_of? ::Mdm::Host
host = opts[:host]
else
host = report_host({:workspace => wspace, :host => opts[:host]})
addr = Msf::Util::Host.normalize_host(opts[:host])
end
end
ret = {}
ltype = opts.delete(:type) || opts.delete(:ltype) || (raise RuntimeError, "A loot :type or :ltype is required")
ctype = opts.delete(:ctype) || opts.delete(:content_type) || 'text/plain'
name = opts.delete(:name)
info = opts.delete(:info)
data = opts[:data]
loot = wspace.loots.new
if host
loot.host_id = host[:id]
end
if opts[:service] and opts[:service].kind_of? ::Mdm::Service
loot.service_id = opts[:service][:id]
end
loot.path = path
loot.ltype = ltype
loot.content_type = ctype
loot.data = data
loot.name = name if name
loot.info = info if info
loot.workspace = wspace
msf_import_timestamps(opts,loot)
loot.save!
ret[:loot] = loot
}
end
# Update the attributes of a Loot entry with the values in opts.
# The values in opts should match the attributes to update.
#
# @param opts [Hash] Hash containing the updated values. Key should match the attribute to update. Must contain :id of record to update.
# @return [Mdm::Loot] The updated Mdm::Loot object.
def update_loot(opts)
::ApplicationRecord.connection_pool.with_connection {
wspace = Msf::Util::DBManager.process_opts_workspace(opts, framework, false)
# Prevent changing the data field to ensure the file contents remain the same as what was originally looted.
raise ArgumentError, "Updating the data attribute is not permitted." if opts[:data]
opts = opts.clone()
opts.delete(:workspace)
opts[:workspace] = wspace if wspace
id = opts.delete(:id)
loot = Mdm::Loot.find(id)
# If the user updates the path attribute (or filename) we need to update the file
# on disk to reflect that.
if opts[:path] && File.exist?(loot.path)
File.rename(loot.path, opts[:path])
end
loot.update!(opts)
return loot
}
end
# Deletes Loot entries based on the IDs passed in.
#
# @param opts[:ids] [Array] Array containing Integers corresponding to the IDs of the Loot entries to delete.
# @return [Array] Array containing the Mdm::Loot objects that were successfully deleted.
def delete_loot(opts)
raise ArgumentError.new("The following options are required: :ids") if opts[:ids].nil?
::ApplicationRecord.connection_pool.with_connection {
deleted = []
opts[:ids].each do |loot_id|
loot = Mdm::Loot.find(loot_id)
begin
deleted << loot.destroy
rescue # refs suck
elog("Forcibly deleting #{loot}")
deleted << loot.delete
end
end
return deleted
}
end
end