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 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