Skip to content

Commit c9a85f5

Browse files
author
Brent Cook
committed
add pkill command, rework to share filtering logic with ps
1 parent a1be63e commit c9a85f5

File tree

1 file changed

+123
-67
lines changed
  • lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi

1 file changed

+123
-67
lines changed

lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb

Lines changed: 123 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,13 @@ class Console::CommandDispatcher::Stdapi::Sys
6363
# Options for the 'ps' command.
6464
#
6565
@@ps_opts = Rex::Parser::Arguments.new(
66-
"-S" => [ true, "String to search for (converts to regex)" ],
67-
"-h" => [ false, "Help menu." ],
68-
"-A" => [ true, "Filters processes on architecture" ],
69-
"-s" => [ false, "Show only SYSTEM processes" ],
70-
"-c" => [ false, "Show only child processes of the current shell" ],
71-
"-U" => [ true, "Filters processes on the user using the supplied RegEx"])
66+
"-S" => [ true, "Filter on process name" ],
67+
"-U" => [ true, "Filter on user name" ],
68+
"-A" => [ true, "Filter on architecture" ],
69+
"-x" => [ false, "Filter for exact matches rather than regex" ],
70+
"-s" => [ false, "Filter only SYSTEM processes" ],
71+
"-c" => [ false, "Filter only child processes of the current shell" ],
72+
"-h" => [ false, "Help menu." ])
7273

