rex 2.0.9 → 2.0.10

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