rex 2.0.9 → 2.0.10

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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rex/exploitation/cmdstager/bourne.rb +14 -8
  3. data/lib/rex/exploitation/cmdstager/echo.rb +3 -3
  4. data/lib/rex/exploitation/js/memory.rb +1 -1
  5. data/lib/rex/java/serialization/model/contents.rb +1 -1
  6. data/lib/rex/mime/message.rb +1 -1
  7. data/lib/rex/parser/acunetix_nokogiri.rb +2 -0
  8. data/lib/rex/parser/appscan_nokogiri.rb +1 -1
  9. data/lib/rex/parser/burp_issue_nokogiri.rb +139 -0
  10. data/lib/rex/parser/burp_session_nokogiri.rb +1 -1
  11. data/lib/rex/parser/fs/bitlocker.rb +233 -0
  12. data/lib/rex/parser/fusionvm_nokogiri.rb +2 -2
  13. data/lib/rex/parser/ini.rb +1 -8
  14. data/lib/rex/parser/nokogiri_doc_mixin.rb +5 -0
  15. data/lib/rex/payloads/meterpreter/config.rb +23 -4
  16. data/lib/rex/post/meterpreter/channel.rb +8 -3
  17. data/lib/rex/post/meterpreter/client.rb +1 -0
  18. data/lib/rex/post/meterpreter/client_core.rb +2 -2
  19. data/lib/rex/post/meterpreter/extensions/android/android.rb +86 -1
  20. data/lib/rex/post/meterpreter/extensions/android/tlv.rb +29 -0
  21. data/lib/rex/post/meterpreter/extensions/extapi/wmi/wmi.rb +1 -1
  22. data/lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/tcp_server_channel.rb +75 -89
  23. data/lib/rex/post/meterpreter/extensions/stdapi/sys/event_log.rb +8 -2
  24. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +10 -5
  25. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +7 -2
  26. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/remote_registry_key.rb +10 -5
  27. data/lib/rex/post/meterpreter/extensions/stdapi/sys/thread.rb +8 -2
  28. data/lib/rex/post/meterpreter/extensions/stdapi/webcam/webcam.rb +1 -1
  29. data/lib/rex/post/meterpreter/packet.rb +38 -0
  30. data/lib/rex/post/meterpreter/packet_dispatcher.rb +101 -108
  31. data/lib/rex/post/meterpreter/packet_parser.rb +14 -6
  32. data/lib/rex/post/meterpreter/packet_response_waiter.rb +42 -21
  33. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +54 -4
  34. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +39 -13
  35. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +8 -0
  36. data/lib/rex/proto/adb.rb +7 -0
  37. data/lib/rex/proto/adb/client.rb +39 -0
  38. data/lib/rex/proto/adb/message.rb +164 -0
  39. data/lib/rex/proto/dcerpc/svcctl/packet.rb +9 -9
  40. data/lib/rex/proto/http/client_request.rb +2 -1
  41. data/lib/rex/proto/http/response.rb +1 -1
  42. data/lib/rex/proto/kademlia/bootstrap_response.rb +2 -2
  43. data/lib/rex/proto/ntp/modes.rb +17 -0
  44. data/lib/rex/text.rb +12 -0
  45. data/lib/rex/zip/blocks.rb +1 -1
  46. data/lib/rex/zip/entry.rb +1 -1
  47. data/rex.gemspec +28 -1
  48. metadata +106 -3
@@ -60,7 +60,9 @@ class EventLog
60
60
  def initialize(hand)
61
61
  self.client = self.class.client
62
62
  self.handle = hand
63
- ObjectSpace.define_finalizer( self, self.class.finalize(self.client, self.handle) )
63
+
64
+ # Ensure the remote object is closed when all references are removed
65
+ ObjectSpace.define_finalizer(self, self.class.finalize(client, hand))
64
66
  end
65
67
 
66
68
  def self.finalize(client,handle)
@@ -185,7 +187,11 @@ class EventLog
185
187
 
186
188
  # Instance method
187
189
  def close
