New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deserialize JSON into MDM Objects #9394

Closed
wants to merge 57 commits into
base: master
from
Commits
Jump to file or symbol
Failed to load files and symbols.
+151 −106
Diff settings

Always

Just for now

Viewing a subset of changes. View all

creds command converted

  • Loading branch information...
jbarnett-r7 committed Oct 16, 2017
commit 5232e9926e876437b98ef5cd578d2beb548f1d49
@@ -12,11 +12,10 @@ def create_credential(opts)
end
end
def credentials(opts = {})
def creds(opts = {})
begin
data_service = self.get_data_service
opts[:wspace] = wspace
data_service.loot(opts)
data_service.creds(opts)
rescue Exception => e
puts "Call to #{data_service.class}#credentials threw exception: #{e.message}"
e.backtrace.each { |line| puts "#{line}\n" }
@@ -5,7 +5,7 @@ module RemoteCredentialDataService
CREDENTIAL_PATH = '/api/1/msf/credential'
def credential(opts = {})
def creds(opts = {})
json_to_open_struct_object(self.get_data(CREDENTIAL_PATH, opts), [])
end
Copy path View file
@@ -1,9 +1,41 @@
module Msf::DBManager::Cred
# This methods returns a list of all credentials in the database
def creds(wspace=workspace)
::ActiveRecord::Base.connection_pool.with_connection {
Mdm::Cred.where("hosts.workspace_id = ?", wspace.id).joins(:service => :host)
}
def creds(opts)
query = nil
::ActiveRecord::Base.connection_pool.with_connection {
query = Metasploit::Credential::Core.where( workspace_id: framework.db.workspace.id )
query = query.includes(:private, :public, :logins).references(:private, :public, :logins)
query = query.includes(logins: [ :service, { service: :host } ])
if opts[:type].present?
query = query.where(metasploit_credential_privates: { type: opts[:type] })
end
if opts[:svcs].present?
query = query.where(Mdm::Service[:name].in(opts[:svcs]))
end
if opts[:ports].present?
query = query.where(Mdm::Service[:port].in(opts[:ports]))
end
if opts[:user].present?
# If we have a user regex, only include those that match
query = query.where('"metasploit_credential_publics"."username" ~* ?', opts[:user])
end
if opts[:pass].present?
# If we have a password regex, only include those that match
query = query.where('"metasploit_credential_privates"."data" ~* ?', opts[:pass])
end
if opts[:host_ranges] || opts[:ports] || opts[:svcs]
# Only find Cores that have non-zero Logins if the user specified a
# filter based on host, port, or service name
query = query.where(Metasploit::Credential::Login[:id].not_eq(nil))
end
}
query
end
# This method iterates the creds table calling the supplied block with the
@@ -5,8 +5,8 @@ def self.api_path
end
def self.registered(app)
app.get LootServlet.api_path, &get_credentials
app.post LootServlet.api_path, &create_credential
app.get CredentialServlet.api_path, &get_credentials
app.post CredentialServlet.api_path, &create_credential
end
#######
@@ -17,8 +17,16 @@ def self.get_credentials
lambda {
begin
opts = parse_json_request(request, false)
data = get_db().credentials(opts)
set_json_response(data)
data = get_db().creds(opts)
includes = [:logins, :public, :private, :origin, :realm]
# Need to append the human attribute into the private sub-object before converting to json
# This is normally pulled from a class method from the MetasploitCredential class
response = []
data.each do |cred|
json = cred.as_json(include: includes).merge('human' => cred.private.class.model_name.human)
response << json
end
set_json_response(response)
rescue Exception => e
set_error_on_response(e)
end
@@ -27,7 +35,7 @@ def self.get_credentials
def self.create_credential
lambda {
job = lambda { |opts| get_db().report_credential(opts) }
job = lambda { |opts| get_db().report_cred(opts) }
exec_report_job(request, &job)
}
end
@@ -290,6 +290,7 @@ def creds_search(*args)
port_ranges = []
svcs = []
rhosts = []
opts = {}
set_rhosts = false
@@ -314,6 +315,7 @@ def creds_search(*args)
end
when "-t","--type"
ptype = args.shift
opts[:ptype] = ptype
if (!ptype)
print_error("Argument required for -t")
return
@@ -325,14 +327,17 @@ def creds_search(*args)
return
end
svcs = service.split(/[\s]*,[\s]*/)
opts[:svcs] = svcs
when "-P","--password"
pass = args.shift
opts[:pass] = pass
if (!pass)
print_error("Argument required for -P")
return
end
when "-u","--user"
user = args.shift
opts[:user] = user
if (!user)
print_error("Argument required for -u")
return
@@ -343,13 +348,15 @@ def creds_search(*args)
set_rhosts = true
when '-O', '--origins'
hosts = args.shift
opts[:hosts] = hosts
if !hosts
print_error("Argument required for -O")
return
end
arg_host_range(hosts, origin_ranges)
when '-S', '--search-term'
search_term = args.shift
opts[:search_term] = search_term
else
# Anything that wasn't an option is a host to search for
unless (arg_host_range(arg, host_ranges))
@@ -374,6 +381,8 @@ def creds_search(*args)
end
end
opts[:type] = type if type
# normalize
ports = port_ranges.flatten.uniq
svcs.flatten!
@@ -384,120 +393,117 @@ def creds_search(*args)
}
tbl = Rex::Text::Table.new(tbl_opts)
opts = {}
opts[:wspace] = framework.db.workspace
query = framework.db.creds(opts)
::ActiveRecord::Base.connection_pool.with_connection {
query = Metasploit::Credential::Core.where( workspace_id: framework.db.workspace )
query = query.includes(:private, :public, :logins).references(:private, :public, :logins)
query = query.includes(logins: [ :service, { service: :host } ])
if type.present?
query = query.where(metasploit_credential_privates: { type: type })
end
if svcs.present?
query = query.where(Mdm::Service[:name].in(svcs))
end
query.each do |core|
if ports.present?
query = query.where(Mdm::Service[:port].in(ports))
# Exclude non-blank username creds if that's what we're after
if user == "" && core.public && !(core.public.username.blank?)
next
end
if user.present?
# If we have a user regex, only include those that match
query = query.where('"metasploit_credential_publics"."username" ~* ?', user)
# Exclude non-blank password creds if that's what we're after
if pass == "" && core.private && !(core.private.data.blank?)
next
end
if pass.present?
# If we have a password regex, only include those that match
query = query.where('"metasploit_credential_privates"."data" ~* ?', pass)
origin = ''
if core.origin.kind_of?(Metasploit::Credential::Origin::Service)
origin = core.origin.service.host.address
elsif core.origin.kind_of?(Metasploit::Credential::Origin::Session)
origin = core.origin.session.host.address
end
if host_ranges.any? || ports.any? || svcs.any?
# Only find Cores that have non-zero Logins if the user specified a
# filter based on host, port, or service name
query = query.where(Metasploit::Credential::Login[:id].not_eq(nil))
if !origin.empty? && origin_ranges.present? && !origin_ranges.any? {|range| range.include?(origin) }
next
end
query.find_each do |core|
# Exclude non-blank username creds if that's what we're after
if user == "" && core.public && !(core.public.username.blank?)
next
end
# Exclude non-blank password creds if that's what we're after
if pass == "" && core.private && !(core.private.data.blank?)
next
end
origin = ''
if core.origin.kind_of?(Metasploit::Credential::Origin::Service)
origin = core.origin.service.host.address
elsif core.origin.kind_of?(Metasploit::Credential::Origin::Session)
origin = core.origin.session.host.address
if core.logins.empty? && origin_ranges.empty?
public_val = core.public ? core.public.username : ""
private_val = core.private ? core.private.data : ""
realm_val = core.realm ? core.realm.value : ""
human_val = ""
# TODO: We shouldn't have separate code paths depending on the model we're working with
# This should always expect an OpenStruct.
if core.private
if core.private.is_a?(OpenStruct)
human_val = core.human
else
human_val = core.private.class.model_name.human
end
end
if !origin.empty? && origin_ranges.present? && !origin_ranges.any? {|range| range.include?(origin) }
next
end
tbl << [
"", # host
"", # cred
"", # service
public_val,
private_val,
realm_val,
human_val,
]
else
core.logins.each do |login|
# If none of this Core's associated Logins is for a host within
# the user-supplied RangeWalker, then we don't have any reason to
# print it out. However, we treat the absence of ranges as meaning
# all hosts.
if host_ranges.present? && !host_ranges.any? { |range| range.include?(login.service.host.address) }
next
end
if core.logins.empty? && origin_ranges.empty?
tbl << [
"", # host
"", # cred
"", # service
core.public,
core.private,
core.realm,
core.private ? core.private.class.model_name.human : "",
]
else
core.logins.each do |login|
# If none of this Core's associated Logins is for a host within
# the user-supplied RangeWalker, then we don't have any reason to
# print it out. However, we treat the absence of ranges as meaning
# all hosts.
if host_ranges.present? && !host_ranges.any? { |range| range.include?(login.service.host.address) }
next
end
row = [ login.service.host.address ]
row << origin
rhosts << login.service.host.address
if login.service.name.present?
row << "#{login.service.port}/#{login.service.proto} (#{login.service.name})"
else
row << "#{login.service.port}/#{login.service.proto}"
end
row = [ login.service.host.address ]
row << origin
rhosts << login.service.host.address
if login.service.name.present?
row << "#{login.service.port}/#{login.service.proto} (#{login.service.name})"
public_val = core.public ? core.public.username : ""
private_val = core.private ? core.private.data : ""
realm_val = core.realm ? core.realm.value : ""
human_val = ""
# TODO: We shouldn't have separate code paths depending on the model we're working with
# This should always expect an OpenStruct.
if core.private
if core.private.is_a?(OpenStruct)
human_val = core.human
else
row << "#{login.service.port}/#{login.service.proto}"
human_val = core.private.class.model_name.human
end
row += [
core.public,
core.private,
core.realm,
core.private ? core.private.class.model_name.human : "",
]
tbl << row
end
end
if mode == :delete
core.destroy
delete_count += 1
row += [
public_val,
private_val,
realm_val,
human_val,
]
tbl << row
end
end
if output_file.nil?
print_line(tbl.to_s)
else
# create the output file
::File.open(output_file, "wb") { |f| f.write(tbl.to_csv) }
print_status("Wrote creds to #{output_file}")
if mode == :delete
core.destroy
delete_count += 1
end
end
# Finally, handle the case where the user wants the resulting list
# of hosts to go into RHOSTS.
set_rhosts_from_addrs(rhosts.uniq) if set_rhosts
print_status("Deleted #{delete_count} creds") if delete_count > 0
}
if output_file.nil?
print_line(tbl.to_s)
else
# create the output file
::File.open(output_file, "wb") { |f| f.write(tbl.to_csv) }
print_status("Wrote creds to #{output_file}")
end
# Finally, handle the case where the user wants the resulting list
# of hosts to go into RHOSTS.
set_rhosts_from_addrs(rhosts.uniq) if set_rhosts
print_status("Deleted #{delete_count} creds") if delete_count > 0
end
def cmd_creds_tabs(str, words)
ProTip! Use n and p to navigate between commits in a pull request.