From fb475ca49c66cb782de96cb55b604db16affef6a Mon Sep 17 00:00:00 2001 From: RageLtMan Date: Sun, 15 Jan 2012 00:49:25 -0500 Subject: [PATCH 1/3] Search functionality for db dispatcher commands --- lib/msf/ui/console/command_dispatcher/db.rb | 68 ++++++++++++++++++--- 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index aa9ec40c3d..cfda6c2994 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -162,6 +162,7 @@ class Db delete_count = 0 host_ranges = [] + search_term = '' output = nil default_columns = ::Msf::DBManager::Host.column_names.sort @@ -197,6 +198,8 @@ class Db when '-R','--rhosts' set_rhosts = true rhosts = [] + when '-S', '--search' + search_term = args.shift when '-h','--help' print_line "Usage: hosts [ options ] [addr1 addr2 ...]" @@ -209,6 +212,7 @@ class Db print_line " -u,--up Only show hosts which are up" print_line " -o Send output to a file in csv format" print_line " -R,--rhosts Set RHOSTS from the results of the search" + print_line " -S,--search Search string to filter by" print_line print_line "Available columns: #{default_columns.join(", ")}" print_line @@ -234,7 +238,7 @@ class Db print_status("Time: #{host.created_at} Host: host=#{host.address}") if set_rhosts # only unique addresses - addr = (host.scope ? host.address + '%' + host.scope : host.address ) + addr = (host.scope ? host.address + '%' + host.scope : host.address ) rhosts << addr unless rhosts.include?(addr) end end @@ -252,9 +256,13 @@ class Db # Sentinal value meaning all host_ranges.push(nil) if host_ranges.empty? + search_term = '.' if search_term.empty? each_host_range_chunk(host_ranges) do |host_search| framework.db.hosts(framework.db.workspace, onlyup, host_search).each do |host| + next unless host.attribute_names.any? { + |a| host[a.to_sym].to_s.downcase.match(/#{search_term.downcase}/) + } columns = col_names.map do |n| # Deal with the special cases if virtual_columns.include?(n) @@ -271,7 +279,7 @@ class Db tbl << columns if set_rhosts - addr = (host.scope ? host.address + '%' + host.scope : host.address ) + addr = (host.scope ? host.address + '%' + host.scope : host.address ) rhosts << addr unless rhosts.include?(addr) end if mode == :delete @@ -316,6 +324,7 @@ class Db host_ranges = [] port_ranges = [] delete_count = 0 + search_term = '' # option parsing while (arg = args.shift) @@ -367,6 +376,8 @@ class Db when '-R','--rhosts' set_rhosts = true rhosts = [] + when '-S', '--search' + search_term = args.shift when '-h','--help' print_line @@ -382,6 +393,7 @@ class Db print_line " -u,--up Only show services which are up" print_line " -o Send output to a file in csv format" print_line " -R,--rhosts Set RHOSTS from the results of the search" + print_line " -S,--search Search string to filter by" print_line print_line "Available columns: #{default_columns.join(", ")}" print_line @@ -435,18 +447,25 @@ class Db # Sentinal value meaning all host_ranges.push(nil) if host_ranges.empty? ports = nil if ports.empty? + search_term = '.' if search_term.empty? each_host_range_chunk(host_ranges) do |host_search| framework.db.services(framework.db.workspace, onlyup, proto, host_search, ports, names).each do |service| host = service.host + next unless host.attribute_names.any? { + |a| host[a.to_sym].to_s.downcase.match(/#{search_term.downcase}/) + } or service.attribute_names.any? { + |a| service[a.to_sym].to_s.downcase.match(/#{search_term.downcase}/) + } + columns = [host.address] + col_names.map { |n| service[n].to_s || "" } tbl << columns if set_rhosts - addr = (host.scope ? host.address + '%' + host.scope : host.address ) + addr = (host.scope ? host.address + '%' + host.scope : host.address ) rhosts << addr unless rhosts.include?(addr) end - + if (mode == :delete) service.destroy delete_count += 1 @@ -479,6 +498,7 @@ class Db print_line " -h,--help Show this help information" print_line " -p,--port List vulns matching this port spec" print_line " -s List vulns matching these service names" + print_line " -S,--search Search string to filter by" print_line print_line "Examples:" print_line " vulns -p 1-65536 # only vulns with associated services" @@ -493,6 +513,7 @@ class Db host_ranges = [] port_ranges = [] svcs = [] + search_term = '' # Short-circuit help if args.delete "-h" @@ -521,6 +542,8 @@ class Db return end svcs = service.split(/[\s]*,[\s]*/) + when '-S', '--search' + search_term = args.shift else # Anything that wasn't an option is a host to search for unless (arg_host_range(arg, host_ranges)) @@ -533,10 +556,16 @@ class Db host_ranges.push(nil) if host_ranges.empty? ports = port_ranges.flatten.uniq svcs.flatten! + search_term = '.' if search_term.empty? each_host_range_chunk(host_ranges) do |host_search| framework.db.hosts(framework.db.workspace, false, host_search).each do |host| host.vulns.each do |vuln| + next unless vuln.attribute_names.any? { + |a| vuln[a.to_sym].to_s.downcase.match(/#{search_term.downcase}/) + } or vuln.host.attribute_names.any? { + |a| vuln.host[a.to_sym].to_s.downcase.match(/#{search_term.downcase}/) + } reflist = vuln.refs.map { |r| r.name } if(vuln.service) # Skip this one if the user specified a port and it @@ -570,6 +599,7 @@ class Db print_line " -u,--user Add a cred for this user (only with -a). Default: blank" print_line " -P,--password Add a cred with this password (only with -a). Default: blank" print_line " -R,--rhosts Set RHOSTS from the results of the search" + print_line " -S,--search Search string to filter by" print_line print_line "Examples:" print_line " creds # Default, returns all active credentials" @@ -597,6 +627,7 @@ class Db host_ranges = [] port_ranges = [] svcs = [] + search_term = '' user = nil @@ -649,6 +680,8 @@ class Db when "-R" set_rhosts = true rhosts = [] + when '-S', '--search' + search_term = args.shift when "-u","--user" user = args.shift if (!user) @@ -698,6 +731,7 @@ class Db # normalize ports = port_ranges.flatten.uniq svcs.flatten! + search_term = '.' if search_term.empty? tbl = Rex::Ui::Text::Table.new({ 'Header' => "Credentials", @@ -709,7 +743,9 @@ class Db framework.db.each_cred(framework.db.workspace) do |cred| # skip if it's inactive and user didn't ask for all next unless (cred.active or inactive_ok) - + next unless cred.attribute_names.any? { + |a| cred[a.to_sym].to_s.downcase.match(/#{search_term.downcase}/) + } # Also skip if the user is searching for something and this # one doesn't match includes = false @@ -738,7 +774,7 @@ class Db cred.destroy end if set_rhosts - addr = (cred.service.host.scope ? cred.service.host.address + '%' + cred.service.host.scope : cred.service.host.address ) + addr = (cred.service.host.scope ? cred.service.host.address + '%' + cred.service.host.scope : cred.service.host.address ) rhosts << addr unless rhosts.include?(addr) end creds_returned += 1 @@ -766,6 +802,7 @@ class Db print_line " -t Search for a list of types" print_line " -h,--help Show this help information" print_line " -R,--rhosts Set RHOSTS from the results of the search" + print_line " -S,--search Search string to filter by" print_line print_line "Examples:" print_line " notes --add -t apps -n 'winzip' 10.1.1.34 10.1.20.41" @@ -781,6 +818,7 @@ class Db set_rhosts = false host_ranges = [] + search_term = '' while (arg = args.shift) case arg @@ -804,6 +842,8 @@ class Db when '-R','--rhosts' set_rhosts = true rhosts = [] + when '-S', '--search' + search_term = args.shift when '-h','--help' cmd_notes_help return @@ -835,6 +875,7 @@ class Db end note_list = [] + search_term = '.' if search_term.empty? delete_count = 0 if host_ranges.empty? # No host specified - collect all notes note_list = framework.db.notes @@ -845,6 +886,10 @@ class Db end end end + note_list.keep_if {|n| n.attribute_names.any? { + |a| n[a.to_sym].to_s.downcase =~ /#{search_term.downcase}/ + } + } # Now display them note_list.each do |note| next if(types and types.index(note.ntype).nil?) @@ -853,7 +898,7 @@ class Db host = note.host msg << " host=#{note.host.address}" if set_rhosts - addr = (host.scope ? host.address + '%' + host.scope : host.address ) + addr = (host.scope ? host.address + '%' + host.scope : host.address ) rhosts << addr unless rhosts.include?(addr) end end @@ -881,6 +926,7 @@ class Db print_line print_line " -t Search for a list of types" print_line " -h,--help Show this help information" + print_line " -S,--search Search string to filter by" print_line end @@ -890,6 +936,7 @@ class Db host_ranges = [] types = nil delete_count = 0 + search_term = '' while (arg = args.shift) case arg @@ -902,6 +949,8 @@ class Db return end types = typelist.strip().split(",") + when '-S', '--search' + search_term = args.shift when '-h','--help' cmd_loot_help return @@ -925,6 +974,11 @@ class Db framework.db.hosts(framework.db.workspace, false, host_search).each do |host| host.loots.each do |loot| next if(types and types.index(loot.ltype).nil?) + next unless loot.attribute_names.any? { + |a| loot[a.to_sym].to_s.downcase.match(/#{search_term.downcase}/) + } or loot.host.attribute_names.any? { + |a| loot.host[a.to_sym].to_s.downcase.match(/#{search_term.downcase}/) + } row = [] row.push( (loot.host ? loot.host.address : "") ) if (loot.service) From a957c45dafaa6b8ab67c49c08793289c812a96d5 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Mon, 5 Mar 2012 13:21:05 -0600 Subject: [PATCH 2/3] Tidies up sempervictus's search patch Affects the console's db commands of hosts, services, vulns, creds, notes, loot Skips searching entirely unless a search term is provided, and explicitly casts the term as a Regexp object from the outset. Avoids using Object#to_sym in preference of Object#intern (safer in nearly all cases) Temporarily disables functionality on notes since Array#keep_if isn't available prior to Ruby 1.9.2 --- lib/msf/ui/console/command_dispatcher/db.rb | 83 ++++++++++----------- 1 file changed, 40 insertions(+), 43 deletions(-) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index cfda6c2994..691d51a40b 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -162,7 +162,7 @@ class Db delete_count = 0 host_ranges = [] - search_term = '' + search_term = nil output = nil default_columns = ::Msf::DBManager::Host.column_names.sort @@ -199,7 +199,7 @@ class Db set_rhosts = true rhosts = [] when '-S', '--search' - search_term = args.shift + search_term = /#{args.shift}/nmi when '-h','--help' print_line "Usage: hosts [ options ] [addr1 addr2 ...]" @@ -256,13 +256,12 @@ class Db # Sentinal value meaning all host_ranges.push(nil) if host_ranges.empty? - search_term = '.' if search_term.empty? each_host_range_chunk(host_ranges) do |host_search| framework.db.hosts(framework.db.workspace, onlyup, host_search).each do |host| - next unless host.attribute_names.any? { - |a| host[a.to_sym].to_s.downcase.match(/#{search_term.downcase}/) - } + if search_term + next unless host.attribute_names.any? { |a| host[a.intern].to_s.match(search_term) } + end columns = col_names.map do |n| # Deal with the special cases if virtual_columns.include?(n) @@ -324,7 +323,7 @@ class Db host_ranges = [] port_ranges = [] delete_count = 0 - search_term = '' + search_term = nil # option parsing while (arg = args.shift) @@ -377,7 +376,7 @@ class Db set_rhosts = true rhosts = [] when '-S', '--search' - search_term = args.shift + search_term = /#{args.shift}/nmi when '-h','--help' print_line @@ -447,17 +446,17 @@ class Db # Sentinal value meaning all host_ranges.push(nil) if host_ranges.empty? ports = nil if ports.empty? - search_term = '.' if search_term.empty? each_host_range_chunk(host_ranges) do |host_search| framework.db.services(framework.db.workspace, onlyup, proto, host_search, ports, names).each do |service| host = service.host - next unless host.attribute_names.any? { - |a| host[a.to_sym].to_s.downcase.match(/#{search_term.downcase}/) - } or service.attribute_names.any? { - |a| service[a.to_sym].to_s.downcase.match(/#{search_term.downcase}/) - } + if search_term + next unless( + host.attribute_names.any? { |a| host[a.intern].to_s.match(search_term)} or + service.attribute_names.any? { |a| service[a.intern].to_s.match(search_term)} + ) + end columns = [host.address] + col_names.map { |n| service[n].to_s || "" } tbl << columns @@ -513,7 +512,7 @@ class Db host_ranges = [] port_ranges = [] svcs = [] - search_term = '' + search_term = nil # Short-circuit help if args.delete "-h" @@ -543,7 +542,7 @@ class Db end svcs = service.split(/[\s]*,[\s]*/) when '-S', '--search' - search_term = args.shift + search_term = /#{args.shift}/nmi else # Anything that wasn't an option is a host to search for unless (arg_host_range(arg, host_ranges)) @@ -556,16 +555,16 @@ class Db host_ranges.push(nil) if host_ranges.empty? ports = port_ranges.flatten.uniq svcs.flatten! - search_term = '.' if search_term.empty? each_host_range_chunk(host_ranges) do |host_search| framework.db.hosts(framework.db.workspace, false, host_search).each do |host| host.vulns.each do |vuln| - next unless vuln.attribute_names.any? { - |a| vuln[a.to_sym].to_s.downcase.match(/#{search_term.downcase}/) - } or vuln.host.attribute_names.any? { - |a| vuln.host[a.to_sym].to_s.downcase.match(/#{search_term.downcase}/) - } + if search_term + next unless( + vuln.host.attribute_names.any? { |a| vuln.host[a.intern].to_s.match(search_term) } or + vuln.attribute_names.any? { |a| vuln[a.intern].to_s.match(search_term) } + ) + end reflist = vuln.refs.map { |r| r.name } if(vuln.service) # Skip this one if the user specified a port and it @@ -627,7 +626,7 @@ class Db host_ranges = [] port_ranges = [] svcs = [] - search_term = '' + search_term = nil user = nil @@ -681,7 +680,7 @@ class Db set_rhosts = true rhosts = [] when '-S', '--search' - search_term = args.shift + search_term = /#{args.shift}/nmi when "-u","--user" user = args.shift if (!user) @@ -731,7 +730,6 @@ class Db # normalize ports = port_ranges.flatten.uniq svcs.flatten! - search_term = '.' if search_term.empty? tbl = Rex::Ui::Text::Table.new({ 'Header' => "Credentials", @@ -743,9 +741,9 @@ class Db framework.db.each_cred(framework.db.workspace) do |cred| # skip if it's inactive and user didn't ask for all next unless (cred.active or inactive_ok) - next unless cred.attribute_names.any? { - |a| cred[a.to_sym].to_s.downcase.match(/#{search_term.downcase}/) - } + if search_term + next unless cred.attribute_names.any? { |a| cred[a.intern].to_s.match(search_term) } + end # Also skip if the user is searching for something and this # one doesn't match includes = false @@ -818,7 +816,7 @@ class Db set_rhosts = false host_ranges = [] - search_term = '' + search_term = nil while (arg = args.shift) case arg @@ -843,7 +841,7 @@ class Db set_rhosts = true rhosts = [] when '-S', '--search' - search_term = args.shift + search_term = /#{args.shift}/nmi when '-h','--help' cmd_notes_help return @@ -875,10 +873,9 @@ class Db end note_list = [] - search_term = '.' if search_term.empty? delete_count = 0 if host_ranges.empty? # No host specified - collect all notes - note_list = framework.db.notes + note_list = framework.db.notes.dup else # Collect notes of specified hosts each_host_range_chunk(host_ranges) do |host_search| framework.db.hosts(framework.db.workspace, false, host_search).each do |host| @@ -886,10 +883,9 @@ class Db end end end - note_list.keep_if {|n| n.attribute_names.any? { - |a| n[a.to_sym].to_s.downcase =~ /#{search_term.downcase}/ - } - } + if search_term + # TODO: Actually select notes based on a criteria. Can't use keep_if since that's a 1.9.2 thing. + end # Now display them note_list.each do |note| next if(types and types.index(note.ntype).nil?) @@ -936,7 +932,7 @@ class Db host_ranges = [] types = nil delete_count = 0 - search_term = '' + search_term = nil while (arg = args.shift) case arg @@ -950,7 +946,7 @@ class Db end types = typelist.strip().split(",") when '-S', '--search' - search_term = args.shift + search_term = /#{args.shift}/nmi when '-h','--help' cmd_loot_help return @@ -974,11 +970,12 @@ class Db framework.db.hosts(framework.db.workspace, false, host_search).each do |host| host.loots.each do |loot| next if(types and types.index(loot.ltype).nil?) - next unless loot.attribute_names.any? { - |a| loot[a.to_sym].to_s.downcase.match(/#{search_term.downcase}/) - } or loot.host.attribute_names.any? { - |a| loot.host[a.to_sym].to_s.downcase.match(/#{search_term.downcase}/) - } + if search_term + next unless( + loot.attribute_names.any? { |a| loot[a.intern].to_s.match(search_term) } or + loot.host.attribute_names.any? { |a| loot.host[a.intern].to_s.match(search_term) } + ) + end row = [] row.push( (loot.host ? loot.host.address : "") ) if (loot.service) From 85d1b77ed3625266b86ded1d614223063fdd0fc1 Mon Sep 17 00:00:00 2001 From: Tod Beardsley Date: Mon, 5 Mar 2012 13:37:53 -0600 Subject: [PATCH 3/3] Fix up notes search implementation Uses delete_if and a negative assertion, rather than the (much nicer but unavailable) keep_if method. --- lib/msf/ui/console/command_dispatcher/db.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/msf/ui/console/command_dispatcher/db.rb b/lib/msf/ui/console/command_dispatcher/db.rb index 691d51a40b..ca3142e190 100644 --- a/lib/msf/ui/console/command_dispatcher/db.rb +++ b/lib/msf/ui/console/command_dispatcher/db.rb @@ -884,7 +884,9 @@ class Db end end if search_term - # TODO: Actually select notes based on a criteria. Can't use keep_if since that's a 1.9.2 thing. + note_list.delete_if do |n| + !!n.attribute_names.any? { |a| n[a.intern].to_s.match(search_term) } + end end # Now display them note_list.each do |note|