@@ -82,7 +82,7 @@ def commands
82
82
"shell" => "Drop into a system command shell" ,
83
83
"shutdown" => "Shuts down the remote computer" ,
84
84
"steal_token" => "Attempts to steal an impersonation token from the target process" ,
85
- "suspend" => "Suspends or resumes a list of processes"
85
+ "suspend" => "Suspends or resumes a list of processes" ,
86
86
"sysinfo" => "Gets information about the remote system, such as OS" ,
87
87
}
88
88
reqs = {
@@ -282,17 +282,17 @@ def cmd_kill(*args)
282
282
end
283
283
284
284
# validate all the proposed pids first so we can bail if one is bogus
285
- args . each do | arg |
286
- if not is_valid_pid? ( arg )
287
- print_error ( " #{ arg } is not a valid pid" )
288
- cmd_kill_help
289
- return false
290
- end
285
+ clean_pids = validate_pids ( args )
286
+ args . uniq!
287
+ diff = args - clean_pids . map { | e | e . to_s }
288
+ if not diff . empty? # then we had an invalid pid
289
+ print_error ( "The following pids are not valid: #{ diff . join ( ", " ) . to_s } , quitting" )
290
+ return false
291
291
end
292
292
293
293
# kill kill kill
294
- print_line ( "Killing: #{ args . join ( ", " ) } " )
295
- client . sys . process . kill ( *( args . map { |x | x . to_i } ) )
294
+ print_line ( "Killing: #{ clean_pids . join ( ", " ) . to_s } " )
295
+ client . sys . process . kill ( *( clean_pids . map { |x | x } ) )
296
296
return true
297
297
end
298
298
@@ -304,15 +304,56 @@ def cmd_kill_help
304
304
end
305
305
306
306
#
307
- # Checks if +pid+ is a valid looking pid
308
- #
309
- def is_valid_pid? ( pid )
310
- # in lieu of checking server side for pid validity at the moment, we just sanity check here
311
- pid . strip!
312
- return false if pid . strip =~ /^-/ # invalid if it looks "negative"
313
- return true if pid == "0" # allow them to kill pid 0, otherwise false
314
- # cuz everything returned from .to_i that's not an int returns 0, we depend on the statement above
315
- return true if pid . to_i > 0
307
+ # validates an array of pids against the running processes on target host
308
+ # behavior can be controlled to allow/deny proces 0 and the session's process
309
+ # the pids:
310
+ # - are converted to integers
311
+ # - have had pid 0 removed unless allow_pid_0
312
+ # - have had current session pid removed unless allow_session_pid (to protect the session)
313
+ # - have redundant entries removed
314
+ #
315
+ # @param pids [Array<String>] The pids to validate
316
+ # @param allow_pid_0 [Boolean] whether to consider a pid of 0 as valid
317
+ # @param allow_session_pid [Boolean] whether to consider a pid = the current session pid as valid
318
+ # @return [Array] Returns an array of valid pids
319
+
320
+ def validate_pids ( arr_pids , allow_pid_0 = false , allow_session_pid = false )
321
+
322
+ return [ ] if ( arr_pids . class != Array or arr_pids . empty? )
323
+ pids = arr_pids . dup
324
+ clean_pids = [ ]
325
+ # to minimize network traffic, we only get host processes once
326
+ host_processes = client . sys . process . get_processes
327
+ if host_processes . length < 1
328
+ print_error "No running processes found on the target host."
329
+ return [ ]
330
+ end
331
+
332
+ # get the current session pid so we don't suspend it later
333
+ mypid = client . sys . process . getpid . to_i
334
+
335
+ # we convert to integers here separately because we want to uniq this array first so we
336
+ # can avoid redundant lookups later
337
+ pids . each_with_index do |pid , idx |
338
+ next if pid . nil?
339
+ pids [ idx ] = pid . to_i
340
+ end
341
+ # uniq'ify
342
+ pids . uniq!
343
+ # now we look up the pids & remove bad stuff if nec
344
+ pids . delete_if do |p |
345
+ ( ( p == 0 and not allow_pid_0 ) or ( p == mypid and not allow_session_pid ) )
346
+ end
347
+ pids . each do |pid |
348
+ # find the process with this pid
349
+ theprocess = host_processes . select { |x | x [ "pid" ] == pid } . first
350
+ if ( theprocess . nil? )
351
+ next
352
+ else
353
+ clean_pids << pid
354
+ end
355
+ end
356
+ return clean_pids
316
357
end
317
358
318
359
#
@@ -715,26 +756,28 @@ def cmd_suspend(*args)
715
756
continue = args . delete ( "-c" ) || false
716
757
resume = args . delete ( "-r" ) || false
717
758
718
- # TODO add -u/-r to unsuspend/resume and -c continue
719
759
# validate all the proposed pids first so we can bail if one is bogus
720
- args . each do |arg |
721
- if not is_valid_pid? ( arg )
722
- print_error ( "#{ arg } is not a valid pid" )
723
- cmd_suspend_help
760
+ clean_pids = validate_pids ( args )
761
+ args . uniq!
762
+ diff = args - clean_pids . map { |e | e . to_s }
763
+ if not diff . empty? # then we had an invalid pid
764
+ print_error ( "The following pids are not valid:#{ diff . join ( ", " ) . to_s } " )
765
+ if continue
766
+ print_status ( "Continuing. Invalid args have been removed from the list." )
767
+ else
768
+ print_error ( "Quitting. Use -c to continue using only the valid pids." )
724
769
return false
725
770
end
726
771
end
727
772
728
- # suspend
729
- print_line ( "Suspending: #{ args . join ( ", " ) } " )
730
773
#client.sys.process.kill(*(args.map { |x| x.to_i }))
731
774
targetprocess = nil
732
775
if resume
776
+ print_status ( "Resuming: #{ clean_pids . join ( ", " ) . to_s } " )
733
777
begin
734
- pids . each do |pid |
778
+ clean_pids . each do |pid |
735
779
print_status ( "Targeting process with PID #{ pid } ..." )
736
780
targetprocess = client . sys . process . open ( pid , PROCESS_ALL_ACCESS )
737
- vprint_status "Resuming threads"
738
781
targetprocess . thread . each_thread do |x |
739
782
targetprocess . thread . open ( x ) . resume
740
783
end
@@ -747,12 +790,12 @@ def cmd_suspend(*args)
747
790
targetprocess . close if targetprocess
748
791
return false unless continue
749
792
end
750
- else
793
+ else # suspend
794
+ print_status ( "Suspending: #{ clean_pids . join ( ", " ) . to_s } " )
751
795
begin
752
- pids . each do |pid |
796
+ clean_pids . each do |pid |
753
797
print_status ( "Targeting process with PID #{ pid } ..." )
754
798
targetprocess = client . sys . process . open ( pid , PROCESS_ALL_ACCESS )
755
- vprint_status "Suspending threads"
756
799
targetprocess . thread . each_thread do |x |
757
800
targetprocess . thread . open ( x ) . suspend
758
801
end
@@ -774,7 +817,7 @@ def cmd_suspend(*args)
774
817
#
775
818
def cmd_suspend_help
776
819
print_line ( "Usage: suspend [options] pid1 pid2 pid3 ...\n \n Suspend one or more processes." )
777
- print @@connect_opts . usage
820
+ print @@suspend_opts . usage
778
821
end
779
822
780
823
end
0 commit comments