Skip to content

Commit 809bc52

Browse files
committed
Land rapid7#4982, tagging for msfconsole
2 parents fe3f9c7 + 0e1b9f9 commit 809bc52

File tree

2 files changed

+108
-15
lines changed
  • lib/msf/ui/console/command_dispatcher
  • spec/lib/msf/ui/console/command_dispatcher

2 files changed

+108
-15
lines changed

lib/msf/ui/console/command_dispatcher/db.rb

Lines changed: 106 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,11 @@ def cmd_hosts_help
220220
end
221221

222222
def change_host_info(rws, data)
223+
if rws == [nil]
224+
print_error("In order to change the host info, you must provide a range of hosts")
225+
return
226+
end
227+
223228
rws.each do |rw|
224229
rw.each do |ip|
225230
id = framework.db.get_host(:address => ip).id
@@ -230,6 +235,11 @@ def change_host_info(rws, data)
230235
end
231236

232237
def change_host_name(rws, data)
238+
if rws == [nil]
239+
print_error("In order to change the host name, you must provide a range of hosts")
240+
return
241+
end
242+
233243
rws.each do |rw|
234244
rw.each do |ip|
235245
id = framework.db.get_host(:address => ip).id
@@ -240,6 +250,11 @@ def change_host_name(rws, data)
240250
end
241251

242252
def change_host_comment(rws, data)
253+
if rws == [nil]
254+
print_error("In order to change the comment, you must provide a range of hosts")
255+
return
256+
end
257+
243258
rws.each do |rw|
244259
rw.each do |ip|
245260
id = framework.db.get_host(:address => ip).id
@@ -249,12 +264,59 @@ def change_host_comment(rws, data)
249264
end
250265
end
251266