7374
#
7475
# Options for the 'suspend' command.
@@ -92,6 +93,7 @@ def commands
9293
"getsid" => "Get the SID of the user that the server is running as",
9394
"getenv" => "Get one or more environment variable values",
9495
"kill" => "Terminate a process",
96+
"pkill" => "Terminate a process by name",
9597
"ps" => "List running processes",
9698
"reboot" => "Reboots the remote computer",
9799
"reg" => "Modify and interact with the remote registry",
@@ -113,6 +115,7 @@ def commands
113115
"getsid" => [ "stdapi_sys_config_getsid" ],
114116
"getenv" => [ "stdapi_sys_config_getenv" ],
115117
"kill" => [ "stdapi_sys_process_kill" ],
118+
"pkill" => [ "stdapi_sys_process_kill" ],
116119
"ps" => [ "stdapi_sys_process_get_processes" ],
117120
"reboot" => [ "stdapi_sys_power_exitwindows" ],
118121
"reg" => [
@@ -367,12 +370,37 @@ def cmd_kill(*args)
367370
end
368371

369372
#
370-
# help for the kill command
373+
# Kills one or more processes by name.
371374
#
372-
def cmd_kill_help
373-
print_line("Usage: kill [pid1 [pid2 [pid3 ...]]] [-s]")
374-
print_line("Terminate one or more processes.")
375-
print_line(" -s : Kills the pid associated with the current session.")
375+
def cmd_pkill(*args)
376+
if args.include?('-h')
377+
cmd_pkill_help
378+
return true
379+
end
380+
381+
all_processes = client.sys.process.get_processes
382+
processes = match_processes(all_processes, args)
383+
384+
if processes.length == 0
385+
print_line("No matching processes were found.")
386+
return true
387+
end
388+
389+
if processes.length == all_processes.length && !args.include?('-f')
390+
print_error("All processes will be killed, use '-f' to force.")
391+
return true
392+
end
393+
394+
pids = processes.collect { |p| p['pid'] }
395+
print_line("Killing: #{pids.join(', ')}")
396+
client.sys.process.kill(*(pids.map { |x| x }))
397+
true
398+
end
399+
400+
def cmd_pkill_help
401+
print_line("Usage: pkill [ options ] pattern")
402+
print_line("Terminate one or more processes by name.")
403+
print_line @@ps_opts.usage
376404
end
377405

378406
#
@@ -418,92 +446,120 @@ def validate_pids(pids, allow_pid_0 = false, allow_session_pid = false)
418446
valid_pids << pid
419447
end
420448
end
421-
return valid_pids
449+
valid_pids
422450
end
423451

424-
#
425-
# Lists running processes.
426-
#
427-
def cmd_ps(*args)
428-
if args.include?('-h')
429-
cmd_ps_help
430-
return true
431-
end
452+
def match_processes(processes, args)
432453

433-
# Init vars
434-
processes = client.sys.process.get_processes
435-
search_term = nil
454+
search_proc = nil
455+
search_user = nil
456+
exact_match = false
436457

437458
# Parse opts
438-
@@ps_opts.parse(args) { |opt, idx, val|
459+
@@ps_opts.parse(args) do |opt, idx, val|
439460
case opt
440-
when '-S'
441-
search_term = val
442-
if search_term.nil?
443-
print_error("Enter a search term")
444-
return true
461+
when '-S', nil
462+
if val.nil? || val.empty?
463+
print_error "Enter a process name"
464+
processes = []
465+
else
466+
search_proc = val
467+
end
468+
when "-U"
469+
if val.nil? || val.empty?
470+
print_line "Enter a process user"
471+
processes = []
472+
else
473+
search_user = val
445474
end
475+
when '-x'
476+
exact_match = true
446477
when "-A"
447-
print_line "Filtering on arch..."
448-
searched_procs = Rex::Post::Meterpreter::Extensions::Stdapi::Sys::ProcessList.new
449-
processes.each do |proc|
450-
next if proc['arch'].nil? or proc['arch'].empty?
451-
if val.nil? or val.empty?
452-
return false
478+
if val.nil? || val.empty?
479+
print_error "Enter an architecture"
480+
processes = []
481+
else
482+
print_line "Filtering on arch '#{val}"
483+
processes = processes.select do |p|
484+
p['arch'] == val
453485
end
454-
searched_procs << proc if proc["arch"] == val
455486
end
456-
processes = searched_procs
457487
when "-s"
458488
print_line "Filtering on SYSTEM processes..."
459-
searched_procs = Rex::Post::Meterpreter::Extensions::Stdapi::Sys::ProcessList.new
460-
processes.each do |proc|
461-
searched_procs << proc if proc["user"] == "NT AUTHORITY\\SYSTEM"
489+
processes = processes.select do |p|
490+
["NT AUTHORITY\\SYSTEM", "root"].include? p['user']
462491
end
463-
processes = searched_procs
464492
when "-c"
465493
print_line "Filtering on child processes of the current shell..."
466494
current_shell_pid = client.sys.process.getpid
467-
searched_procs = Rex::Post::Meterpreter::Extensions::Stdapi::Sys::ProcessList.new
468-
processes.each do |proc|
469-
searched_procs << proc if proc['ppid'] == current_shell_pid
495+
processes = processes.select do |p|
496+
p['ppid'] == current_shell_pid
470497
end
471-
processes = searched_procs
472-
when "-U"
473-
print_line "Filtering on user name..."
474-
searched_procs = Rex::Post::Meterpreter::Extensions::Stdapi::Sys::ProcessList.new
475-
processes.each do |proc|
476-
if val.nil? or val.empty?
477-
print_line "You must supply a search term!"
478-
return false
479-
end
480-
searched_procs << proc if proc["user"].match(/#{val}/)
498+
end
499+
end
500+
501+
unless search_proc.nil?
502+
print_line "Filtering on '#{search_proc}'"
503+
if exact_match
504+
processes = processes.select do |p|
505+
p['name'] == search_proc
506+
end
507+
else
508+
match = /#{search_proc}/
509+
processes = processes.select do |p|
510+
p['name'] =~ match
481511
end
482-
processes = searched_procs
483512
end
484-
}
513+
end
485514

486-
if (processes.length == 0)
487-
print_line("No running processes were found.")
488-
else
489-
tbl = processes.to_table('SearchTerm' => search_term)
490-
print_line
491-
print_line(tbl.to_s)
515+
unless search_user.nil?
516+
print_line "Filtering on user '#{search_user}'"
517+
if exact_match
518+
processes = processes.select do |p|
519+
p['user'] == search_user
520+
end
521+
else
522+
match = /#{search_user}/
523+
processes = processes.select do |p|
524+
p['user'] =~ match
525+
end
526+
end
492527
end
493-
return true
528+
529+
Rex::Post::Meterpreter::Extensions::Stdapi::Sys::ProcessList.new(processes)
530+
end
531+
532+
#
533+
# Lists running processes.
534+
#
535+
def cmd_ps(*args)
536+
if args.include?('-h')
537+
cmd_ps_help
538+
return true
539+
end
540+
541+
all_processes = client.sys.process.get_processes
542+
processes = match_processes(all_processes, args)
543+
544+
if processes.length == 0
545+
print_line("No matching processes were found.")
546+
return true
547+
end
548+
549+
tbl = processes.to_table
550+
print_line
551+
print_line(tbl.to_s)
552+
true
494553
end
495554

496555
def cmd_ps_help
497-
print_line "Usage: ps [ options ]"
556+
print_line "Usage: ps [ options ] pattern"
498557
print_line
499558
print_line "Use the command with no arguments to see all running processes."
500559
print_line "The following options can be used to filter those results:"
501-
502560
print_line @@ps_opts.usage
503561
end
504562

505-
506-
507563
#
508564
# Reboots the remote computer.
509565
#

0 commit comments

Comments
 (0)