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
@@ -12,6 +12,11 @@ module Meterpreter
12
12
  ###
13
13
  class PacketParser
14
14
 
15
+ # 4 byte xor
16
+ # 4 byte length
17
+ # 4 byte type
18
+ HEADER_SIZE = 12
19
+
15
20
  #
16
21
  # Initializes the packet parser context with an optional cipher.
17
22
  #
@@ -26,7 +31,7 @@ class PacketParser
26
31
  #
27
32
  def reset
28
33
  self.raw = ''
29
- self.hdr_length_left = 8
34
+ self.hdr_length_left = HEADER_SIZE
30
35
  self.payload_length_left = 0
31
36
  end
32
37
 
@@ -34,6 +39,9 @@ class PacketParser
34
39
  # Reads data from the wire and parse as much of the packet as possible.
35
40
  #
36
41
  def recv(sock)
42
+ # Create a typeless packet
43
+ packet = Packet.new(0)
44
+
37
45
  if (self.hdr_length_left > 0)
38
46
  buf = sock.read(self.hdr_length_left)
39
47
 
@@ -49,7 +57,10 @@ class PacketParser
49
57
  # payload length left to the number of bytes
50
58
  # specified in the length
51
59
  if (self.hdr_length_left == 0)
52
- self.payload_length_left = raw.unpack("N")[0] - 8
60
+ xor_key = raw[0, 4].unpack('N')[0]
61
+ length_bytes = packet.xor_bytes(xor_key, raw[4, 4])
62
+ # header size doesn't include the xor key, which is always tacked on the front
63
+ self.payload_length_left = length_bytes.unpack("N")[0] - (HEADER_SIZE - 4)
53
64
  end
54
65
  elsif (self.payload_length_left > 0)
55
66
  buf = sock.read(self.payload_length_left)
@@ -67,14 +78,11 @@ class PacketParser
67
78
  if ((self.hdr_length_left == 0) &&
68
79
  (self.payload_length_left == 0))
69
80
 
70
- # Create a typeless packet
71
- packet = Packet.new(0)
72
-
73
81
  # TODO: cipher decryption
74
82
  if (cipher)
75
83
  end
76
84
 
77
- # Serialize the packet from the raw buffer
85
+ # Deserialize the packet from the raw buffer
78
86
  packet.from_r(self.raw)
79
87
 
80
88
  # Reset our state
@@ -15,6 +15,30 @@ module Meterpreter
15
15
  ###
16
16
  class PacketResponseWaiter
17
17
 
18
+ # Arbitrary argument to {#completion_routine}
19
+ #
20
+ # @return [Object,nil]
21
+ attr_accessor :completion_param
22
+
23
+ # A callback to be called when this waiter is notified of a packet's
24
+ # arrival. If not nil, this will be called with the response packet as first
25
+ # parameter and {#completion_param} as the second.
26
+ #
27
+ # @return [Proc,nil]
28
+ attr_accessor :completion_routine
29
+
30
+ # @return [ConditionVariable]
31
+ attr_accessor :cond
32
+
33
+ # @return [Mutex]
34
+ attr_accessor :mutex
35
+
36
+ # @return [Packet]
37
+ attr_accessor :response
38
+
39
+ # @return [Fixnum] request ID to wait for
40
+ attr_accessor :rid
41
+
18
42
  #
19
43
  # Initializes a response waiter instance for the supplied request
20
44
  # identifier.
@@ -27,7 +51,8 @@ class PacketResponseWaiter
27
51
  self.completion_routine = completion_routine
28
52
  self.completion_param = completion_param
29
53
  else
30
- self.done = false
54
+ self.mutex = Mutex.new
55
+ self.cond = ConditionVariable.new
31
56
  end
32
57
  end
33
58
 
@@ -42,41 +67,37 @@ class PacketResponseWaiter
42
67
  #
43
68
  # Notifies the waiter that the supplied response packet has arrived.
44
69
  #
70
+ # @param response [Packet]
71
+ # @return [void]
45
72
  def notify(response)
46
- self.response = response
47
-
48
73
  if (self.completion_routine)
74
+ self.response = response
49
75
  self.completion_routine.call(response, self.completion_param)
50
76
  else
51
- self.done = true
77
+ self.mutex.synchronize do
78
+ self.response = response
79
+ self.cond.signal
80
+ end
52
81
  end