188
- self.class.close(self.client, self.handle)
190
+ unless self.handle.nil?
191
+ ObjectSpace.undefine_finalizer(self)
192
+ self.class.close(self.client, self.handle)
193
+ self.handle = nil
194
+ end
189
195
  end
190
196
  end
191
197
 
@@ -285,11 +285,12 @@ class Process < Rex::Post::Process
285
285
  'thread' => Rex::Post::Meterpreter::Extensions::Stdapi::Sys::ProcessSubsystem::Thread.new(self),
286
286
  })
287
287
 
288
- ObjectSpace.define_finalizer( self, self.class.finalize(self.client, self.handle) )
288
+ # Ensure the remote object is closed when all references are removed
289
+ ObjectSpace.define_finalizer(self, self.class.finalize(client, handle))
289
290
  end
290
291
 
291
- def self.finalize(client,handle)
292
- proc { self.close(client,handle) }
292
+ def self.finalize(client, handle)
293
+ proc { self.close(client, handle) }
293
294
  end
294
295
 
295
296
  #
@@ -320,8 +321,12 @@ class Process < Rex::Post::Process
320
321
  #
321
322
  # Instance method
322
323
  #
323
- def close(handle=self.handle)
324
- self.class.close(self.client, handle)
324
+ def close(handle = self.handle)
325
+ unless self.pid.nil?
326
+ ObjectSpace.undefine_finalizer(self)
327
+ self.class.close(self.client, handle)
328
+ self.pid = nil
329
+ end
325
330
  end
326
331
 
327
332
  #
@@ -30,7 +30,8 @@ class RegistryKey
30
30
  self.perm = perm
31
31
  self.hkey = hkey
32
32
 
33
- ObjectSpace.define_finalizer( self, self.class.finalize(self.client, self.hkey) )
33
+ # Ensure the remote object is closed when all references are removed
34
+ ObjectSpace.define_finalizer(self, self.class.finalize(client, hkey))
34
35
  end
35
36
 
36
37
  def self.finalize(client,hkey)
@@ -115,7 +116,11 @@ class RegistryKey
115
116
 
116
117
  # Instance method for the same
117
118
  def close()
118
- self.class.close(self.client, self.hkey)
119
+ unless self.hkey.nil?
120
+ ObjectSpace.undefine_finalizer(self)
121
+ self.class.close(self.client, self.hkey)
122
+ self.hkey = nil
123
+ end
119
124
  end
120
125
 
121
126
  ##
@@ -29,11 +29,12 @@ class RemoteRegistryKey
29
29
  self.target_host = target_host
30
30
  self.hkey = hkey
31
31
 
32
- ObjectSpace.define_finalizer( self, self.class.finalize(self.client, self.hkey) )
32
+ # Ensure the remote object is closed when all references are removed
33
+ ObjectSpace.define_finalizer(self, self.class.finalize(client, hkey))
33
34
  end
34
35
 
35
- def self.finalize(client,hkey)
36
- proc { self.close(client,hkey) }
36
+ def self.finalize(client, hkey)
37
+ proc { self.close(client, hkey) }
37
38
  end
38
39
 
39
40
  ##
@@ -113,8 +114,12 @@ class RemoteRegistryKey
113
114
  end
114
115
 
115
116
  # Instance method for the same
116
- def close()
117
- self.class.close(self.client, self.hkey)
117
+ def close
118
+ unless self.hkey.nil?
119
+ ObjectSpace.undefine_finalizer(self)
120
+ self.class.close(self.client, self.hkey)
121
+ self.hkey = nil
122
+ end
118
123
  end
119
124
 
120
125
  ##
@@ -34,7 +34,9 @@ class Thread < Rex::Post::Thread
34
34
  self.process = process
35
35
  self.handle = handle
36
36
  self.tid = tid
37
- ObjectSpace.define_finalizer( self, self.class.finalize(self.process.client, self.handle) )
37
+
38
+ # Ensure the remote object is closed when all references are removed
39
+ ObjectSpace.define_finalizer(self, self.class.finalize(process.client, handle))
38
40
  end
39
41
 
40
42
  def self.finalize(client,handle)
@@ -168,7 +170,11 @@ class Thread < Rex::Post::Thread
168
170
 
169
171
  # Instance method
