Skip to content

Commit

Permalink
Add implementation of interactive_shell_read and `interactive_shell…
Browse files Browse the repository at this point in the history
…_write` RPC calls for Session API to support interacting with sessions of new types (DB and SMB sessions) via RPC.
  • Loading branch information
ekalinichev-r7 committed Mar 21, 2024
1 parent 80f64f5 commit e70078d
Showing 1 changed file with 53 additions and 0 deletions.
53 changes: 53 additions & 0 deletions lib/msf/core/rpc/v10/rpc_session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,59 @@ def rpc_shell_upgrade( sid, lhost, lport)
{ "result" => "success" }
end

# Writes to an interactive session (i.e. DB and SMB sessions). Note that you will to manually add a newline at the
# end of your input so the system will process it.
# You may want to use #rpc_interactive_shell_read to retrieve the output.
#
# @param [Integer] sid Session ID.
# @param [String] data The data to write.
#
# @return [Hash] A hash indicating the action was successful. It contains the following key:
# * 'result' [String] A message that says 'success'
#
# @example Here's how you would use this from the client:
# rpc.call('session.interactive_shell_write', 2, "DATA")
# => {"result"=>"success"}
def rpc_interactive_shell_write(sid, data)
# Session type is mandatory argument but `_valid_session` doesn't actually use it for interactive session types,
# and we don't know exact type of the session, so we just pass empty string
session = _valid_session(sid, '')

unless session.user_output.respond_to?(:dump_buffer)
session.init_ui(Rex::Ui::Text::Input::Buffer.new, Rex::Ui::Text::Output::Buffer.new)
end

if session.interacting
session.user_input.put(data + "\n")
else
framework.threads.spawn('InteractiveRunSingle', false, session) { |s| s.console.run_single(data) }
end
{ 'result' => 'success' }
end

# Reads the output from interactive session (such as a command output).
# This method supports "new" session types such as DB sessions and SMB session
#
# @param [Integer] sid Session ID.
# @raise [Msf::RPC::Exception] 500 Session ID is unknown.
#
# @return [Hash] It contains the following key:
# * 'data' [String] Data read.
#
# @example Here's how you would use this from the client:
# rpc.call('session.interactive_shell_read', 2)
def rpc_interactive_shell_read(sid)
# Session type is mandatory argument but `_valid_session` doesn't actually use it for interactive session types,
# and we don't know exact type of the session, so we just pass empty string
session = _valid_session(sid, '')

unless session.user_output.respond_to?(:dump_buffer)
session.init_ui(Rex::Ui::Text::Input::Buffer.new, Rex::Ui::Text::Output::Buffer.new)
end

data = session.user_output.dump_buffer
{ 'data' => data }
end

# Reads the output from a meterpreter session (such as a command output).
#
Expand Down

0 comments on commit e70078d

Please sign in to comment.