Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

extend error message for timeouts to include more detail to user #18299

Merged
merged 1 commit into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 42 additions & 13 deletions lib/msf/ui/console/command_dispatcher/core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1576,7 +1576,7 @@ def cmd_sessions(*args)
rescue ::Rex::Post::Meterpreter::RequestError
print_error("Failed: #{$!.class} #{$!}")
rescue Rex::TimeoutError
print_error("Operation timed out")
print_error("Operation timed out. Timeout currently #{session.response_timeout} seconds, you can configure this with %grnsessions -c <cmd> --timeout <value>%clr")
end
elsif session.type == 'shell' || session.type == 'powershell'
output = session.shell_command(cmd)
Expand Down Expand Up @@ -1612,20 +1612,28 @@ def cmd_sessions(*args)

cmds.each do |cmd|
sessions.each do |session|
session = verify_session(session)
unless session.type == 'meterpreter'
print_error "Session ##{session.sid} is not a Meterpreter shell. Skipping..."
next
end
begin
session = verify_session(session)
unless session.type == 'meterpreter'
print_error "Session ##{session.sid} is not a Meterpreter shell. Skipping..."
next
end

next unless session
print_status("Running '#{cmd}' on #{session.type} session #{session.sid} (#{session.session_host})")
if session.respond_to?(:response_timeout)
last_known_timeout = session.response_timeout
session.response_timeout = response_timeout
end
next unless session
print_status("Running '#{cmd}' on #{session.type} session #{session.sid} (#{session.session_host})")
if session.respond_to?(:response_timeout)
last_known_timeout = session.response_timeout
session.response_timeout = response_timeout
session.on_run_command_error_proc = log_on_timeout_error("Send timed out. Timeout currently #{session.response_timeout} seconds, you can configure this with %grnsessions -C <cmd> --timeout <value>%clr")
end

output = session.run_cmd(cmd, driver.output)
output = session.run_cmd(cmd, driver.output)
ensure
if session.respond_to?(:response_timeout) && last_known_timeout
session.response_timeout = last_known_timeout
session.on_run_command_error_proc = nil
end
end
end
end
when 'kill'
Expand Down Expand Up @@ -1674,16 +1682,19 @@ def cmd_sessions(*args)
if session.respond_to?(:response_timeout)
last_known_timeout = session.response_timeout
session.response_timeout = response_timeout
session.on_run_command_error_proc = log_on_timeout_error("Send timed out. Timeout currently #{session.response_timeout} seconds, you can configure this with %grnsessions --interact <id> --timeout <value>%clr")
end
print_status("Starting interaction with #{session.name}...\n") unless quiet
begin
self.active_session = session

sid = session.interact(driver.input.dup, driver.output)
self.active_session = nil
driver.input.reset_tab_completion if driver.input.supports_readline
ensure
if session.respond_to?(:response_timeout) && last_known_timeout
session.response_timeout = last_known_timeout
session.on_run_command_error_proc = nil
end
end
else
Expand All @@ -1708,20 +1719,24 @@ def cmd_sessions(*args)
if session.respond_to?(:response_timeout)
last_known_timeout = session.response_timeout
session.response_timeout = response_timeout
session.on_run_command_error_proc = log_on_timeout_error("Send timed out. Timeout currently #{session.response_timeout} seconds, you can configure this with %grnsessions --timeout <value> --script <script> <id>%clr")
end
begin
print_status("Session #{sess_id} (#{session.session_host}):")
print_status("Running #{script} on #{session.type} session" +
" #{sess_id} (#{session.session_host})")
begin
session.init_ui(driver.input, driver.output)
session.execute_script(script, *extra)
rescue ::Exception => e
log_error("Error executing script or module: #{e.class} #{e}")
end
ensure
if session.respond_to?(:response_timeout) && last_known_timeout
session.response_timeout = last_known_timeout
session.on_run_command_error_proc = nil
end
session.reset_ui
end
else
print_error("Invalid session identifier: #{sess_id}")
Expand Down Expand Up @@ -2595,6 +2610,20 @@ def verify_session(session_id, quiet = false)
end
end

#
# Custom error code to handle timeout errors
#
# @param message [String] The message to be printed when a timeout error is hit
# @return [Proc] proc function that prints the specified error when the error types match
def log_on_timeout_error(message)
proc do |e|
next unless e.is_a?(Rex::TimeoutError) || e.is_a?(Timeout::Error)
elog(e)
print_error(message)
:handled
end
end

#
# Returns an array of lines at the provided line number plus any before and/or after lines requested
# from all_lines by supplying the +before+ and/or +after+ parameters which are always positive
Expand Down
27 changes: 16 additions & 11 deletions lib/rex/post/meterpreter/ui/console.rb
Original file line number Diff line number Diff line change
Expand Up @@ -100,17 +100,22 @@ def queue_cmd(cmd)
def run_command(dispatcher, method, arguments)
begin
super
rescue Timeout::Error
log_error("Operation timed out.")
rescue RequestError => info
log_error(info.to_s)
rescue Rex::InvalidDestination => e
log_error(e.message)
rescue ::Errno::EPIPE, ::OpenSSL::SSL::SSLError, ::IOError
self.client.kill
rescue ::Exception => e
log_error("Error running command #{method}: #{e.class} #{e}")
elog(e)
rescue Exception => e
is_error_handled = self.client.on_run_command_error_proc && self.client.on_run_command_error_proc.call(e) == :handled
return if is_error_handled
case e
when Rex::TimeoutError, Rex::InvalidDestination
log_error(e.message)
when Timeout::Error
log_error('Operation timed out.')
when RequestError
log_error(e.to_s)
when ::Errno::EPIPE, ::OpenSSL::SSL::SSLError, ::IOError
self.client.kill
when ::Exception
log_error("Error running command #{method}: #{e.class} #{e}")
elog(e)
end
end
end

Expand Down
6 changes: 6 additions & 0 deletions lib/rex/ui/interactive.rb
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,12 @@ def detach
attr_accessor :on_print_proc
attr_accessor :on_command_proc

#
# A function to be run when running a session command hits an error
#
# @return [Proc,nil] A function to be run when running a session command hits an error
attr_accessor :on_run_command_error_proc

protected

#
Expand Down
Loading