170
172
  def close
171
- self.class.close(self.process.client, self.handle)
173
+ unless self.handle.nil?
174
+ ObjectSpace.undefine_finalizer(self)
175
+ self.class.close(self.process.client, self.handle)
176
+ self.handle = nil
177
+ end
172
178
  end
173
179
 
174
180
  attr_reader :process, :handle, :tid # :nodoc:
@@ -66,7 +66,7 @@ class Webcam
66
66
 
67
67
  remote_browser_path = webrtc_browser_path
68
68
 
69
- if remote_browser_path.blank?
69
+ if remote_browser_path.to_s.empty?
70
70
  fail "Unable to find a suitable browser on the target machine"
71
71
  end
72
72
 
@@ -665,6 +665,44 @@ class Packet < GroupTlv
665
665
  end
666
666
  end
667
667
 
668
+ #
669
+ # Override the function that creates the raw byte stream for
670
+ # sending so that it generates an XOR key, uses it to scramble
671
+ # the serialized TLV content, and then returns the key plus the
672
+ # scrambled data as the payload.
673
+ #
674
+ def to_r
675
+ raw = super
676
+ xor_key = rand(254) + 1
677
+ xor_key |= (rand(254) + 1) << 8
678
+ xor_key |= (rand(254) + 1) << 16
679
+ xor_key |= (rand(254) + 1) << 24
680
+ result = [xor_key].pack('N') + xor_bytes(xor_key, raw)
681
+ result
682
+ end
683
+
684
+ #
685
+ # Override the function that reads from a raw byte stream so
686
+ # that the XORing of data is included in the process prior to
687
+ # passing it on to the default functionality that can parse
688
+ # the TLV values.
689
+ #
690
+ def from_r(bytes)
691
+ xor_key = bytes[0,4].unpack('N')[0]
692
+ super(xor_bytes(xor_key, bytes[4, bytes.length]))
693
+ end
694
+
695
+ #
696
+ # Xor a set of bytes with a given DWORD xor key.
697
+ #
698
+ def xor_bytes(xor_key, bytes)
699
+ result = ''
700
+ bytes.bytes.zip([xor_key].pack('V').bytes.cycle).each do |b|
701
+ result << (b[0].ord ^ b[1].ord).chr
702
+ end
703
+ result
704
+ end
705
+
668
706
  ##
669
707
  #
670
708
  # Conditionals
@@ -42,23 +42,32 @@ end
42
42
  ###
43
43
  module PacketDispatcher
44
44
 
45
- PacketTimeout = 600
45
+ # Defualt time, in seconds, to wait for a response after sending a packet
46
+ PACKET_TIMEOUT = 600
46
47
 
47
- ##
48
- #
49
- # Synchronization
48
+ # Number of seconds to wait without getting any packets before we try to
49
+ # send a liveness check. A minute should be generous even on the highest
50
+ # latency networks
50
51
  #
51
- ##
52
+ # @see #keepalive
53
+ PING_TIME = 60
54
+
55
+ # This mutex is used to lock out new commands during an
56
+ # active migration. Unused if this is a passive dispatcher
52
57
  attr_accessor :comm_mutex
53
58
 
54
59
 
55
- ##
56
- #
57
- #
58
60
  # Passive Dispatching
59
61
  #
60
- ##
61
- attr_accessor :passive_service, :send_queue, :recv_queue
62
+ # @return [Rex::ServiceManager]
63
+ # @return [nil] if this is not a passive dispatcher
64
+ attr_accessor :passive_service
65
+
66
+ # @return [Array]
67
+ attr_accessor :send_queue
68
+
69
+ # @return [Array]
70
+ attr_accessor :recv_queue
62
71
 
63
72
  def initialize_passive_dispatcher
64
73
  self.send_queue = []
@@ -108,8 +117,7 @@ module PacketDispatcher
108
117
 
109
118
  self.last_checkin = Time.now
110
119
 
111
- # If the first 4 bytes are "RECV", return the oldest packet from the outbound queue
112
- if req.body[0,4] == "RECV"
120
+ if req.method == 'GET'
113
121
  rpkt = send_queue.shift