53
82
  end
54
83
 
55
84
  #
56
- # Waits for a given time interval for the response packet to arrive.
57
- # If the interval is -1 we can wait forever.
85
+ # Wait for a given time interval for the response packet to arrive.
58
86
  #
87
+ # @param interval [Fixnum,nil] number of seconds to wait, or nil to wait
88
+ # forever
89
+ # @return [Packet,nil] the response, or nil if the interval elapsed before
90
+ # receiving one
59
91
  def wait(interval)
60
- if( interval and interval == -1 )
61
- while(not self.done)
62
- ::IO.select(nil, nil, nil, 0.1)
63
- end
64
- else
65
- begin
66
- Timeout.timeout(interval) {
67
- while(not self.done)
68
- ::IO.select(nil, nil, nil, 0.1)
69
- end
70
- }
71
- rescue Timeout::Error
72
- self.response = nil
92
+ interval = nil if interval and interval == -1
93
+ self.mutex.synchronize do
94
+ if self.response.nil?
95
+ self.cond.wait(self.mutex, interval)
73
96
  end
74
97
  end
75
98
  return self.response
76
99
  end
77
100
 
78
- attr_accessor :rid, :done, :response # :nodoc:
79
- attr_accessor :completion_routine, :completion_param # :nodoc:
80
101
  end
81
102
 
82
103
  end; end; end
@@ -29,7 +29,9 @@ class Console::CommandDispatcher::Android
29
29
  'device_shutdown' => 'Shutdown device',
30
30
  'send_sms' => 'Sends SMS from target session',
31
31
  'wlan_geolocate' => 'Get current lat-long using WLAN information',
32
- 'interval_collect' => 'Manage interval collection capabilities'
32
+ 'interval_collect' => 'Manage interval collection capabilities',
33
+ 'activity_start' => 'Start an Android activity from a Uri string',
34
+ 'set_audio_mode' => 'Set Ringer Mode'
33
35
  }
34
36
 
35
37
  reqs = {
@@ -41,7 +43,9 @@ class Console::CommandDispatcher::Android
41
43
  'device_shutdown' => ['device_shutdown'],
42
44
  'send_sms' => ['send_sms'],
43
45
  'wlan_geolocate' => ['wlan_geolocate'],
44
- 'interval_collect' => ['interval_collect']
46
+ 'interval_collect' => ['interval_collect'],
47
+ 'activity_start' => ['activity_start'],
48
+ 'set_audio_mode' => ['set_audio_mode']
45
49
  }
46
50
 
47
51
  # Ensure any requirements of the command are met
@@ -151,6 +155,36 @@ class Console::CommandDispatcher::Android
151
155
  end
152
156
  end
153
157
 
158
+ def cmd_set_audio_mode(*args)
159
+ help = false
160
+ mode = 1
161
+ set_audio_mode_opts = Rex::Parser::Arguments.new(
162
+ '-h' => [ false, "Help Banner" ],
163
+ '-m' => [ true, "Set Mode - (0 - Off, 1 - Normal, 2 - Max) (Default: '#{mode}')"]
164
+ )
165
+
166
+ set_audio_mode_opts.parse(args) do |opt, _idx, val|
167
+ case opt
168
+ when '-h'
169
+ help = true
170
+ when '-m'
171
+ mode = val.to_i
172
+ else
173
+ help = true
174
+ end
175
+ end
176
+
177
+ if help || mode < 0 || mode > 2
178
+ print_line('Usage: set_audio_mode [options]')
179
+ print_line('Set Ringer mode.')
180
+ print_line(set_audio_mode_opts.usage)
181
+ return
182
+ end
183
+
184
+ client.android.set_audio_mode(mode)
185
+ print_status("Ringer mode was changed to #{mode}!")
186
+ end
187
+
154
188
  def cmd_dump_sms(*args)
155
189
  path = "sms_dump_#{Time.new.strftime('%Y%m%d%H%M%S')}.txt"