267+
def add_host_tag(rws, tag_name)
268+
if rws == [nil]
269+
print_error("In order to add a tag, you must provide a range of hosts")
270+
return
271+
end
272+
273+
rws.each do |rw|
274+
rw.each do |ip|
275+
wspace = framework.db.workspace
276+
host = framework.db.get_host(:workspace => wspace, :address => ip)
277+
if host
278+
possible_tags = Mdm::Tag.includes(:hosts).where("hosts.workspace_id = ? and hosts.address = ? and tags.name = ?", wspace.id, ip, tag_name).order("tags.id DESC").limit(1)
279+
tag = (possible_tags.blank? ? Mdm::Tag.new : possible_tags.first)
280+
tag.name = tag_name
281+
tag.hosts = [host]
282+
tag.save! if tag.changed?
283+
end
284+
end
285+
end
286+
end
287+
288+
def delete_host_tag(rws, tag_name)
289+
wspace = framework.db.workspace
290+
tag_ids = []
291+
if rws == [nil]
292+
found_tags = Mdm::Tag.includes(:hosts).where("hosts.workspace_id = ? and tags.name = ?", wspace.id, tag_name)
293+
found_tags.each do |t|
294+
tag_ids << t.id
295+
end
296+
else
297+
rws.each do |rw|
298+
rw.each do |ip|
299+
found_tags = Mdm::Tag.includes(:hosts).where("hosts.workspace_id = ? and hosts.address = ? and tags.name = ?", wspace.id, ip, tag_name)
300+
found_tags.each do |t|
301+
tag_ids << t.id
302+
end
303+
end
304+
end
305+
end
306+
307+
tag_ids.each do |id|
308+
tag = Mdm::Tag.find_by_id(id)
309+
tag.hosts.delete
310+
tag.destroy
311+
end
312+
end
313+
252314
def cmd_hosts(*args)
253315
return unless active?
254316
::ActiveRecord::Base.connection_pool.with_connection {
255317
onlyup = false
256318
set_rhosts = false
257-
mode = :search
319+
mode = []
258320
delete_count = 0
259321

260322
rhosts = []
@@ -263,17 +325,18 @@ def cmd_hosts(*args)
263325

264326
output = nil
265327
default_columns = ::Mdm::Host.column_names.sort
266-
virtual_columns = [ 'svcs', 'vulns', 'workspace' ]
328+
default_columns << 'tags' # Special case
329+
virtual_columns = [ 'svcs', 'vulns', 'workspace', 'tags' ]
267330

268331
col_search = [ 'address', 'mac', 'name', 'os_name', 'os_flavor', 'os_sp', 'purpose', 'info', 'comments']
269332

270333
default_columns.delete_if {|v| (v[-2,2] == "id")}
271334
while (arg = args.shift)
272335
case arg
273336
when '-a','--add'
274-
mode = :add
337+
mode << :add
275338
when '-d','--delete'
276-
mode = :delete
339+
mode << :delete
277340
when '-c'
278341
list = args.shift
279342
if(!list)
@@ -297,14 +360,17 @@ def cmd_hosts(*args)
297360
when '-S', '--search'
298361
search_term = /#{args.shift}/nmi
299362
when '-i', '--info'
300-
mode = :new_info
363+
mode << :new_info
301364
info_data = args.shift
302365
when '-n', '--name'
303-
mode = :new_name
366+
mode << :new_name
304367
name_data = args.shift
305368
when '-m', '--comment'
306-
mode = :new_comment
369+
mode << :new_comment
307370
comment_data = args.shift
371+
when '-t', '--tag'
372+
mode << :tag
373+
tag_name = args.shift
308374
when '-h','--help'
309375
print_line "Usage: hosts [ options ] [addr1 addr2 ...]"
310376
print_line
@@ -320,6 +386,7 @@ def cmd_hosts(*args)
320386
print_line " -i,--info Change the info of a host"
321387
print_line " -n,--name Change the name of a host"
322388
print_line " -m,--comment Change the comment of a host"
389+
print_line " -t,--tag Add or specify a tag to a range of hosts"
323390
print_line
324391
print_line "Available columns: #{default_columns.join(", ")}"
325392
print_line
@@ -338,7 +405,9 @@ def cmd_hosts(*args)
338405
col_names = default_columns + virtual_columns
339406
end
340407

341-
if mode == :add
408+
mode << :search if mode.empty?
409+
410+
if mode == [:add]
342411
host_ranges.each do |range|
343412
range.each do |address|
344413
host = framework.db.find_or_create_host(:host => address)
@@ -358,30 +427,53 @@ def cmd_hosts(*args)
358427
# Sentinal value meaning all
359428
host_ranges.push(nil) if host_ranges.empty?
360429

361-
case mode
362-
when :new_info
430+
case
431+
when mode == [:new_info]
363432
change_host_info(host_ranges, info_data)
364433
return
365-
when :new_name
434+
when mode == [:new_name]
366435
change_host_name(host_ranges, name_data)
367436
return
368-
when :new_comment
437+
when mode == [:new_comment]
369438
change_host_comment(host_ranges, comment_data)
370439
return
440+
when mode == [:tag]
441+
begin
442+
add_host_tag(host_ranges, tag_name)
443+
rescue ::Exception => e
444+
if e.message.include?('Validation failed')
445+
print_error(e.message)
446+
else
447+
raise e
448+
end
449+
end
450+
return
451+
when mode.include?(:tag) && mode.include?(:delete)
452+
delete_host_tag(host_ranges, tag_name)
453+
return
371454
end
372455

373456
each_host_range_chunk(host_ranges) do |host_search|
374457
framework.db.hosts(framework.db.workspace, onlyup, host_search).each do |host|
375458
if search_term
376-
next unless host.attribute_names.any? { |a| host[a.intern].to_s.match(search_term) }
459+
next unless (
460+
host.attribute_names.any? { |a| host[a.intern].to_s.match(search_term) } ||
461+
!Mdm::Tag.includes(:hosts).where("hosts.workspace_id = ? and hosts.address = ? and tags.name = ?", framework.db.workspace.id, host.address, search_term.source).order("tags.id DESC").empty?
462+
)
377463
end
464+
378465
columns = col_names.map do |n|
379466
# Deal with the special cases
380467
if virtual_columns.include?(n)
381468
case n
382469
when "svcs"; host.services.length
383470
when "vulns"; host.vulns.length
384471
when "workspace"; host.workspace.name
472+
when "tags"
473+
found_tags = Mdm::Tag.includes(:hosts).where("hosts.workspace_id = ? and hosts.address = ?", framework.db.workspace.id, host.address).order("tags.id DESC")
474+
tag_names = []
475+
found_tags.each { |t| tag_names << t.name }
476+
found_tags * ", "
385477
end
386478
# Otherwise, it's just an attribute
387479
else
@@ -394,7 +486,7 @@ def cmd_hosts(*args)
394486
addr = (host.scope ? host.address + '%' + host.scope : host.address )
395487
rhosts << addr
396488
end
397-
if mode == :delete
489+
if mode == [:delete]
398490
host.destroy
399491
delete_count += 1
400492
end

spec/lib/msf/ui/console/command_dispatcher/db_spec.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,8 @@
394394
" -i,--info Change the info of a host",
395395
" -n,--name Change the name of a host",
396396
" -m,--comment Change the comment of a host",
397-
"Available columns: address, arch, comm, comments, created_at, cred_count, detected_arch, exploit_attempt_count, host_detail_count, info, mac, name, note_count, os_flavor, os_lang, os_name, os_sp, purpose, scope, service_count, state, updated_at, virtual_host, vuln_count"
397+
" -t,--tag Add or specify a tag to a range of hosts",
398+
"Available columns: address, arch, comm, comments, created_at, cred_count, detected_arch, exploit_attempt_count, host_detail_count, info, mac, name, note_count, os_flavor, os_lang, os_name, os_sp, purpose, scope, service_count, state, updated_at, virtual_host, vuln_count, tags"
398399
]
399400
end
400401
end

0 commit comments

Comments
 (0)