114
122
  resp.body = rpkt || ''
115
123
  begin
@@ -159,9 +167,6 @@ module PacketDispatcher
159
167
 
160
168
  if (raw)
161
169
 
162
- # This mutex is used to lock out new commands during an
163
- # active migration.
164
-
165
170
  self.comm_mutex.synchronize do
166
171
  begin
167
172
  bytes = self.sock.write(raw)
@@ -170,13 +175,11 @@ module PacketDispatcher
170
175
  end
171
176
  end
172
177
 
178
+
173
179
  if bytes.to_i == 0
174
180
  # Mark the session itself as dead
175
181
  self.alive = false
176
182
 
177
- # Indicate that the dispatcher should shut down too
178
- @finish = true
179
-
180
183
  # Reraise the error to the top-level caller
181
184
  raise err if err
182
185
  end
@@ -188,15 +191,16 @@ module PacketDispatcher
188
191
  #
189
192
  # Sends a packet and waits for a timeout for the given time interval.
190
193
  #
191
- def send_request(packet, t = self.response_timeout)
192
- if not t
193
- send_packet(packet)
194
- return nil
195
- end
196
-
197
- response = send_packet_wait_response(packet, t)
194
+ # @param packet [Packet] request to send
195
+ # @param timeout [Fixnum,nil] seconds to wait for response, or nil to ignore the
196
+ # response and return immediately
197
+ # @return (see #send_packet_wait_response)
198
+ def send_request(packet, timeout = self.response_timeout)
199
+ response = send_packet_wait_response(packet, timeout)
198
200
 
199
- if (response == nil)
201
+ if timeout.nil?
202
+ return nil
203
+ elsif response.nil?
200
204
  raise TimeoutError.new("Send timed out")
201
205
  elsif (response.result != 0)
202
206
  einfo = lookup_error(response.result)
@@ -213,26 +217,58 @@ module PacketDispatcher
213
217
  #
214
218
  # Transmits a packet and waits for a response.
215
219
  #
216
- def send_packet_wait_response(packet, t)
220
+ # @param packet [Packet] the request packet to send
221
+ # @param timeout [Fixnum,nil] number of seconds to wait, or nil to wait
222
+ # forever
223
+ def send_packet_wait_response(packet, timeout)
217
224
  # First, add the waiter association for the supplied packet
218
225
  waiter = add_response_waiter(packet)
219
226
 
227
+ bytes_written = send_packet(packet)
228
+
220
229
  # Transmit the packet
221
- if (send_packet(packet).to_i <= 0)
230
+ if (bytes_written.to_i <= 0)
222
231
  # Remove the waiter if we failed to send the packet.
223
232
  remove_response_waiter(waiter)
224
233
  return nil
225
234
  end
226
235
 
236
+ if not timeout
237
+ return nil
238
+ end
239
+
227
240
  # Wait for the supplied time interval
228
- waiter.wait(t)
241
+ response = waiter.wait(timeout)
229
242
 
230
243
  # Remove the waiter from the list of waiters in case it wasn't
231
- # removed
244
+ # removed. This happens if the waiter timed out above.
232
245
  remove_response_waiter(waiter)
233
246
 
234
247
  # Return the response packet, if any
235
- return waiter.response
248
+ return response
249
+ end
250
+
251
+ # Send a ping to the server.
252
+ #
253
+ # Our 'ping' is a check for eof on channel id 0. This method has no side
254
+ # effects and always returns an answer (regardless of the existence of chan
255
+ # 0), which is all that's needed for a liveness check. The answer itself is
256
+ # unimportant and is ignored.
257
+ #
258
+ # @return [void]
259
+ def keepalive
260
+ if @ping_sent
261
+ if Time.now.to_i - last_checkin.to_i > PING_TIME*2
262
+ dlog("No response to ping, session #{self.sid} is dead", LEV_3)
263
+ self.alive = false
264
+ end
265
+ else
266
+ pkt = Packet.create_request('core_channel_eof')
267
+ pkt.add_tlv(TLV_TYPE_CHANNEL_ID, 0)
268
+ add_response_waiter(pkt, Proc.new { @ping_sent = false })
269
+ send_packet(pkt)
270
+ @ping_sent = true
271
+ end
236
272
  end