156
190
  dump_sms_opts = Rex::Parser::Arguments.new(
@@ -457,7 +491,7 @@ class Console::CommandDispatcher::Android
457
491
  end
458
492
  end
459
493
 
460
- if dest.blank? || body.blank?
494
+ if dest.to_s.empty? || body.to_s.empty?
461
495
  print_error("You must enter both a destination address -d and the SMS text body -t")
462
496
  print_error('e.g. send_sms -d +351961234567 -t "GREETINGS PROFESSOR FALKEN."')
463
497
  print_line(send_sms_opts.usage)
@@ -509,7 +543,7 @@ class Console::CommandDispatcher::Android
509
543
  wlan_list << [mac, ssid, ss.to_s]
510
544
  end
511
545
 
512
- if wlan_list.blank?
546
+ if wlan_list.to_s.empty?
513
547
  print_error("Unable to enumerate wireless networks from the target. Wireless may not be present or enabled.")
514
548
  return
515
549
  end
@@ -528,6 +562,22 @@ class Console::CommandDispatcher::Android
528
562
  end
529
563
  end
530
564
 
565
+ def cmd_activity_start(*args)
566
+ if (args.length < 1)
567
+ print_line("Usage: activity_start <uri>\n")
568
+ print_line("Start an Android activity from a uri")
569
+ return
570
+ end
571
+
572
+ uri = args[0]
573
+ result = client.android.activity_start(uri)
574
+ if result.nil?
575
+ print_status("Intent started")
576
+ else
577
+ print_error("Error: #{result}")
578
+ end
579
+ end
580
+
531
581
  #
532
582
  # Name for this dispatcher
533
583
  #
@@ -816,16 +816,18 @@ class Console::CommandDispatcher::Core
816
816
  end
817
817
 
818
818
  @@migrate_opts = Rex::Parser::Arguments.new(
819
- '-p' => [true, 'Writable path - Linux only (eg. /tmp).'],
820
- '-t' => [true, 'The number of seconds to wait for migration to finish (default: 60).'],
821
- '-h' => [false, 'Help menu.']
819
+ '-P' => [true, 'PID to migrate to.'],
820
+ '-N' => [true, 'Process name to migrate to.'],
821
+ '-p' => [true, 'Writable path - Linux only (eg. /tmp).'],
822
+ '-t' => [true, 'The number of seconds to wait for migration to finish (default: 60).'],
823
+ '-h' => [false, 'Help menu.']
822
824
  )
823
825
 
824
826
  def cmd_migrate_help
825
827
  if client.platform =~ /linux/
826
- print_line('Usage: migrate <pid> [-p writable_path] [-t timeout]')
828
+ print_line('Usage: migrate <<pid> | -P <pid> | -N <name>> [-p writable_path] [-t timeout]')
827
829
  else
828
- print_line('Usage: migrate <pid> [-t timeout]')
830
+ print_line('Usage: migrate <<pid> | -P <pid> | -N <name>> [-t timeout]')
829
831
  end
830
832
  print_line
831
833
  print_line('Migrates the server instance to another process.')
@@ -840,29 +842,53 @@ class Console::CommandDispatcher::Core
840
842
  # platforms a path for the unix domain socket used for IPC.
841
843
  # @return [void]
842
844
  def cmd_migrate(*args)
843
- if args.length == 0 || args.include?('-h')
845
+ if args.length == 0 || args.any? { |arg| %w(-h --pid --name).include? arg }
844
846
  cmd_migrate_help
845
847
  return true
846
848
  end
847
849
 
848
- pid = args[0].to_i
849
- if pid == 0
850
- print_error('A process ID must be specified, not a process name')
851
- return
852
- end
853
-
850
+ pid = nil
854
851
  writable_dir = nil
855
852
  opts = {
856
853
  timeout: nil
857
854
  }
858
855
 
859
- @@transport_opts.parse(args) do |opt, idx, val|
856
+ @@migrate_opts.parse(args) do |opt, idx, val|
860
857
  case opt
861
858
  when '-t'
862
859
  opts[:timeout] = val.to_i
863
860
  when '-p'
864
861
  writable_dir = val
862
+ when '-P'
863
+ unless val =~ /^\d+$/
864
+ print_error("Not a PID: #{val}")
865
+ return
866
+ end
867
+ pid = val.to_i
868
+ when '-N'
869
+ if val.to_s.empty?
870
+ print_error("No process name provided")
871
+ return
872
+ end
873
+ # this will migrate to the first process with a matching name
874
+ unless (process = client.sys.process.processes.find { |p| p['name'] == val })
875
+ print_error("Could not find process name #{val}")
876
+ return
877
+ end
878
+ pid = process['pid']
879
+ end
880
+ end
881
+
882
+ unless pid
883
+ unless (pid = args.first)
884
+ print_error('A process ID or name argument must be provided')
885
+ return
886
+ end
887
+ unless pid =~ /^\d+$/
888
+ print_error("Not a PID: #{pid}")
889
+ return
865
890
  end
891
+ pid = pid.to_i
866
892
  end
867
893
 
868
894
  begin
@@ -52,6 +52,7 @@ class Console::CommandDispatcher::Stdapi::Fs
52
52
  'cat' => 'Read the contents of a file to the screen',
53
53
  'cd' => 'Change directory',
54
54
  'del' => 'Delete the specified file',
55
+ 'dir' => 'List files (alias for ls)',
55
56
  'download' => 'Download a file or directory',
56
57
  'edit' => 'Edit a file',
57
58
  'getlwd' => 'Print local working directory',
@@ -73,6 +74,7 @@ class Console::CommandDispatcher::Stdapi::Fs
73
74
  'cat' => [],
74
75
  'cd' => ['stdapi_fs_chdir'],
75
76
  'del' => ['stdapi_fs_rm'],
77
+ 'dir' => ['stdapi_fs_stat', 'stdapi_fs_ls'],
76
78
  'download' => [],
77
79
  'edit' => [],
78
80
  'getlwd' => [],
@@ -598,6 +600,12 @@ class Console::CommandDispatcher::Stdapi::Fs
598
600
  return true
599
601
  end
600
602
 
603
+ #
604
+ # Alias the ls command to dir, for those of us who have windows muscle-memory
605
+ #
606
+ alias cmd_dir cmd_ls
607
+
608
+
601
609
  #
602
610
  # Make one or more directory.
603
611
  #
@@ -0,0 +1,7 @@
1
+ # -*- coding: binary -*-
2
+ #
3
+ # Support for the ADB android debugging protocol
4
+ #
5
+
6
+ require 'rex/proto/adb/client'
7
+ require 'rex/proto/adb/message'
@@ -0,0 +1,39 @@
1
+ # -*- coding: binary -*-
2
+
3
+ ##
4
+ # ADB protocol support
5
+ ##
6
+
7
+ require 'rex/proto/adb/message'
8
+
9
+ module Rex
10
+ module Proto
11
+ module ADB
12
+
13
+ class Client
14
+
15
+ def initialize(sock, opts = {})
16
+ @sock = sock
17
+ @opts = opts
18
+ @local_id_counter = 0x0a
19
+ end
20
+
21
+ def connect
22
+ ADB::Message::Connect.new.send_recv(@sock)
23
+ end
24
+
25
+ def exec_cmd(cmd)
26
+ local_id = @local_id_counter += 1
27
+ response = ADB::Message::Open.new(local_id, "shell:"+cmd).send_recv(@sock)
28
+ ADB::Message::Close.new(local_id, response.arg0).send_recv(@sock)
29
+ end
30
+
31
+ def read_message
32
+ ADB::Message.read(@sock)
33
+ end
34
+
35
+ end # Client
36
+
37
+ end # ADB
38
+ end # Proto
39
+ end # Rex
@@ -0,0 +1,164 @@
1
+ # -*- coding: binary -*-
2
+
3
+ ##
4
+ # ADB protocol support
5
+ ##
6
+
7
+ module Rex
8
+ module Proto
9
+ module ADB
10
+
11
+ # A Message for the ADB protocol. For documentation see:
12
+ # https://android.googlesource.com/platform/system/core/+/master/adb/protocol.txt
13
+ class Message
14
+
15
+ WORD_WIDTH = 4 # bytes
16
+ WORD_PACK = 'L<'
17
+
18
+ attr_accessor :command
19
+ attr_accessor :arg0
20
+ attr_accessor :arg1
21
+ attr_accessor :data
22
+
23
+ def initialize(arg0, arg1, data)
24
+ self.command = self.class::COMMAND if defined?(self.class::COMMAND)
25
+ self.arg0 = arg0
26
+ self.arg1 = arg1
27
+ self.data = data + "\0"
28
+ end
29
+
30
+ def data_check
31
+ # this check is implemented in adb/transport.cpp, in the send_packet method.
32
+ # it is not crc32 as the docs make it appear, it is just a 32bit sum.
33
+ data.bytes.inject(&:+) & 0xffffffff
34
+ end
35
+
36
+ def magic
37
+ command_word ^ 0xffffffff
38
+ end
39
+
40
+ def command_word
41
+ command.unpack(WORD_PACK)[0]
42
+ end
43
+
44
+ def send_recv(socket)
45
+ socket.print self.serialize
46
+ Message.read socket
47
+ end
48
+
49
+ def serialize
50
+ [
51
+ command_word,
52
+ arg0,
53
+ arg1,
54
+ data.bytes.length,
55
+ data_check,
56
+ magic
57
+ ].pack(WORD_PACK+'*') + data
58
+ end
59
+
60
+ def to_s
61
+ [
62
+ "command=#{command}",
63
+ "arg0=0x#{arg0.to_s(16)}",
64
+ "arg1=0x#{arg1.to_s(16)}",
65
+ "data=#{data}"
66
+ ].join("\n")
67
+ end
68
+
69
+ def self.read(socket)
70
+ header = socket.recvfrom(6 * WORD_WIDTH)[0]
71
+ command = header[0, WORD_WIDTH]
72
+ arg0 = header[WORD_WIDTH, WORD_WIDTH].unpack(WORD_PACK)[0]
73
+ arg1 = header[WORD_WIDTH*2, WORD_WIDTH].unpack(WORD_PACK)[0]
74
+ payload_len = header[WORD_WIDTH*3, WORD_WIDTH].unpack(WORD_PACK)[0]
75
+ payload = socket.recvfrom(payload_len)[0]
76
+
77
+ klass = MESSAGE_TYPES.find { |klass| klass::COMMAND == command }
78
+ if klass.nil?
79
+ raise "Invalid adb command: #{command}"
80
+ end
81
+
82
+ message = klass.allocate
83
+ message.command = command
84
+ message.arg0 = arg0
85
+ message.arg1 = arg1
86
+ message.data = payload
87
+ message
88
+ end
89
+
90
+ #
91
+ # Subclasses inside Message:: namespace for specific message types
92
+ #
93
+
94
+ class Connect < Message
95
+ COMMAND = "CNXN"
96
+ DEFAULT_VERSION = 0x01000000
97
+ DEFAULT_MAXDATA = 4096
98
+ DEFAULT_IDENTITY = "host::"
99
+
100
+ def initialize(version=DEFAULT_VERSION,
101
+ maxdata=DEFAULT_MAXDATA,
102
+ system_identity_string=DEFAULT_IDENTITY)
103
+ super
104
+ end
105
+ end
106
+
107
+ class Auth < Message
108
+ COMMAND = "AUTH"
109
+ TYPE_TOKEN = 1
110
+ TYPE_SIGNATURE = 2
111
+
112
+ def initialize(type, data)
113
+ super(type, 0, data)
114
+ end
115
+ end
116
+
117
+ class Open < Message
118
+ COMMAND = "OPEN"
119
+
120
+ def initialize(local_id, destination)
121
+ super(local_id, 0, destination)
122
+ end
123
+ end
124
+
125
+ class Ready < Message
126
+ COMMAND = "OKAY"
127
+
128
+ def initialize(local_id, remote_id)
129
+ super(local_id, remote_id, "")
130
+ end
131
+ end
132
+
133
+ class Write < Message
134
+ COMMAND = "WRTE"
135
+
136
+ def initialize(local_id, remote_id, data)
137
+ super
138
+ end
139
+ end
140
+
141
+ class Close < Message
142
+ COMMAND = "CLSE"
143
+
144
+ def initialize(local_id, remote_id)
145
+ super(local_id, remote_id, "")
146
+ end
147
+ end
148
+
149
+ class Sync < Message
150
+ COMMAND = "SYNC"
151
+
152
+ def initialize(online, sequence)
153
+ super(online, sequence, "")
154
+ end
155
+ end
156
+
157
+ # Avoid a dependency on Rails's nice Class#subclasses
158
+ MESSAGE_TYPES = [Connect, Auth, Open, Ready, Write, Close, Sync]
159
+
160
+ end # Message
161
+
162
+ end # ADB
163
+ end # Proto
164
+ end # Rex