diff --git a/modules/auxiliary/admin/smb/psexec_command.rb b/modules/auxiliary/admin/smb/psexec_command.rb index 22f154d56b..b89f70c278 100644 --- a/modules/auxiliary/admin/smb/psexec_command.rb +++ b/modules/auxiliary/admin/smb/psexec_command.rb @@ -53,6 +53,9 @@ class Metasploit3 < Msf::Auxiliary register_advanced_options([ OptString.new('FILEPREFIX', [false, 'Add a custom prefix to the temporary files','']), + OptInt.new('DELAY', [true, 'Wait this many seconds before reading output and cleaning up', 1]), + OptInt.new('RETRY', [true, 'Retry this many times to check if the process is complete', 10]), + OptPath.new('LOGDIR', [false, 'File to log output', '']), ], self.class) deregister_options('RHOST') @@ -77,9 +80,21 @@ class Metasploit3 < Msf::Auxiliary print_error("#{peer} - Unable to authenticate with given credentials: #{autherror}") return end - if execute_command(text, bat) + res = execute_command(text, bat) + + for i in 0..(datastore['RETRY']) + sleep datastore['DELAY'] + # if the output file is still locked then the program is still likely running + if (exclusive_access(text)) + break + elsif (i == datastore['RETRY']) + print_error("Command seems to still be executing. Try increasing RETRY and DELAY") + end + end + if res get_output(text) end + cleanup_after(text, bat) disconnect end @@ -110,10 +125,47 @@ class Metasploit3 < Msf::Auxiliary print_status("#{peer} - Command finished with no output") return end - print_good("#{peer} - Command completed successfuly! Output:") - print_line("#{output}") + + # Define log filename + timestamp = ::Time.now.strftime('%Y%m%d:%H%M%S') + filename = "#{datastore['RHOSTS']}_#{timestamp}" + if (datastore['LOGDIR'].nil?) + log_file = ::File.join(log_dir,"#{filename}.txt") + else + log_file = ::File.join(datastore['LOGDIR'], "#{filename}.txt") + end + + print_good("#{peer} - Command completed successfuly!") + print_status("Logging output to #{log_file}.") + output = "# CMD: #{datastore['COMMAND']}" + output + + fd = ::File.new(log_file, 'w+') + fd.write(output) + fd.close() + + if datastore["VERBOSE"] + print_status("Output:") + print_line("#{output}") + end end + #check if our process is done using these files + def exclusive_access(*files) + simple.connect("\\\\#{@ip}\\#{@smbshare}") + files.each do |file| + begin + print_status("checking if the file is unlocked") + fd = smb_open(file, 'rwo') + fd.close + rescue Rex::Proto::SMB::Exceptions::ErrorCode => accesserror + print_status("#{peer} - Unable to get handle: #{accesserror}") + return false + end + end + return true + end + + # Removes files created during execution. def cleanup_after(*files) simple.connect("\\\\#{@ip}\\#{@smbshare}")