237
273
 
238
274
  ##
@@ -253,59 +289,23 @@ module PacketDispatcher
253
289
 
254
290
  self.waiters = []
255
291
 
256
- @pqueue = []
257
- @finish = false
258
- @last_recvd = Time.now
292
+ @pqueue = ::Queue.new
259
293
  @ping_sent = false
260
294
 
261
- self.alive = true
262
-
263
295
  # Spawn a thread for receiving packets
264
296
  self.receiver_thread = Rex::ThreadFactory.spawn("MeterpreterReceiver", false) do
265
297
  while (self.alive)
266
298
  begin
267
- rv = Rex::ThreadSafe.select([ self.sock.fd ], nil, nil, 0.25)
268
- ping_time = 60
269
- # If there's nothing to read, and it's been awhile since we
270
- # saw a packet, we need to send a ping. We wait
271
- # ping_time*2 seconds before deciding a session is dead.
272
- if (not rv and self.send_keepalives and Time.now - @last_recvd > ping_time)
273
- # If the queue is empty and we've already sent a
274
- # keepalive without getting a reply, then this
275
- # session is hosed, and we should give up on it.
276
- if @ping_sent and @pqueue.empty? and (Time.now - @last_recvd > ping_time * 2)
277
- dlog("No response to ping, session #{self.sid} is dead", LEV_3)
278
- self.alive = false
279
- @finish = true
280
- break
281
- end
282
- # Let the packet queue processor finish up before
283
- # we send a ping.
284
- if not @ping_sent and @pqueue.empty?
285
- # Our 'ping' is actually just a check for eof on
286
- # channel id 0. This method has no side effects
287
- # and always returns an answer (regardless of the
288
- # existence of chan 0), which is all that's
289
- # needed for a liveness check. The answer itself
290
- # is unimportant and is ignored.
291
- pkt = Packet.create_request('core_channel_eof')
292
- pkt.add_tlv(TLV_TYPE_CHANNEL_ID, 0)
293
- waiter = Proc.new { |response, param|
294
- @ping_sent = false
295
- @last_recvd = Time.now
296
- }
297
- send_packet(pkt, waiter)
298
- @ping_sent = true
299
- end
300
- next
299
+ rv = Rex::ThreadSafe.select([ self.sock.fd ], nil, nil, PING_TIME)
300
+ if rv
301
+ packet = receive_packet
302
+ @pqueue << packet if packet
303
+ elsif self.send_keepalives && @pqueue.empty?
304
+ keepalive
301
305
  end
302
- next if not rv
303
- packet = receive_packet
304
- @pqueue << packet if packet
305
- @last_recvd = Time.now
306
- rescue ::Exception
307
- dlog("Exception caught in monitor_socket: #{$!}", 'meterpreter', LEV_1)
308
- @finish = true
306
+ rescue ::Exception => e
307
+ dlog("Exception caught in monitor_socket: #{e.class}: #{e}", 'meterpreter', LEV_1)
308
+ dlog("Call stack: #{e.backtrace.join("\n")}", 'meterpreter', LEV_2)
309
309
  self.alive = false
310
310
  break
311
311
  end
@@ -315,19 +315,13 @@ module PacketDispatcher
315
315
  # Spawn a new thread that monitors the socket
316
316
  self.dispatcher_thread = Rex::ThreadFactory.spawn("MeterpreterDispatcher", false) do
317
317
  begin
318
- # Whether we're finished or not is determined by the receiver
319
- # thread above.
320
- while(not @finish)
321
- if(@pqueue.empty?)
322
- ::IO.select(nil, nil, nil, 0.10)
323
- next
324
- end
325
-
318
+ while (self.alive)
326
319
  incomplete = []
327
320
  backlog = []
328
321
 
322
+ backlog << @pqueue.pop
329
323
  while(@pqueue.length > 0)
330
- backlog << @pqueue.shift
324
+ backlog << @pqueue.pop
331
325
  end
332
326
 
333
327
  #
@@ -356,7 +350,6 @@ module PacketDispatcher
356
350
  backlog.push(*tmp_channel)
