CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/rex/post/meterpreter/ui/console.rb
Views: 11789
1
# -*- coding: binary -*-
2
require 'rex/post/meterpreter'
3
4
module Rex
5
module Post
6
module Meterpreter
7
module Ui
8
9
###
10
#
11
# This class provides a shell driven interface to the meterpreter client API.
12
#
13
###
14
class Console
15
16
include Rex::Ui::Text::DispatcherShell
17
18
# Dispatchers
19
require 'rex/post/meterpreter/ui/console/interactive_channel'
20
require 'rex/post/meterpreter/ui/console/command_dispatcher'
21
require 'rex/post/meterpreter/ui/console/command_dispatcher/core'
22
23
#
24
# Initialize the meterpreter console.
25
#
26
def initialize(client)
27
if (Rex::Compat.is_windows())
28
super("meterpreter")
29
else
30
super("%undmeterpreter%clr", '>', Msf::Config.meterpreter_history, nil, :meterpreter)
31
end
32
33
# The meterpreter client context
34
self.client = client
35
36
# Queued commands array
37
self.commands = []
38
39
# Point the input/output handles elsewhere
40
reset_ui
41
42
enstack_dispatcher(Console::CommandDispatcher::Core)
43
44
# Set up logging to whatever logsink 'core' is using
45
if ! $dispatcher['meterpreter']
46
$dispatcher['meterpreter'] = $dispatcher['core']
47
end
48
end
49
50
#
51
# Called when someone wants to interact with the meterpreter client. It's
52
# assumed that init_ui has been called prior.
53
#
54
def interact(&block)
55
# Run queued commands
56
commands.delete_if { |ent|
57
run_single(ent)
58
true
59
}
60
61
# Run the interactive loop
62
run { |line|
63
# Run the command
64
run_single(line)
65
66
# If a block was supplied, call it, otherwise return false
67
if (block)
68
block.call
69
else
70
false
71
end
72
}
73
end
74
75
#
76
# Interacts with the supplied channel.
77
#
78
def interact_with_channel(channel, raw: false)
79
channel.extend(InteractiveChannel) unless (channel.kind_of?(InteractiveChannel) == true)
80
channel.on_command_proc = self.on_command_proc if self.on_command_proc
81
channel.on_print_proc = self.on_print_proc if self.on_print_proc
82
channel.on_log_proc = method(:log_output) if self.respond_to?(:log_output, true)
83
channel.raw = raw
84
85
channel.interact(input, output)
86
channel.reset_ui
87
end
88
89
#
90
# Queues a command to be run when the interactive loop is entered.
91
#
92
def queue_cmd(cmd)
93
self.commands << cmd
94
end
95
96
#
97
# Runs the specified command wrapper in something to catch meterpreter
98
# exceptions.
99
#
100
def run_command(dispatcher, method, arguments)
101
begin
102
super
103
rescue Exception => e
104
is_error_handled = self.client.on_run_command_error_proc && self.client.on_run_command_error_proc.call(e) == :handled
105
return if is_error_handled
106
case e
107
when Rex::TimeoutError, Rex::InvalidDestination
108
log_error(e.message)
109
when Timeout::Error
110
log_error('Operation timed out.')
111
when RequestError
112
log_error(e.to_s)
113
when ::Errno::EPIPE, ::OpenSSL::SSL::SSLError, ::IOError
114
self.client.kill
115
when ::Exception
116
log_error("Error running command #{method}: #{e.class} #{e}")
117
elog(e)
118
end
119
end
120
end
121
122
#
123
# Logs that an error occurred and persists the callstack.
124
#
125
def log_error(msg)
126
print_error(msg)
127
128
elog(msg, 'meterpreter')
129
130
dlog("Call stack:\n#{$@.join("\n")}", 'meterpreter')
131
end
132
133
attr_reader :client # :nodoc:
134
135
protected
136
137
attr_writer :client # :nodoc:
138
attr_accessor :commands # :nodoc:
139
140
end
141
142
end
143
end
144
end
145
end
146
147
148