From 2013e28608b3098501653d0e72181a0bbd1dbacd Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 22 Jul 2014 02:05:55 -0500 Subject: [PATCH 01/17] WIP: First stab at creds add-* subcommands --- lib/msf/ui/console/command_dispatcher/db.rb | 37 +++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index ccd0450953..f7d4e97719 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -18,6 +18,8 @@ class Db # TODO: Not thrilled about including this entire module for just store_local. include Msf::Auxiliary::Report + include Metasploit::Credential::Creation + # # The dispatcher's name. # @@ -668,6 +670,25 @@ class Db print_line end + def creds_add(private_type, *args) + username, password, realm = args.pop(3) + cred_data = { + username: username, + private_data: password, + private_type: private_type, + workspace_id: framework.db.workspace, + } + if realm + cred_data.merge( + realm_value: realm, + realm_key: Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN + ) + end + + $stderr.puts("Your mom") + create_credential(cred_data) + end + # # Can return return active or all, on a certain host or range, on a # certain port or range, and/or on a service name. @@ -690,6 +711,22 @@ class Db return end + subcommand = args.shift + case subcommand + when "add-ntlm" + creds_add(:ntlm_hash, *args) + return + when "add-password" + creds_add(:password, *args) + return + when "add-hash" + creds_add(:non_replayable_hash, *args) + return + else + # then it's not actually a subcommand + args.unshift(subcommand) + end + while (arg = args.shift) case arg when "-h" From 4f19a1defaaea3ec88bce4763d9d6296ccffae42 Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 22 Jul 2014 19:52:10 -0500 Subject: [PATCH 02/17] Add an origin type and actually honor realm Also adds better help text --- lib/msf/ui/console/command_dispatcher/db.rb | 47 ++++++++++++++++----- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index f7d4e97719..6122867e64 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -650,24 +650,47 @@ class Db end def cmd_creds_help - print_line "Usage: creds [addr range]" - print_line "List credentials. If an address range is given, show only credentials with" - print_line "logins on hosts within that range." print_line + print_line "With no sub-command, list credentials. If an address range is" + print_line "given, show only credentials with logins on hosts within that" + print_line "range." + + print_line + print_line "Usage - Listing credentials:" + print_line " creds [filter options] [address range]" + print_line + print_line "Usage - Adding credentials:" + print_line " creds add-ntlm [domain]" + print_line " creds add-password [realm]" + + print_line + print_line "General options" print_line " -h,--help Show this help information" - print_line " -c,--columns Columns of interest" + print_line + print_line "Filter options" print_line " -P,--password List passwords that match this regex" print_line " -p,--port List creds with logins on services matching this port spec" print_line " -s List creds matching comma-separated service names" print_line " -u,--user List users that match this regex" + #print_line + #print_line "Add options" + #print_line " --realm-type One of: domain, db2, sid, pgdb. (Defaults to domain)" print_line - print_line "Examples:" + print_line "Examples, listing:" print_line " creds # Default, returns all credentials" print_line " creds 1.2.3.4/24 # nmap host specification" print_line " creds -p 22-25,445 # nmap port specification" print_line " creds -s ssh,smb # All creds associated with a login on SSH or SMB services" print_line + + print_line + print_line "Examples, adding:" + print_line " # Add a user with an NTLMHash" + print_line " creds add-ntlm alice aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0" + print_line " # Add a user with a blank password and a domain" + print_line " creds add-password bob '' contosso" + print_line end def creds_add(private_type, *args) @@ -677,16 +700,21 @@ class Db private_data: password, private_type: private_type, workspace_id: framework.db.workspace, + origin_type: :import, + filename: "MSFCONSOLE" } if realm - cred_data.merge( + cred_data.merge!( realm_value: realm, realm_key: Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN ) end - $stderr.puts("Your mom") - create_credential(cred_data) + begin + create_credential(cred_data) + rescue ActiveRecord::RecordInvalid => e + print_error("Failed to add #{private_type}: #{e}") + end end # @@ -729,9 +757,6 @@ class Db while (arg = args.shift) case arg - when "-h" - cmd_creds_help - return when '-o' output_file = args.shift if (!output_file) From 1a4e59e54759fa1a73f8b2ec30bfc098285d3d31 Mon Sep 17 00:00:00 2001 From: James Lee Date: Wed, 23 Jul 2014 17:09:02 -0500 Subject: [PATCH 03/17] Add add-ssh-key subcommand --- lib/msf/ui/console/command_dispatcher/db.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index 6122867e64..db93b10d72 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -717,6 +717,18 @@ class Db end end + def creds_add_ssh_key(*args) + username, key_file = args.pop(2) + + begin + key_data = File.read(key_file) + rescue ::Errno::EACCES, ::Errno::ENOENT => e + print_error("Failed to add ssh key: #{e}") + else + creds_add(:ssh_key, username, key_data, *args) + end + end + # # Can return return active or all, on a certain host or range, on a # certain port or range, and/or on a service name. @@ -750,6 +762,9 @@ class Db when "add-hash" creds_add(:non_replayable_hash, *args) return + when "add-ssh-key" + creds_add_ssh_key(*args) + return else # then it's not actually a subcommand args.unshift(subcommand) From 8a279d202cfb2f0d836bd48773963f58d3605cf2 Mon Sep 17 00:00:00 2001 From: James Lee Date: Thu, 24 Jul 2014 13:56:57 -0500 Subject: [PATCH 04/17] Whitespace --- lib/rex/ui/text/table.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/rex/ui/text/table.rb b/lib/rex/ui/text/table.rb index ca1c3ec5d3..25a197edeb 100644 --- a/lib/rex/ui/text/table.rb +++ b/lib/rex/ui/text/table.rb @@ -275,9 +275,9 @@ protected nameline << pad(' ', last_col, last_idx) remainder = colprops[last_idx]['MaxWidth'] - last_col.length - if (remainder < 0) - remainder = 0 - end + if (remainder < 0) + remainder = 0 + end barline << (' ' * (cellpad + remainder)) end nameline << col From 1470f3de307eb09ab9a416d3dc77691d2da9c010 Mon Sep 17 00:00:00 2001 From: James Lee Date: Thu, 24 Jul 2014 14:00:09 -0500 Subject: [PATCH 05/17] Fix padding when a cell value is nil --- lib/rex/ui/text/table.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rex/ui/text/table.rb b/lib/rex/ui/text/table.rb index 25a197edeb..0cbb315494 100644 --- a/lib/rex/ui/text/table.rb +++ b/lib/rex/ui/text/table.rb @@ -305,7 +305,7 @@ protected last_cell = nil last_idx = nil row.each_with_index { |cell, idx| - if (last_cell) + if (idx != 0) line << pad(' ', last_cell.to_s, last_idx) end # line << pad(' ', cell.to_s, idx) From 18ce342e2a06f76d8f8701f0ac9c836a1df4ae5b Mon Sep 17 00:00:00 2001 From: James Lee Date: Thu, 24 Jul 2014 15:42:36 -0500 Subject: [PATCH 06/17] Refactor a bit for readability --- lib/msf/ui/console/command_dispatcher/db.rb | 188 +++++++++++--------- 1 file changed, 101 insertions(+), 87 deletions(-) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index db93b10d72..cc4e645a2e 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -693,8 +693,7 @@ class Db print_line end - def creds_add(private_type, *args) - username, password, realm = args.pop(3) + def creds_add(private_type, username, password=nil, realm=nil) cred_data = { username: username, private_data: password, @@ -717,9 +716,19 @@ class Db end end - def creds_add_ssh_key(*args) - username, key_file = args.pop(2) + def creds_add_non_replayable_hash(*args) + creds_add(:non_replayable_hash, *args) + end + def creds_add_ntlm_hash(*args) + creds_add(:ntlm_hash, *args) + end + + def creds_add_password(*args) + creds_add(:password, *args) + end + + def creds_add_ssh_key(username, *args) begin key_data = File.read(key_file) rescue ::Errno::EACCES, ::Errno::ENOENT => e @@ -729,47 +738,15 @@ class Db end end - # - # Can return return active or all, on a certain host or range, on a - # certain port or range, and/or on a service name. - # - def cmd_creds(*args) - return unless active? - ::ActiveRecord::Base.connection_pool.with_connection { - + def creds_search(*args) host_ranges = [] port_ranges = [] svcs = [] #cred_table_columns = [ 'host', 'port', 'user', 'pass', 'type', 'proof', 'active?' ] - cred_table_columns = [ 'host', 'port', 'public', 'private', 'realm', 'private_type' ] + cred_table_columns = [ 'host', 'service', 'public', 'private', 'realm', 'private_type' ] user = nil - # Short-circuit help - if args.delete "-h" - cmd_creds_help - return - end - - subcommand = args.shift - case subcommand - when "add-ntlm" - creds_add(:ntlm_hash, *args) - return - when "add-password" - creds_add(:password, *args) - return - when "add-hash" - creds_add(:non_replayable_hash, *args) - return - when "add-ssh-key" - creds_add_ssh_key(*args) - return - else - # then it's not actually a subcommand - args.unshift(subcommand) - end - while (arg = args.shift) case arg when '-o' @@ -834,67 +811,104 @@ class Db tbl = Rex::Ui::Text::Table.new(tbl_opts) - query = Metasploit::Credential::Core.where( - workspace_id: framework.db.workspace, - ) + ::ActiveRecord::Base.connection_pool.with_connection { + query = Metasploit::Credential::Core.where( + workspace_id: framework.db.workspace, + ) - query.each do |core| + query.each do |core| - # Exclude creds that don't match the given user - if user_regex.present? && !core.public.username.match(user_regex) - next - end + # Exclude creds that don't match the given user + if user_regex.present? && !core.public.username.match(user_regex) + next + end - # Exclude creds that don't match the given pass - if pass_regex.present? && !core.private.data.match(pass_regex) - next - end + # Exclude creds that don't match the given pass + if pass_regex.present? && !core.private.data.match(pass_regex) + next + end - if core.logins.empty? - # Skip cores that don't have any logins if the user specified a - # filter based on host, port, or service name - next if host_ranges.any? || ports.any? || svcs.any? - - tbl << [ - "", # host - "", # port - core.public ? core.public.username : "", - core.private ? core.private.data : "", - core.realm ? core.realm.value : "", - core.private ? core.private.class.model_name.human : "", - ] - else - core.logins.each do |login| - if svcs.present? && !svcs.include?(login.service.name) - next - end - - if ports.present? && !ports.include?(login.service.port) - next - end - - # 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? + # Skip cores that don't have any logins if the user specified a + # filter based on host, port, or service name + next if host_ranges.any? || ports.any? || svcs.any? tbl << [ - login.service.host.address, - login.service.port, - core.public ? core.public.username : "", - core.private ? core.private.data : "", - core.realm ? core.realm.value : "", + "", # host + "", # port + core.public, + core.private, + core.realm, core.private ? core.private.class.model_name.human : "", ] + else + core.logins.each do |login| + if svcs.present? && !svcs.include?(login.service.name) + next + end + + if ports.present? && !ports.include?(login.service.port) + next + end + + # 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 ] + 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 += [ + core.public, + core.private, + core.realm, + core.private ? core.private.class.model_name.human : "", + ] + tbl << row + end end end + + print_line(tbl.to_s) + } + end + + # + # Can return return active or all, on a certain host or range, on a + # certain port or range, and/or on a service name. + # + def cmd_creds(*args) + return unless active? + + # Short-circuit help + if args.delete "-h" + cmd_creds_help + return + end + + subcommand = args.shift + case subcommand + when "add-ntlm" + creds_add_ntlm_hash(*args) + when "add-password" + creds_add_password(*args) + when "add-hash" + creds_add_non_replayable_hash(*args) + when "add-ssh-key" + creds_add_ssh_key(*args) + else + # then it's not actually a subcommand + args.unshift(subcommand) if subcommand + creds_search(*args) end - print_line(tbl.to_s) - } end def cmd_notes_help From b8b3509c96d65f81ad99c4bec3ae1dbf217dafdd Mon Sep 17 00:00:00 2001 From: James Lee Date: Thu, 24 Jul 2014 15:44:52 -0500 Subject: [PATCH 07/17] Re-add the ability to delete creds --- lib/msf/ui/console/command_dispatcher/db.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index cc4e645a2e..09f53ce5ac 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -746,6 +746,7 @@ class Db #cred_table_columns = [ 'host', 'port', 'user', 'pass', 'type', 'proof', 'active?' ] cred_table_columns = [ 'host', 'service', 'public', 'private', 'realm', 'private_type' ] user = nil + delete_count = 0 while (arg = args.shift) case arg @@ -785,6 +786,8 @@ class Db print_error("Argument required for -u") return end + when "-d" + mode = :delete else # Anything that wasn't an option is a host to search for unless (arg_host_range(arg, host_ranges)) @@ -874,9 +877,14 @@ class Db tbl << row end end + if mode == :delete + core.destroy + delete_count += 1 + end end print_line(tbl.to_s) + print_status("Deleted #{delete_count} creds") if delete_count > 0 } end From bc836f3606f7c56fd82386b2045f23bd7bf0a0f1 Mon Sep 17 00:00:00 2001 From: James Lee Date: Thu, 24 Jul 2014 16:37:24 -0500 Subject: [PATCH 08/17] Add a little easter egg in the NTLM hash --- lib/msf/ui/console/command_dispatcher/db.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index 09f53ce5ac..88c01ed553 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -687,7 +687,7 @@ class Db print_line print_line "Examples, adding:" print_line " # Add a user with an NTLMHash" - print_line " creds add-ntlm alice aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0" + print_line " creds add-ntlm alice 5cfe4c82d9ab8c66590f5b47cd6690f1:978a2e2e1dec9804c6b936f254727f9a" print_line " # Add a user with a blank password and a domain" print_line " creds add-password bob '' contosso" print_line From b8bb4c7bc039a99a7a93cf08d5229cc12803872d Mon Sep 17 00:00:00 2001 From: James Lee Date: Sun, 27 Jul 2014 13:46:38 -0500 Subject: [PATCH 09/17] Add add-ssh-key to help output, fix some warnings --- lib/msf/ui/console/command_dispatcher/db.rb | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index 88c01ed553..55ffc04bb5 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -219,7 +219,6 @@ class Db return unless active? ::ActiveRecord::Base.connection_pool.with_connection { onlyup = false - host_search = nil set_rhosts = false mode = :search delete_count = 0 @@ -582,7 +581,6 @@ class Db return end - mode = :search while (arg = args.shift) case arg #when "-a","--add" @@ -662,6 +660,7 @@ class Db print_line "Usage - Adding credentials:" print_line " creds add-ntlm [domain]" print_line " creds add-password [realm]" + print_line " creds add-ssh-key [realm]" print_line print_line "General options" @@ -729,12 +728,13 @@ class Db end def creds_add_ssh_key(username, *args) + key_file, realm = args begin key_data = File.read(key_file) rescue ::Errno::EACCES, ::Errno::ENOENT => e print_error("Failed to add ssh key: #{e}") else - creds_add(:ssh_key, username, key_data, *args) + creds_add(:ssh_key, username, key_data, realm) end end @@ -1156,8 +1156,8 @@ class Db info = args.shift if(!info) print_error("Can't make loot with no info") - return - end + return + end when '-t' typelist = args.shift if(!typelist) @@ -1205,8 +1205,8 @@ class Db range.each do |host| file = File.open(filename, "rb") contents = file.read - lootfile = framework.db.find_or_create_loot(:type => type, :host => host,:info => info, :data => contents,:path => filename,:name => name) - print_status("Added loot #{host}") + lootfile = framework.db.find_or_create_loot(:type => type, :host => host, :info => info, :data => contents, :path => filename, :name => name) + print_status("Added loot for #{host} (#{lootfile})") end end return @@ -1362,7 +1362,7 @@ class Db def cmd_db_import(*args) return unless active? ::ActiveRecord::Base.connection_pool.with_connection { - if (args.include?("-h") or not (args and args.length > 0)) + if args.include?("-h") || ! (args && args.length > 0) cmd_db_import_help return end @@ -1425,8 +1425,8 @@ class Db next rescue REXML::ParseException => e print_error("Failed to import #{filename} due to malformed XML:") - print_error("#{$!.class}: #{$!}") - elog("Failed to import #{filename}: #{$!.class}: #{$!}") + print_error("#{e.class}: #{e}") + elog("Failed to import #{filename}: #{e.class}: #{e}") dlog("Call stack: #{$@.join("\n")}", LEV_3) next end @@ -1728,7 +1728,6 @@ class Db end def db_find_tools(tools) - found = true missed = [] tools.each do |name| if(! Rex::FileUtils.find_full_path(name)) From a35e7371bb7b05639bdc36b97713e8858280017c Mon Sep 17 00:00:00 2001 From: James Lee Date: Sun, 27 Jul 2014 14:05:39 -0500 Subject: [PATCH 10/17] Add simple tabbing for creds command --- lib/msf/ui/console/command_dispatcher/db.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index 55ffc04bb5..5a9762d685 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -919,6 +919,23 @@ class Db end + def cmd_creds_tabs(str, words) + case words.length + when 1 + # subcommands + tabs = [ 'add-ntlm', 'add-password', 'add-hash', 'add-ssh-key', ] + when 2 + tabs = if words[1] == 'add-ssh-key' + tab_complete_filenames(str, words) + else + [] + end + else + tabs = [] + end + return tabs + end + def cmd_notes_help print_line "Usage: notes [-h] [-t ] [-n ] [-a] [addr range]" print_line From 1931024c86572f306d8e1c948b31061887bf193e Mon Sep 17 00:00:00 2001 From: James Lee Date: Sun, 27 Jul 2014 14:04:20 -0500 Subject: [PATCH 11/17] Bump credential version for #to_s fixes --- Gemfile | 2 +- Gemfile.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Gemfile b/Gemfile index da51f4999b..ac228f3df8 100755 --- a/Gemfile +++ b/Gemfile @@ -7,7 +7,7 @@ group :db do # Needed for Msf::DbManager gem 'activerecord', '>= 3.0.0', '< 4.0.0' # Metasploit::Credential database models - gem 'metasploit-credential', '>= 0.7.10.pre.core.pre.search', '< 0.8' + gem 'metasploit-credential', '~> 0.7.14', '< 0.8' # Database models shared between framework and Pro. gem 'metasploit_data_models', '~> 0.19' # Needed for module caching in Mdm::ModuleDetails diff --git a/Gemfile.lock b/Gemfile.lock index c36333f202..42ccda85a9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -60,7 +60,7 @@ GEM json (1.8.1) metasploit-concern (0.1.1) activesupport (~> 3.0, >= 3.0.0) - metasploit-credential (0.7.10.pre.core.pre.search) + metasploit-credential (0.7.14) metasploit-concern (~> 0.1.0) metasploit-model (>= 0.25.6) metasploit_data_models (~> 0.19) @@ -69,7 +69,7 @@ GEM rubyzip (~> 1.1) metasploit-model (0.25.6) activesupport - metasploit_data_models (0.19.0) + metasploit_data_models (0.19.3) activerecord (>= 3.2.13, < 4.0.0) activesupport arel-helpers @@ -82,7 +82,7 @@ GEM msgpack (0.5.8) multi_json (1.0.4) network_interface (0.0.1) - nokogiri (1.6.2.1) + nokogiri (1.6.3.1) mini_portile (= 0.6.0) packetfu (1.1.9) pcaprub (0.11.3) @@ -118,9 +118,9 @@ GEM rspec-collection_matchers (1.0.0) rspec-expectations (>= 2.99.0.beta1) rspec-core (2.99.1) - rspec-expectations (2.99.1) + rspec-expectations (2.99.2) diff-lcs (>= 1.1.3, < 2.0) - rspec-mocks (2.99.1) + rspec-mocks (2.99.2) rspec-rails (2.99.0) actionpack (>= 3.0) activemodel (>= 3.0) @@ -132,13 +132,13 @@ GEM rspec-mocks (~> 2.99.0) rubyntlm (0.4.0) rubyzip (1.1.6) - shoulda-matchers (2.6.1) + shoulda-matchers (2.6.2) activesupport (>= 3.0.0) simplecov (0.5.4) multi_json (~> 1.0.3) simplecov-html (~> 0.5.3) simplecov-html (0.5.3) - slop (3.5.0) + slop (3.6.0) sprockets (2.2.2) hike (~> 1.2) multi_json (~> 1.0) @@ -159,7 +159,7 @@ DEPENDENCIES factory_girl (>= 4.1.0) factory_girl_rails fivemat (= 1.2.1) - metasploit-credential (>= 0.7.10.pre.core.pre.search, < 0.8) + metasploit-credential (~> 0.7.14, < 0.8) metasploit-framework! metasploit_data_models (~> 0.19) network_interface (~> 0.0.1) From c65db18090911a062a6be2687ead5291e0178650 Mon Sep 17 00:00:00 2001 From: James Lee Date: Mon, 28 Jul 2014 09:19:09 -0500 Subject: [PATCH 12/17] Add rudimentary specs and fix some help wording --- lib/msf/ui/console/command_dispatcher/db.rb | 15 +++++---- spec/lib/msf/ui/command_dispatcher/db_spec.rb | 32 +++++++++++++++++++ 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index 5a9762d685..b4ba23e4b6 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -658,22 +658,23 @@ class Db print_line " creds [filter options] [address range]" print_line print_line "Usage - Adding credentials:" - print_line " creds add-ntlm [domain]" + print_line " creds add-ntlm [domain]" print_line " creds add-password [realm]" - print_line " creds add-ssh-key [realm]" + print_line " creds add-ssh-key " + #print_line "Where [realm type] can be one of:" + #Metasploit::Model::Realm::Key::SHORT_NAMES.each do |short, description| + # print_line " #{short} - #{description}" + #end print_line print_line "General options" print_line " -h,--help Show this help information" print_line - print_line "Filter options" + print_line "Filter options for listing" print_line " -P,--password List passwords that match this regex" print_line " -p,--port List creds with logins on services matching this port spec" print_line " -s List creds matching comma-separated service names" print_line " -u,--user List users that match this regex" - #print_line - #print_line "Add options" - #print_line " --realm-type One of: domain, db2, sid, pgdb. (Defaults to domain)" print_line print_line "Examples, listing:" @@ -930,6 +931,8 @@ class Db else [] end + #when 5 + # tabs = Metasploit::Model::Realm::Key::SHORT_NAMES.keys else tabs = [] end diff --git a/spec/lib/msf/ui/command_dispatcher/db_spec.rb b/spec/lib/msf/ui/command_dispatcher/db_spec.rb index 3498dcd25b..ddb2a230d8 100644 --- a/spec/lib/msf/ui/command_dispatcher/db_spec.rb +++ b/spec/lib/msf/ui/command_dispatcher/db_spec.rb @@ -11,6 +11,36 @@ describe Msf::Ui::Console::CommandDispatcher::Db do described_class.new(driver) end + describe "#cmd_creds" do + describe "add-password" do + let(:username) { "username" } + let(:password) { "password" } + context "when no core exists" do + it "should add a Core" do + expect { + subject.cmd_creds("add-password", username, password) + }.to change{ Metasploit::Credential::Core.count }.by 1 + end + end + context "when a core already exists" do + before(:each) do + priv = FactoryGirl.create(:metasploit_credential_password, data: password) + pub = FactoryGirl.create(:metasploit_credential_public, username: username) + core = FactoryGirl.create(:metasploit_credential_core, + private: priv, + public: pub, + realm: nil, + workspace: Mdm::Workspace.last) + end + it "should not add a Core" do + expect { + subject.cmd_creds("add-password", username, password) + }.to_not change{ Metasploit::Credential::Core.count } + end + end + end + end + describe "#cmd_workspace" do describe "-h" do it "should show a help message" do @@ -183,6 +213,7 @@ describe Msf::Ui::Console::CommandDispatcher::Db do end +=begin describe "#cmd_creds" do describe "-h" do it "should show a help message" do @@ -206,6 +237,7 @@ describe Msf::Ui::Console::CommandDispatcher::Db do end end end +=end describe "#cmd_db_import" do describe "-h" do From 49d0fc37c2984bdd1cb8e8dfae885e474bc8a731 Mon Sep 17 00:00:00 2001 From: James Lee Date: Mon, 28 Jul 2014 14:39:24 -0500 Subject: [PATCH 13/17] Add support for different realm_key --- lib/msf/ui/console/command_dispatcher/db.rb | 27 ++++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index b4ba23e4b6..8a66d7a72c 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -659,12 +659,12 @@ class Db print_line print_line "Usage - Adding credentials:" print_line " creds add-ntlm [domain]" - print_line " creds add-password [realm]" - print_line " creds add-ssh-key " - #print_line "Where [realm type] can be one of:" - #Metasploit::Model::Realm::Key::SHORT_NAMES.each do |short, description| - # print_line " #{short} - #{description}" - #end + print_line " creds add-password [realm] [realm-type]" + print_line " creds add-ssh-key [realm-type]" + print_line "Where [realm type] can be one of:" + Metasploit::Model::Realm::Key::SHORT_NAMES.each do |short, description| + print_line " #{short} - #{description}" + end print_line print_line "General options" @@ -693,19 +693,28 @@ class Db print_line end - def creds_add(private_type, username, password=nil, realm=nil) + def creds_add(private_type, username, password=nil, realm=nil, realm_type=nil) cred_data = { username: username, private_data: password, private_type: private_type, workspace_id: framework.db.workspace, origin_type: :import, - filename: "MSFCONSOLE" + filename: "msfconsole" } if realm + if realm_type + realm_key = Metasploit::Model::Realm::Key::SHORT_NAMES[realm_type] + if realm_key.nil? + valid = Metasploit::Model::Realm::Key::SHORT_NAMES.keys.map{|n|"'#{n}'"}.join(", ") + print_error("Invalid realm type: #{realm_type}. Valid values: #{valid}") + return + end + end + realm_key ||= Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN cred_data.merge!( realm_value: realm, - realm_key: Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN + realm_key: realm_key ) end From ef7f5fe967f01768e494525788c8984535e0dc47 Mon Sep 17 00:00:00 2001 From: James Lee Date: Mon, 28 Jul 2014 18:49:44 -0500 Subject: [PATCH 14/17] Make metasploit-model a direct dep Needed for all the scanners that use Metasploit::Model::Realm::Key constants. --- Gemfile.lock | 1 + lib/metasploit/framework.rb | 3 ++- metasploit-framework.gemspec | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 42ccda85a9..6e9779231a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,6 +5,7 @@ PATH activesupport (>= 3.0.0, < 4.0.0) bcrypt json + metasploit-model (~> 0.25) meterpreter_bins (= 0.0.6) msgpack nokogiri diff --git a/lib/metasploit/framework.rb b/lib/metasploit/framework.rb index 61d2f70d31..1555b00532 100644 --- a/lib/metasploit/framework.rb +++ b/lib/metasploit/framework.rb @@ -9,6 +9,7 @@ require 'active_support' require 'bcrypt' require 'json' require 'msgpack' +require 'metasploit/model' require 'nokogiri' require 'packetfu' # railties has not autorequire defined @@ -43,4 +44,4 @@ module Metasploit @root end end -end \ No newline at end of file +end diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index e0980416d6..8a28e477e6 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -55,6 +55,9 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency 'bcrypt' # Needed for some admin modules (scrutinizer_add_user.rb) spec.add_runtime_dependency 'json' + # Things that would normally be part of the database model, but which + # are needed when there's no database + spec.add_runtime_dependency 'metasploit-model', '~> 0.25' # Needed for Meterpreter on Windows, soon others. spec.add_runtime_dependency 'meterpreter_bins', '0.0.6' # Needed by msfgui and other rpc components From 1ee32b3b9875fb95e675c2dec1ad5307e2c60748 Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 29 Jul 2014 12:19:03 -0500 Subject: [PATCH 15/17] Bump metasploit-model so we can use Realm::Key map --- Gemfile.lock | 8 ++++---- metasploit-framework.gemspec | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 6e9779231a..7545a39821 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,7 +5,7 @@ PATH activesupport (>= 3.0.0, < 4.0.0) bcrypt json - metasploit-model (~> 0.25) + metasploit-model (~> 0.25.7) meterpreter_bins (= 0.0.6) msgpack nokogiri @@ -42,7 +42,7 @@ GEM i18n (~> 0.6, >= 0.6.4) multi_json (~> 1.0) arel (3.0.3) - arel-helpers (2.0.0) + arel-helpers (2.0.1) activerecord (>= 3.1.0, < 5) bcrypt (3.1.7) builder (3.0.4) @@ -61,14 +61,14 @@ GEM json (1.8.1) metasploit-concern (0.1.1) activesupport (~> 3.0, >= 3.0.0) - metasploit-credential (0.7.14) + metasploit-credential (0.7.16) metasploit-concern (~> 0.1.0) metasploit-model (>= 0.25.6) metasploit_data_models (~> 0.19) pg rubyntlm rubyzip (~> 1.1) - metasploit-model (0.25.6) + metasploit-model (0.25.7) activesupport metasploit_data_models (0.19.3) activerecord (>= 3.2.13, < 4.0.0) diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index 8a28e477e6..0eac8fca7e 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -57,7 +57,7 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency 'json' # Things that would normally be part of the database model, but which # are needed when there's no database - spec.add_runtime_dependency 'metasploit-model', '~> 0.25' + spec.add_runtime_dependency 'metasploit-model', '~> 0.25.7' # Needed for Meterpreter on Windows, soon others. spec.add_runtime_dependency 'meterpreter_bins', '0.0.6' # Needed by msfgui and other rpc components From ef59d88f64ae9d766826c7d0a5f7642180ffff2e Mon Sep 17 00:00:00 2001 From: James Lee Date: Wed, 30 Jul 2014 11:26:35 -0500 Subject: [PATCH 16/17] Fix spec failure due to workspace mismatch Also fixes intermittent failure from FactoryGirl picking a heinous Origin type. --- spec/lib/msf/ui/command_dispatcher/db_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/lib/msf/ui/command_dispatcher/db_spec.rb b/spec/lib/msf/ui/command_dispatcher/db_spec.rb index ddb2a230d8..25319a5456 100644 --- a/spec/lib/msf/ui/command_dispatcher/db_spec.rb +++ b/spec/lib/msf/ui/command_dispatcher/db_spec.rb @@ -27,10 +27,11 @@ describe Msf::Ui::Console::CommandDispatcher::Db do priv = FactoryGirl.create(:metasploit_credential_password, data: password) pub = FactoryGirl.create(:metasploit_credential_public, username: username) core = FactoryGirl.create(:metasploit_credential_core, + origin: FactoryGirl.create(:metasploit_credential_origin_import), private: priv, public: pub, realm: nil, - workspace: Mdm::Workspace.last) + workspace: framework.db.workspace) end it "should not add a Core" do expect { From 85b00eede6e642e2bfcc23c4dbc146f38bee67a5 Mon Sep 17 00:00:00 2001 From: James Lee Date: Wed, 30 Jul 2014 11:52:59 -0500 Subject: [PATCH 17/17] Add #present? checks --- lib/msf/ui/console/command_dispatcher/db.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index 8a66d7a72c..32f4c32ae1 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -693,6 +693,11 @@ class Db print_line end + # @param private_type [Symbol] See `Metasploit::Credential::Creation#create_credential` + # @param username [String] + # @param password [String] + # @param realm [String] + # @param realm_type [String] A key in `Metasploit::Model::Realm::Key::SHORT_NAMES` def creds_add(private_type, username, password=nil, realm=nil, realm_type=nil) cred_data = { username: username, @@ -702,8 +707,8 @@ class Db origin_type: :import, filename: "msfconsole" } - if realm - if realm_type + if realm.present? + if realm_type.present? realm_key = Metasploit::Model::Realm::Key::SHORT_NAMES[realm_type] if realm_key.nil? valid = Metasploit::Model::Realm::Key::SHORT_NAMES.keys.map{|n|"'#{n}'"}.join(", ")