librex 0.0.38 → 0.0.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +1 -1
- data/lib/rex/post/meterpreter/channel.rb +6 -5
- data/lib/rex/post/meterpreter/client.rb +77 -32
- data/lib/rex/post/meterpreter/client_core.rb +61 -14
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +19 -18
- data/lib/rex/post/meterpreter/packet_dispatcher.rb +109 -14
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +22 -6
- data/lib/rex/proto/http/packet.rb +1 -1
- metadata +3 -3
data/README.markdown
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
A non-official re-packaging of the Rex library as a gem for easy of usage of the Metasploit REX framework in a non Metasploit application. I received permission from HDM to create this package.
|
4
4
|
|
5
5
|
Currently based on:
|
6
|
-
SVN Revision:
|
6
|
+
SVN Revision: 13058
|
7
7
|
|
8
8
|
# Credits
|
9
9
|
The Metasploit development team <http://www.metasploit.com>
|
@@ -172,7 +172,8 @@ class Channel
|
|
172
172
|
request = Packet.create_request('core_channel_read')
|
173
173
|
|
174
174
|
if (length == nil)
|
175
|
-
|
175
|
+
# Default block size to a higher amount for passive dispatcher
|
176
|
+
length = self.client.passive_service ? (1024*1024) : 65536
|
176
177
|
end
|
177
178
|
|
178
179
|
request.add_tlv(TLV_TYPE_CHANNEL_ID, self.cid)
|
@@ -228,12 +229,12 @@ class Channel
|
|
228
229
|
|
229
230
|
# Populate the request
|
230
231
|
request.add_tlv(TLV_TYPE_CHANNEL_ID, self.cid)
|
231
|
-
|
232
|
+
|
232
233
|
cdata = request.add_tlv(TLV_TYPE_CHANNEL_DATA, buf)
|
233
234
|
if( ( self.flags & CHANNEL_FLAG_COMPRESS ) == CHANNEL_FLAG_COMPRESS )
|
234
|
-
cdata.compress = true
|
235
|
+
cdata.compress = true
|
235
236
|
end
|
236
|
-
|
237
|
+
|
237
238
|
request.add_tlv(TLV_TYPE_LENGTH, length)
|
238
239
|
request.add_tlvs(addends)
|
239
240
|
|
@@ -285,7 +286,7 @@ class Channel
|
|
285
286
|
|
286
287
|
return true
|
287
288
|
end
|
288
|
-
|
289
|
+
|
289
290
|
def _close(addends = nil)
|
290
291
|
self.class._close(self.client, self.cid, addends)
|
291
292
|
self.cid = nil
|
@@ -45,7 +45,7 @@ class Client
|
|
45
45
|
# Cached SSL certificate (required to scale)
|
46
46
|
#
|
47
47
|
@@ssl_ctx = nil
|
48
|
-
|
48
|
+
|
49
49
|
#
|
50
50
|
# Mutex to synchronize class-wide operations
|
51
51
|
#
|
@@ -89,38 +89,59 @@ class Client
|
|
89
89
|
extension.cleanup if extension.respond_to?( 'cleanup' )
|
90
90
|
end
|
91
91
|
dispatcher_thread.kill if dispatcher_thread
|
92
|
+
core.shutdown rescue nil
|
93
|
+
shutdown_passive_dispatcher
|
92
94
|
end
|
93
95
|
|
94
96
|
#
|
95
97
|
# Initializes the meterpreter client instance
|
96
98
|
#
|
97
99
|
def init_meterpreter(sock,opts={})
|
98
|
-
self.sock
|
99
|
-
self.parser
|
100
|
-
self.ext
|
101
|
-
self.ext_aliases
|
102
|
-
self.alive
|
103
|
-
self.target_id
|
104
|
-
self.capabilities= opts[:capabilities] || {}
|
105
|
-
|
106
|
-
|
100
|
+
self.sock = sock
|
101
|
+
self.parser = PacketParser.new
|
102
|
+
self.ext = ObjectAliases.new
|
103
|
+
self.ext_aliases = ObjectAliases.new
|
104
|
+
self.alive = true
|
105
|
+
self.target_id = opts[:target_id]
|
106
|
+
self.capabilities = opts[:capabilities] || {}
|
107
|
+
|
108
|
+
|
109
|
+
self.conn_id = opts[:conn_id]
|
110
|
+
self.url = opts[:url]
|
111
|
+
self.ssl = opts[:ssl]
|
112
|
+
self.expiration = opts[:expiration]
|
113
|
+
self.comm_timeout = opts[:comm_timeout]
|
114
|
+
self.passive_dispatcher = opts[:passive_dispatcher]
|
115
|
+
|
116
|
+
self.response_timeout = opts[:timeout] || self.class.default_timeout
|
107
117
|
self.send_keepalives = true
|
108
118
|
|
119
|
+
if opts[:passive_dispatcher]
|
120
|
+
initialize_passive_dispatcher
|
109
121
|
|
110
|
-
|
111
|
-
if capabilities[:ssl] and not opts[:skip_ssl]
|
112
|
-
swap_sock_plain_to_ssl()
|
113
|
-
end
|
122
|
+
register_extension_alias('core', ClientCore.new(self))
|
114
123
|
|
115
|
-
|
124
|
+
initialize_inbound_handlers
|
125
|
+
initialize_channels
|
116
126
|
|
117
|
-
|
118
|
-
|
127
|
+
# Register the channel inbound packet handler
|
128
|
+
register_inbound_handler(Rex::Post::Meterpreter::Channel)
|
129
|
+
else
|
130
|
+
# Switch the socket to SSL mode and receive the hello if needed
|
131
|
+
if capabilities[:ssl] and not opts[:skip_ssl]
|
132
|
+
swap_sock_plain_to_ssl()
|
133
|
+
end
|
119
134
|
|
120
|
-
|
121
|
-
register_inbound_handler(Rex::Post::Meterpreter::Channel)
|
135
|
+
register_extension_alias('core', ClientCore.new(self))
|
122
136
|
|
123
|
-
|
137
|
+
initialize_inbound_handlers
|
138
|
+
initialize_channels
|
139
|
+
|
140
|
+
# Register the channel inbound packet handler
|
141
|
+
register_inbound_handler(Rex::Post::Meterpreter::Channel)
|
142
|
+
|
143
|
+
monitor_socket
|
144
|
+
end
|
124
145
|
end
|
125
146
|
|
126
147
|
def swap_sock_plain_to_ssl
|
@@ -138,22 +159,22 @@ class Client
|
|
138
159
|
rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
|
139
160
|
IO::select(nil, nil, nil, 0.10)
|
140
161
|
retry
|
141
|
-
|
142
|
-
# Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
|
162
|
+
|
163
|
+
# Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
|
143
164
|
rescue ::Exception => e
|
144
165
|
if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
|
145
166
|
IO::select( [ ssl ], nil, nil, 0.10 )
|
146
167
|
retry
|
147
168
|
end
|
148
|
-
|
149
|
-
if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
|
169
|
+
|
170
|
+
if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
|
150
171
|
IO::select( nil, [ ssl ], nil, 0.10 )
|
151
172
|
retry
|
152
173
|
end
|
153
|
-
|
174
|
+
|
154
175
|
raise e
|
155
176
|
end
|
156
|
-
end
|
177
|
+
end
|
157
178
|
|
158
179
|
self.sock.extend(Rex::Socket::SslTcp)
|
159
180
|
self.sock.sslsock = ssl
|
@@ -175,11 +196,11 @@ class Client
|
|
175
196
|
end
|
176
197
|
|
177
198
|
def generate_ssl_context
|
178
|
-
@@ssl_mutex.synchronize do
|
199
|
+
@@ssl_mutex.synchronize do
|
179
200
|
if not @@ssl_ctx
|
180
|
-
|
201
|
+
|
181
202
|
wlog("Generating SSL certificate for Meterpreter sessions")
|
182
|
-
|
203
|
+
|
183
204
|
key = OpenSSL::PKey::RSA.new(1024){ }
|
184
205
|
cert = OpenSSL::X509::Certificate.new
|
185
206
|
cert.version = 2
|
@@ -223,12 +244,12 @@ class Client
|
|
223
244
|
ctx.session_id_context = Rex::Text.rand_text(16)
|
224
245
|
|
225
246
|
wlog("Generated SSL certificate for Meterpreter sessions")
|
226
|
-
|
247
|
+
|
227
248
|
@@ssl_ctx = ctx
|
228
|
-
|
249
|
+
|
229
250
|
end # End of if not @ssl_ctx
|
230
251
|
end # End of mutex.synchronize
|
231
|
-
|
252
|
+
|
232
253
|
@@ssl_ctx
|
233
254
|
end
|
234
255
|
|
@@ -379,6 +400,30 @@ class Client
|
|
379
400
|
# The libraries available to this meterpreter server
|
380
401
|
#
|
381
402
|
attr_accessor :capabilities
|
403
|
+
#
|
404
|
+
# The Connection ID
|
405
|
+
#
|
406
|
+
attr_accessor :conn_id
|
407
|
+
#
|
408
|
+
# The Connect URL
|
409
|
+
#
|
410
|
+
attr_accessor :url
|
411
|
+
#
|
412
|
+
# Use SSL (HTTPS)
|
413
|
+
#
|
414
|
+
attr_accessor :ssl
|
415
|
+
#
|
416
|
+
# The Session Expiration Timeout
|
417
|
+
#
|
418
|
+
attr_accessor :expiration
|
419
|
+
#
|
420
|
+
# The Communication Timeout
|
421
|
+
#
|
422
|
+
attr_accessor :comm_timeout
|
423
|
+
#
|
424
|
+
# The Passive Dispatcher
|
425
|
+
#
|
426
|
+
attr_accessor :passive_dispatcher
|
382
427
|
|
383
428
|
protected
|
384
429
|
attr_accessor :parser, :ext_aliases # :nodoc:
|
@@ -184,7 +184,7 @@ class ClientCore < Extension
|
|
184
184
|
|
185
185
|
# We cant migrate into a process that does not exist.
|
186
186
|
if( process == nil )
|
187
|
-
raise RuntimeError, "Cannot migrate into non
|
187
|
+
raise RuntimeError, "Cannot migrate into non existent process", caller
|
188
188
|
end
|
189
189
|
|
190
190
|
# We cant migrate into a process that we are unable to open
|
@@ -216,13 +216,42 @@ class ClientCore < Extension
|
|
216
216
|
migrate_stager = c.new()
|
217
217
|
migrate_stager.datastore['DLL'] = ::File.join( Msf::Config.install_root, "data", "meterpreter", "metsrv.#{binary_suffix}" )
|
218
218
|
|
219
|
-
|
219
|
+
blob = migrate_stager.stage_payload
|
220
|
+
|
221
|
+
if client.passive_service
|
222
|
+
|
223
|
+
# Replace the transport string first (TRANSPORT_SOCKET_SSL
|
224
|
+
i = blob.index("METERPRETER_TRANSPORT_SSL")
|
225
|
+
if i
|
226
|
+
str = client.ssl ? "METERPRETER_TRANSPORT_HTTPS\x00" : "METERPRETER_TRANSPORT_HTTP\x00"
|
227
|
+
blob[i, str.length] = str
|
228
|
+
end
|
229
|
+
|
230
|
+
conn_id = self.client.conn_id
|
231
|
+
i = blob.index("https://" + ("X" * 256))
|
232
|
+
if i
|
233
|
+
str = self.client.url
|
234
|
+
blob[i, str.length] = str
|
235
|
+
end
|
236
|
+
|
237
|
+
i = blob.index([0xb64be661].pack("V"))
|
238
|
+
if i
|
239
|
+
str = [ self.client.expiration ].pack("V")
|
240
|
+
blob[i, str.length] = str
|
241
|
+
end
|
242
|
+
|
243
|
+
i = blob.index([0xaf79257f].pack("V"))
|
244
|
+
if i
|
245
|
+
str = [ self.client.comm_timeout ].pack("V")
|
246
|
+
blob[i, str.length] = str
|
247
|
+
end
|
248
|
+
end
|
220
249
|
|
221
250
|
# Build the migration request
|
222
251
|
request = Packet.create_request( 'core_migrate' )
|
223
252
|
request.add_tlv( TLV_TYPE_MIGRATE_PID, pid )
|
224
|
-
request.add_tlv( TLV_TYPE_MIGRATE_LEN,
|
225
|
-
request.add_tlv( TLV_TYPE_MIGRATE_PAYLOAD,
|
253
|
+
request.add_tlv( TLV_TYPE_MIGRATE_LEN, blob.length )
|
254
|
+
request.add_tlv( TLV_TYPE_MIGRATE_PAYLOAD, blob, false, client.capabilities[:zlib])
|
226
255
|
if( process['arch'] == ARCH_X86_64 )
|
227
256
|
request.add_tlv( TLV_TYPE_MIGRATE_ARCH, 2 ) # PROCESS_ARCH_X64
|
228
257
|
else
|
@@ -232,19 +261,28 @@ class ClientCore < Extension
|
|
232
261
|
# Send the migration request (bump up the timeout to 60 seconds)
|
233
262
|
response = client.send_request( request, 60 )
|
234
263
|
|
235
|
-
|
236
|
-
|
264
|
+
if client.passive_service
|
265
|
+
# Sleep for 5 seconds to allow the full handoff, this prevents
|
266
|
+
# the original process from stealing our loadlib requests
|
267
|
+
::IO.select(nil, nil, nil, 5.0)
|
268
|
+
else
|
269
|
+
# Prevent new commands from being sent while we finish migrating
|
270
|
+
client.comm_mutex.synchronize do
|
271
|
+
# Disable the socket request monitor
|
272
|
+
client.monitor_stop
|
237
273
|
|
238
|
-
|
239
|
-
|
240
|
-
|
274
|
+
###
|
275
|
+
# Now communicating with the new process
|
276
|
+
###
|
241
277
|
|
242
|
-
|
243
|
-
|
244
|
-
|
278
|
+
# Renegotiate SSL over this socket
|
279
|
+
client.swap_sock_ssl_to_plain()
|
280
|
+
client.swap_sock_plain_to_ssl()
|
245
281
|
|
246
|
-
|
247
|
-
|
282
|
+
# Restart the socket monitor
|
283
|
+
client.monitor_socket
|
284
|
+
end
|
285
|
+
end
|
248
286
|
|
249
287
|
# Update the meterpreter platform/suffix for loading extensions as we may have changed target architecture
|
250
288
|
# sf: this is kinda hacky but it works. As ruby doesnt let you un-include a module this is the simplest solution I could think of.
|
@@ -268,6 +306,15 @@ class ClientCore < Extension
|
|
268
306
|
return true
|
269
307
|
end
|
270
308
|
|
309
|
+
#
|
310
|
+
# Shuts the session down
|
311
|
+
#
|
312
|
+
def shutdown
|
313
|
+
request = Packet.create_request('core_shutdown')
|
314
|
+
response = self.client.send_packet_wait_response(request, 15)
|
315
|
+
true
|
316
|
+
end
|
317
|
+
|
271
318
|
end
|
272
319
|
|
273
320
|
end; end; end
|
@@ -27,27 +27,27 @@ SEPARATOR = "\\"
|
|
27
27
|
Separator = "\\"
|
28
28
|
|
29
29
|
include Rex::Post::File
|
30
|
-
|
30
|
+
|
31
31
|
class << self
|
32
32
|
attr_accessor :client
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
#
|
36
36
|
# Search for files.
|
37
37
|
#
|
38
38
|
def File.search( root=nil, glob="*.*", recurse=true, timeout=-1 )
|
39
|
-
|
39
|
+
|
40
40
|
files = ::Array.new
|
41
|
-
|
41
|
+
|
42
42
|
request = Packet.create_request( 'stdapi_fs_search' )
|
43
43
|
|
44
44
|
root = root.chomp( '\\' ) if root
|
45
|
-
|
45
|
+
|
46
46
|
request.add_tlv( TLV_TYPE_SEARCH_ROOT, root )
|
47
47
|
request.add_tlv( TLV_TYPE_SEARCH_GLOB, glob )
|
48
48
|
request.add_tlv( TLV_TYPE_SEARCH_RECURSE, recurse )
|
49
49
|
|
50
|
-
# we set the response timeout to -1 to wait indefinatly as a
|
50
|
+
# we set the response timeout to -1 to wait indefinatly as a
|
51
51
|
# search could take an indeterminate ammount of time to complete.
|
52
52
|
response = client.send_request( request, timeout )
|
53
53
|
if( response.result == 0 )
|
@@ -59,10 +59,10 @@ Separator = "\\"
|
|
59
59
|
}
|
60
60
|
end
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
return files
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
#
|
67
67
|
# Returns the base name of the supplied file path to the caller.
|
68
68
|
#
|
@@ -86,7 +86,7 @@ Separator = "\\"
|
|
86
86
|
request.add_tlv(TLV_TYPE_FILE_PATH, path)
|
87
87
|
|
88
88
|
response = client.send_request(request)
|
89
|
-
|
89
|
+
|
90
90
|
return response.get_tlv_value(TLV_TYPE_FILE_PATH)
|
91
91
|
end
|
92
92
|
|
@@ -104,27 +104,27 @@ Separator = "\\"
|
|
104
104
|
r = client.fs.filestat.new(name) rescue nil
|
105
105
|
r ? true : false
|
106
106
|
end
|
107
|
-
|
107
|
+
|
108
108
|
#
|
109
109
|
# Performs a delete on the specified file.
|
110
110
|
#
|
111
|
-
def File.rm(name)
|
111
|
+
def File.rm(name)
|
112
112
|
request = Packet.create_request('stdapi_fs_delete_file')
|
113
113
|
|
114
114
|
request.add_tlv(TLV_TYPE_FILE_PATH,name)
|
115
115
|
|
116
116
|
response = client.send_request(request)
|
117
|
-
|
117
|
+
|
118
118
|
return response
|
119
119
|
end
|
120
|
-
|
120
|
+
|
121
121
|
#
|
122
122
|
# Performs a delete on the specified file.
|
123
123
|
#
|
124
124
|
def File.unlink(name)
|
125
125
|
return File.rm(name)
|
126
|
-
end
|
127
|
-
|
126
|
+
end
|
127
|
+
|
128
128
|
#
|
129
129
|
# Upload one or more files to the remote computer the remote
|
130
130
|
# directory supplied in destination.
|
@@ -151,7 +151,7 @@ Separator = "\\"
|
|
151
151
|
# all of the contents of the local file
|
152
152
|
dest_fd = client.fs.file.new(dest_file, "wb")
|
153
153
|
src_buf = ''
|
154
|
-
|
154
|
+
|
155
155
|
::File.open(src_file, 'rb') { |f|
|
156
156
|
src_buf = f.read(f.stat.size)
|
157
157
|
}
|
@@ -164,7 +164,7 @@ Separator = "\\"
|
|
164
164
|
end
|
165
165
|
|
166
166
|
#
|
167
|
-
# Download one or more files from the remote computer to the local
|
167
|
+
# Download one or more files from the remote computer to the local
|
168
168
|
# directory supplied in destination.
|
169
169
|
#
|
170
170
|
def File.download(destination, *src_files, &stat)
|
@@ -178,7 +178,7 @@ Separator = "\\"
|
|
178
178
|
end
|
179
179
|
|
180
180
|
download_file(dest, src)
|
181
|
-
|
181
|
+
|
182
182
|
stat.call('downloaded', src, dest) if (stat)
|
183
183
|
}
|
184
184
|
end
|
@@ -272,3 +272,4 @@ protected
|
|
272
272
|
end
|
273
273
|
|
274
274
|
end; end; end; end; end; end
|
275
|
+
|
@@ -29,9 +29,9 @@ class RequestError < ArgumentError
|
|
29
29
|
|
30
30
|
# The error result that occurred, typically a windows error message.
|
31
31
|
attr_reader :result
|
32
|
-
|
32
|
+
|
33
33
|
# The error result that occurred, typically a windows error code.
|
34
|
-
attr_reader :code
|
34
|
+
attr_reader :code
|
35
35
|
end
|
36
36
|
|
37
37
|
###
|
@@ -44,6 +44,84 @@ module PacketDispatcher
|
|
44
44
|
|
45
45
|
PacketTimeout = 600
|
46
46
|
|
47
|
+
##
|
48
|
+
#
|
49
|
+
# Synchronization
|
50
|
+
#
|
51
|
+
##
|
52
|
+
attr_accessor :comm_mutex
|
53
|
+
|
54
|
+
|
55
|
+
##
|
56
|
+
#
|
57
|
+
#
|
58
|
+
# Passive Dispatching
|
59
|
+
#
|
60
|
+
##
|
61
|
+
attr_accessor :passive_service, :send_queue, :recv_queue
|
62
|
+
|
63
|
+
def initialize_passive_dispatcher
|
64
|
+
self.send_queue = []
|
65
|
+
self.recv_queue = []
|
66
|
+
self.waiters = []
|
67
|
+
self.alive = true
|
68
|
+
|
69
|
+
self.passive_service = self.passive_dispatcher
|
70
|
+
self.passive_service.remove_resource("/" + self.conn_id + "/")
|
71
|
+
self.passive_service.add_resource("/" + self.conn_id + "/",
|
72
|
+
'Proc' => Proc.new { |cli, req| on_passive_request(cli, req) },
|
73
|
+
'VirtualDirectory' => true
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
def shutdown_passive_dispatcher
|
78
|
+
return if not self.passive_service
|
79
|
+
self.passive_service.remove_resource("/" + self.conn_id + "/")
|
80
|
+
|
81
|
+
self.alive = false
|
82
|
+
self.send_queue = []
|
83
|
+
self.recv_queue = []
|
84
|
+
self.waiters = []
|
85
|
+
|
86
|
+
self.passive_service = nil
|
87
|
+
end
|
88
|
+
|
89
|
+
def on_passive_request(cli, req)
|
90
|
+
|
91
|
+
begin
|
92
|
+
|
93
|
+
resp = Rex::Proto::Http::Response.new(200, "OK")
|
94
|
+
resp['Content-Type'] = 'application/octet-stream'
|
95
|
+
resp['Connection'] = 'close'
|
96
|
+
|
97
|
+
# If the first 4 bytes are "RECV", return the oldest packet from the outbound queue
|
98
|
+
if req.body[0,4] == "RECV"
|
99
|
+
rpkt = send_queue.pop
|
100
|
+
resp.body = rpkt || ''
|
101
|
+
begin
|
102
|
+
cli.send_response(resp)
|
103
|
+
rescue ::Exception => e
|
104
|
+
send_queue.unshift(rpkt) if rpkt
|
105
|
+
elog("Exception sending a reply to the reader request: #{cli.inspect} #{e.class} #{e} #{e.backtrace}")
|
106
|
+
end
|
107
|
+
else
|
108
|
+
resp.body = ""
|
109
|
+
if req.body and req.body.length > 0
|
110
|
+
packet = Packet.new(0)
|
111
|
+
packet.from_r(req.body)
|
112
|
+
dispatch_inbound_packet(packet)
|
113
|
+
end
|
114
|
+
cli.send_response(resp)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Force a closure for older WinInet implementations
|
118
|
+
self.passive_service.close_client( cli )
|
119
|
+
|
120
|
+
rescue ::Exception => e
|
121
|
+
elog("Exception handling request: #{cli.inspect} #{req.inspect} #{e.class} #{e} #{e.backtrace}")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
47
125
|
##
|
48
126
|
#
|
49
127
|
# Transmission
|
@@ -62,23 +140,34 @@ module PacketDispatcher
|
|
62
140
|
raw = packet.to_r
|
63
141
|
err = nil
|
64
142
|
|
143
|
+
# Short-circuit send when using a passive dispatcher
|
144
|
+
if self.passive_service
|
145
|
+
send_queue.push(raw)
|
146
|
+
return raw.size # Lie!
|
147
|
+
end
|
148
|
+
|
65
149
|
if (raw)
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
150
|
+
|
151
|
+
# This mutex is used to lock out new commands during an
|
152
|
+
# active migration.
|
153
|
+
|
154
|
+
self.comm_mutex.synchronize do
|
155
|
+
begin
|
156
|
+
bytes = self.sock.write(raw)
|
157
|
+
rescue ::Exception => e
|
158
|
+
err = e
|
159
|
+
end
|
71
160
|
end
|
72
|
-
|
161
|
+
|
73
162
|
if bytes.to_i == 0
|
74
163
|
# Mark the session itself as dead
|
75
164
|
self.alive = false
|
76
|
-
|
165
|
+
|
77
166
|
# Indicate that the dispatcher should shut down too
|
78
167
|
@finish = true
|
79
|
-
|
168
|
+
|
80
169
|
# Reraise the error to the top-level caller
|
81
|
-
raise err if err
|
170
|
+
raise err if err
|
82
171
|
end
|
83
172
|
end
|
84
173
|
|
@@ -89,12 +178,12 @@ module PacketDispatcher
|
|
89
178
|
# Sends a packet and waits for a timeout for the given time interval.
|
90
179
|
#
|
91
180
|
def send_request(packet, t = self.response_timeout)
|
92
|
-
|
181
|
+
|
93
182
|
if not t
|
94
183
|
send_packet(packet)
|
95
184
|
return nil
|
96
185
|
end
|
97
|
-
|
186
|
+
|
98
187
|
response = send_packet_wait_response(packet, t)
|
99
188
|
|
100
189
|
if (response == nil)
|
@@ -146,6 +235,12 @@ module PacketDispatcher
|
|
146
235
|
# thread context and parsers all inbound packets.
|
147
236
|
#
|
148
237
|
def monitor_socket
|
238
|
+
|
239
|
+
# Skip if we are using a passive dispatcher
|
240
|
+
return if self.passive_service
|
241
|
+
|
242
|
+
self.comm_mutex = ::Mutex.new
|
243
|
+
|
149
244
|
self.waiters = []
|
150
245
|
|
151
246
|
@pqueue = []
|
@@ -303,6 +398,7 @@ module PacketDispatcher
|
|
303
398
|
self.receiver_thread.kill
|
304
399
|
self.receiver_thread = nil
|
305
400
|
end
|
401
|
+
|
306
402
|
if(self.dispatcher_thread)
|
307
403
|
self.dispatcher_thread.kill
|
308
404
|
self.dispatcher_thread = nil
|
@@ -385,7 +481,6 @@ module PacketDispatcher
|
|
385
481
|
end
|
386
482
|
end
|
387
483
|
|
388
|
-
|
389
484
|
# Enumerate all of the inbound packet handlers until one handles
|
390
485
|
# the packet
|
391
486
|
@inbound_handlers.each { |handler|
|
@@ -43,6 +43,7 @@ class Console::CommandDispatcher::Core
|
|
43
43
|
"close" => "Closes a channel",
|
44
44
|
"channel" => "Displays information about active channels",
|
45
45
|
"exit" => "Terminate the meterpreter session",
|
46
|
+
"detach" => "Detach the meterpreter session (for http/https)",
|
46
47
|
"help" => "Help menu",
|
47
48
|
"interact" => "Interacts with a channel",
|
48
49
|
"irb" => "Drop into irb scripting mode",
|
@@ -204,11 +205,26 @@ class Console::CommandDispatcher::Core
|
|
204
205
|
# Terminates the meterpreter session.
|
205
206
|
#
|
206
207
|
def cmd_exit(*args)
|
208
|
+
print_status("Shutting down Meterpreter...")
|
209
|
+
client.core.shutdown rescue nil
|
210
|
+
client.shutdown_passive_dispatcher
|
207
211
|
shell.stop
|
208
212
|
end
|
209
213
|
|
210
214
|
alias cmd_quit cmd_exit
|
211
215
|
|
216
|
+
#
|
217
|
+
# Disconnects the session
|
218
|
+
#
|
219
|
+
def cmd_detach(*args)
|
220
|
+
if not client.passive_service
|
221
|
+
print_error("Detach is only possible for non-stream sessions (http/https)")
|
222
|
+
return
|
223
|
+
end
|
224
|
+
client.shutdown_passive_dispatcher
|
225
|
+
shell.stop
|
226
|
+
end
|
227
|
+
|
212
228
|
#
|
213
229
|
# Interacts with a channel.
|
214
230
|
#
|
@@ -385,11 +401,11 @@ class Console::CommandDispatcher::Core
|
|
385
401
|
|
386
402
|
def cmd_run_help
|
387
403
|
print_line "Usage: run <script> [arguments]"
|
388
|
-
print_line
|
404
|
+
print_line
|
389
405
|
print_line "Executes a ruby script or Metasploit Post module in the context of the"
|
390
406
|
print_line "meterpreter session. Post modules can take arguments in var=val format."
|
391
407
|
print_line "Example: run post/foo/bar BAZ=abcd"
|
392
|
-
print_line
|
408
|
+
print_line
|
393
409
|
end
|
394
410
|
|
395
411
|
#
|
@@ -535,7 +551,7 @@ class Console::CommandDispatcher::Core
|
|
535
551
|
end
|
536
552
|
|
537
553
|
#
|
538
|
-
# Show info for a given Post module.
|
554
|
+
# Show info for a given Post module.
|
539
555
|
#
|
540
556
|
# See also +cmd_info+ in lib/msf/ui/console/command_dispatcher/core.rb
|
541
557
|
#
|
@@ -546,10 +562,10 @@ class Console::CommandDispatcher::Core
|
|
546
562
|
cmd_info_help
|
547
563
|
return
|
548
564
|
end
|
549
|
-
|
565
|
+
|
550
566
|
module_name = args.shift
|
551
567
|
mod = client.framework.modules.create(module_name);
|
552
|
-
|
568
|
+
|
553
569
|
if mod.nil?
|
554
570
|
print_error 'Invalid module: ' << module_name
|
555
571
|
end
|
@@ -655,7 +671,7 @@ class Console::CommandDispatcher::Core
|
|
655
671
|
|
656
672
|
tab_complete_filenames(str, words)
|
657
673
|
end
|
658
|
-
|
674
|
+
|
659
675
|
def cmd_resource(*args)
|
660
676
|
if args.empty?
|
661
677
|
print(
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: librex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.39
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Metasploit Development Team
|
@@ -11,11 +11,11 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2011-06-
|
14
|
+
date: 2011-06-28 00:00:00 -05:00
|
15
15
|
default_executable:
|
16
16
|
dependencies: []
|
17
17
|
|
18
|
-
description: Rex provides a variety of classes useful for security testing and exploit development. Based on SVN Revision
|
18
|
+
description: Rex provides a variety of classes useful for security testing and exploit development. Based on SVN Revision 13058
|
19
19
|
email:
|
20
20
|
- hdm@metasploit.com
|
21
21
|
- jacob.hammack@hammackj.com
|