357
351
  backlog.push(*tmp_close)
358
352
 
359
-
360
353
  #
361
354
  # Process the message queue
362
355
  #
@@ -367,12 +360,12 @@ module PacketDispatcher
367
360
  if ! dispatch_inbound_packet(pkt)
368
361
  # Keep Packets in the receive queue until a handler is registered
369
362
  # for them. Packets will live in the receive queue for up to
370
- # PacketTimeout, after which they will be dropped.
363
+ # PACKET_TIMEOUT seconds, after which they will be dropped.
371
364
  #
372
365
  # A common reason why there would not immediately be a handler for
373
366
  # a received Packet is in channels, where a connection may
374
367
  # open and receive data before anything has asked to read.
375
- if (::Time.now.to_i - pkt.created_at.to_i < PacketTimeout)
368
+ if (::Time.now.to_i - pkt.created_at.to_i < PACKET_TIMEOUT)
376
369
  incomplete << pkt
377
370
  end
378
371
  end
@@ -393,11 +386,16 @@ module PacketDispatcher
393
386
  ::IO.select(nil, nil, nil, 0.10)
394
387
  end
395
388
 
396
- @pqueue.unshift(*incomplete)
389
+ while incomplete.length > 0
390
+ @pqueue << incomplete.shift
391
+ end
397
392
 
398
393
  if(@pqueue.length > 100)
399
- dlog("Backlog has grown to over 100 in monitor_socket, dropping older packets: #{@pqueue[0 .. 25].map{|x| x.inspect}.join(" - ")}", 'meterpreter', LEV_1)
400
- @pqueue = @pqueue[25 .. 100]
394
+ removed = []
395
+ (1..25).each {
396
+ removed << @pqueue.pop
397
+ }
398
+ dlog("Backlog has grown to over 100 in monitor_socket, dropping older packets: #{removed.map{|x| x.inspect}.join(" - ")}", 'meterpreter', LEV_1)
401
399
  end
402
400
  end
403
401
  rescue ::Exception => e
@@ -454,15 +452,16 @@ module PacketDispatcher
454
452
  # if anyone.
455
453
  #
456
454
  def notify_response_waiter(response)
455
+ handled = false
457
456
  self.waiters.each() { |waiter|
458
457
  if (waiter.waiting_for?(response))
459
458
  waiter.notify(response)
460
-
461
459
  remove_response_waiter(waiter)
462
-
460
+ handled = true
463
461
  break
464
462
  end
465
463
  }
464
+ return handled
466
465
  end
467
466
 
468
467
  #
@@ -491,21 +490,15 @@ module PacketDispatcher
491
490
  # Otherwise, the packet is passed onto any registered dispatch
492
491
  # handlers until one returns success.
493
492
  #
494
- def dispatch_inbound_packet(packet, client = nil)
493
+ def dispatch_inbound_packet(packet)
495
494
  handled = false
496
495
 
497
- # If no client context was provided, return self as PacketDispatcher
498
- # is a mixin for the Client instance
499
- if (client == nil)
500
- client = self
501
- end
502
-
503
496
  # Update our last reply time
504
- client.last_checkin = Time.now
497
+ self.last_checkin = Time.now
505
498
 
506
499
  # If the packet is a response, try to notify any potential
507
500
  # waiters
508
- if ((resp = packet.response?))
501
+ if packet.response?
509
502
  if (notify_response_waiter(packet))
510
503
  return true
511
504
  end
@@ -518,11 +511,11 @@ module PacketDispatcher
518
511
  handled = nil
519
512
  begin
520
513
 
521
- if ! resp
522
- handled = handler.request_handler(client, packet)
523
- else
524
- handled = handler.response_handler(client, packet)
525
- end
514
+ if packet.response?
515
+ handled = handler.response_handler(self, packet)
516
+ else
517
+ handled = handler.request_handler(self, packet)
518
+ end
526
519
 
527
520
  rescue ::Exception => e
528
521
  dlog("Exception caught in dispatch_inbound_packet: handler=#{handler} #{e.class} #{e} #{e.backtrace}", 'meterpreter', LEV_1)