ruby_smb 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c76e06c7e09d56565d9253523f519ac12eccc193201b8f4dcd99a8ed07b37991
4
- data.tar.gz: b533650ae3c9c16e75f2c5b987f53055894f0a99e87151dc5838922882d52ade
3
+ metadata.gz: a683fe9443f70b1f4e7dc98d02d7f4deaf785ae94097752696c516977bc3a36a
4
+ data.tar.gz: 5e74a2b2daaedb9b2f096ef05fcd5465a9caa1b9672af6e42d13f18b70e47110
5
5
  SHA512:
6
- metadata.gz: 82cbd9940e99aea529d23046e26b05f92bcfff3e03ee8df852b0c44f7b50ef517e4549f3e46b6890f55f0c5fc34e624821701cea6b807c008d1cbb03f0e4f242
7
- data.tar.gz: 7d91fa41048597a8c376af79b32374588ffdb79b114bacfb1b43e482f22298f6439fe92a13753abffeb7b329ba3f09f4131a23bf8e63d62c5f9f85da40c5f5e0
6
+ metadata.gz: efaaf45fb9fb49bd37a3f45681800f26437efdd76bd6b06ee763768c3674292fe3e7bc35946a489300a3d696a7f060cad2802335aabfd766dd6bc8dd9f503fdd
7
+ data.tar.gz: cef65fae806b5b6bce656ef799f5ca4376a0cc71e1ad5746ddaf44898652580ce990d728960b2a4767898d1e7ebcb8e12d997919123b4cbc4a2d113c7db57822
Binary file
data.tar.gz.sig CHANGED
@@ -1 +1 @@
1
- Zp����xD�&Ǻ�(�T�q�Q6Q��h_࠘4m��ң��1Q��S�"B'��M���=�g_|i�ЈJz�����������MN-��s��O��&窓�Ӿ�~��*El�aA<>��F�%�_�?�����n1R�~��z
1
+ ���}�T�eX��*|�#VȕHAp��&n����� �I�u� rRႠ��� ��8�c��`鏐K���y�(�{Y��K9…9��†�6�J���_*����� ���G�"�Y �&3="��}<�P��ݘf����Ld�U�Rڨ^O�@����Ab��Մ�Lӊ�������<������o�ǿ�_��q���Ɩ])�����=>z?��\h8�բzV�����ߨ����~
@@ -216,10 +216,10 @@ module RubySMB
216
216
  # @return [String]
217
217
  attr_accessor :server_encryption_key
218
218
 
219
- # Whether or not encryption is required (SMB 3.x)
220
- # @!attribute [rw] encryption_required
219
+ # Whether or not the whole session needs to be encrypted (SMB 3.x)
220
+ # @!attribute [rw] session_encrypt_data
221
221
  # @return [Boolean]
222
- attr_accessor :encryption_required
222
+ attr_accessor :session_encrypt_data
223
223
 
224
224
  # The encryption algorithms supported by the server (SMB 3.x).
225
225
  # @!attribute [rw] server_encryption_algorithms
@@ -233,6 +233,25 @@ module RubySMB
233
233
  # (constants defined in RubySMB::SMB2::CompressionCapabilities)
234
234
  attr_accessor :server_compression_algorithms
235
235
 
236
+ # The GUID of the server (SMB 2.x and 3.x).
237
+ # @!attribute [rw] server_guid
238
+ # @return [String]
239
+ attr_accessor :server_guid
240
+
241
+ # The server's start time if it is reported as part of the negotiation
242
+ # process (SMB 2.x and 3.x). This value is nil if the server does not report
243
+ # it (reports a value of 0).
244
+ # @!attribute [rw] server_start_time
245
+ # @return [Time] the time that the server reports that it was started at
246
+ attr_accessor :server_start_time
247
+
248
+ # The server's current time if it is reported as part of the negotiation
249
+ # process (SMB 2.x and 3.x). This value is nil if the server does not report
250
+ # it (reports a value of 0).
251
+ # @!attribute [rw] server_system_time
252
+ # @return [Time] the time that the server reports as current
253
+ attr_accessor :server_system_time
254
+
236
255
  # The SMB version that has been successfully negotiated. This value is only
237
256
  # set after the NEGOTIATE handshake has been performed.
238
257
  # @!attribute [rw] negotiated_smb_version
@@ -268,12 +287,13 @@ module RubySMB
268
287
  @server_max_transact_size = RubySMB::SMB2::File::MAX_PACKET_SIZE
269
288
 
270
289
  # SMB 3.x options
271
- @encryption_required = always_encrypt
290
+ @session_encrypt_data = always_encrypt
272
291
 
273
292
  negotiate_version_flag = 0x02000000
274
293
  flags = Net::NTLM::Client::DEFAULT_FLAGS |
275
294
  Net::NTLM::FLAGS[:TARGET_INFO] |
276
- negotiate_version_flag
295
+ negotiate_version_flag ^
296
+ Net::NTLM::FLAGS[:OEM]
277
297
 
278
298
  @ntlm_client = Net::NTLM::Client.new(
279
299
  @username,
@@ -347,7 +367,8 @@ module RubySMB
347
367
  negotiate_version_flag = 0x02000000
348
368
  flags = Net::NTLM::Client::DEFAULT_FLAGS |
349
369
  Net::NTLM::FLAGS[:TARGET_INFO] |
350
- negotiate_version_flag
370
+ negotiate_version_flag ^
371
+ Net::NTLM::FLAGS[:OEM]
351
372
 
352
373
  @ntlm_client = Net::NTLM::Client.new(
353
374
  @username,
@@ -398,6 +419,9 @@ module RubySMB
398
419
  # It will also sign the packet if neccessary.
399
420
  #
400
421
  # @param packet [RubySMB::GenericPacket] the request to be sent
422
+ # @param encrypt [Boolean] true if encryption has to be enabled for this transaction
423
+ # (note that if @session_encrypt_data is set, encryption will be enabled
424
+ # regardless of this parameter value)
401
425
  # @return [String] the raw response data received
402
426
  def send_recv(packet, encrypt: false)
403
427
  version = packet.packet_smb_version
@@ -419,7 +443,7 @@ module RubySMB
419
443
  packet = packet
420
444
  end
421
445
 
422
- if can_be_encrypted?(packet) && encryption_supported? && (@encryption_required || encrypt)
446
+ if can_be_encrypted?(packet) && encryption_supported? && (@session_encrypt_data || encrypt)
423
447
  send_encrypt(packet)
424
448
  raw_response = recv_encrypt
425
449
  loop do
@@ -454,18 +478,19 @@ module RubySMB
454
478
  smb2_header.flags.async_command == 1
455
479
  end
456
480
 
457
- # Check if the request packet can be encrypted. Per the SMB spec,
481
+ # Check if the request packet can be encrypted. Per the SMB2 spec,
458
482
  # SessionSetupRequest and NegotiateRequest must not be encrypted.
459
483
  #
460
484
  # @param packet [RubySMB::GenericPacket] the request packet
461
485
  # @return [Boolean] true if the packet can be encrypted
462
486
  def can_be_encrypted?(packet)
487
+ return false if packet.packet_smb_version == 'SMB1'
463
488
  [RubySMB::SMB2::Packet::SessionSetupRequest, RubySMB::SMB2::Packet::NegotiateRequest].none? do |klass|
464
489
  packet.is_a?(klass)
465
490
  end
466
491
  end
467
492
 
468
- # Check if the current dialect support encryption.
493
+ # Check if the current dialect supports encryption.
469
494
  #
470
495
  # @return [Boolean] true if encryption is supported
471
496
  def encryption_supported?
@@ -486,7 +511,13 @@ module RubySMB
486
511
  #
487
512
  # @return [String] the raw unencrypted packet
488
513
  def recv_encrypt
489
- raw_response = dispatcher.recv_packet
514
+ begin
515
+ raw_response = dispatcher.recv_packet
516
+ rescue RubySMB::Error::CommunicationError => e
517
+ raise RubySMB::Error::EncryptionError, "Communication error with the "\
518
+ "remote host: #{e.message}. The server supports encryption but was "\
519
+ "not able to handle the encrypted request."
520
+ end
490
521
  begin
491
522
  transform_response = RubySMB::SMB2::Packet::TransformHeader.read(raw_response)
492
523
  rescue IOError
@@ -216,8 +216,8 @@ module RubySMB
216
216
  raw = smb2_ntlmssp_authenticate(type3_message, @session_id)
217
217
  response = smb2_ntlmssp_final_packet(raw)
218
218
 
219
- if @smb3 && !@encryption_required && response.session_flags.encrypt_data == 1
220
- @encryption_required = true
219
+ if @smb3 && !@session_encrypt_data && response.session_flags.encrypt_data == 1
220
+ @session_encrypt_data = true
221
221
  end
222
222
  ######
223
223
  # DEBUG
@@ -24,6 +24,7 @@ module RubySMB
24
24
  when '0x0311'
25
25
  parse_smb3_encryption_data(request_packet, response_packet)
26
26
  end
27
+
27
28
  # If the response contains the SMB2 wildcard revision number dialect;
28
29
  # it indicates that the server implements SMB 2.1 or future dialect
29
30
  # revisions and expects the client to send a subsequent SMB2 Negotiate
@@ -128,6 +129,8 @@ module RubySMB
128
129
  unless packet.dialect_revision.to_i == 0x02ff
129
130
  self.smb2 = packet.dialect_revision.to_i >= 0x0200 && packet.dialect_revision.to_i < 0x0300
130
131
  self.smb3 = packet.dialect_revision.to_i >= 0x0300 && packet.dialect_revision.to_i < 0x0400
132
+ # Only enable session encryption if the server supports it
133
+ @session_encrypt_data = self.smb3 && @session_encrypt_data && packet.capabilities.encryption == 1
131
134
  end
132
135
  self.signing_required = packet.security_mode.signing_required == 1 if self.smb2 || self.smb3
133
136
  self.dialect = "0x%04x" % packet.dialect_revision
@@ -137,6 +140,9 @@ module RubySMB
137
140
  # This value is used in SMB1 only but calculate a valid value anyway
138
141
  self.server_max_buffer_size = [self.server_max_read_size, self.server_max_write_size, self.server_max_transact_size].min
139
142
  self.negotiated_smb_version = self.smb2 ? 2 : 3
143
+ self.server_guid = packet.server_guid
144
+ self.server_start_time = packet.server_start_time.to_time if packet.server_start_time != 0
145
+ self.server_system_time = packet.system_time.to_time if packet.system_time != 0
140
146
  return "SMB#{self.negotiated_smb_version}"
141
147
  else
142
148
  error = 'Unable to negotiate with remote host'
@@ -198,6 +204,12 @@ module RubySMB
198
204
  # while being guaranteed to work with any modern Windows system. We can get more sophisticated
199
205
  # with switching this on and off at a later date if the need arises.
200
206
  packet.smb_header.flags2.extended_security = 1
207
+ # Recent Mac OS X requires the unicode flag to be set on the Negotiate
208
+ # SMB Header request, even if this packet does not contain string fields
209
+ # (see Flags2 SMB_FLAGS2_UNICODE definition in "2.2.3.1 The SMB Header"
210
+ # documentation:
211
+ # https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/69a29f73-de0c-45a6-a1aa-8ceeea42217f
212
+ packet.smb_header.flags2.unicode = 1
201
213
  # There is no real good reason to ever send an SMB1 Negotiate packet
202
214
  # to Negotiate strictly SMB2, but the protocol WILL support it
203
215
  packet.add_dialect(SMB1_DIALECT_SMB1_DEFAULT) if smb1
@@ -61,13 +61,14 @@ module RubySMB
61
61
  # which are assumed to be the NetBiosSessionService header.
62
62
  # @raise [RubySMB::Error::CommunicationError] if the read timeout expires or an error occurs when reading the socket
63
63
  def recv_packet(full_response: false)
64
+ raise RubySMB::Error::CommunicationError, 'Connection has already been closed' if @tcp_socket.closed?
64
65
  if IO.select([@tcp_socket], nil, nil, @read_timeout).nil?
65
66
  raise RubySMB::Error::CommunicationError, "Read timeout expired when reading from the Socket (timeout=#{@read_timeout})"
66
67
  end
67
68
 
68
69
  begin
69
70
  nbss_data = @tcp_socket.read(4)
70
- raise IOError if nbss_data.nil?
71
+ raise RubySMB::Error::CommunicationError, 'Socket read returned nil' if nbss_data.nil?
71
72
  nbss_header = RubySMB::Nbss::SessionHeader.read(nbss_data)
72
73
  rescue IOError
73
74
  raise ::RubySMB::Error::NetBiosSessionService, 'NBSS Header is missing'
@@ -123,6 +123,15 @@ module RubySMB
123
123
  raw_response = @client.send_recv(nt_create_andx_request)
124
124
  response = RubySMB::SMB1::Packet::NtCreateAndxResponse.read(raw_response)
125
125
  unless response.valid?
126
+ if response.is_a?(RubySMB::SMB1::Packet::EmptyPacket) &&
127
+ response.smb_header.protocol == RubySMB::SMB1::SMB_PROTOCOL_ID &&
128
+ response.smb_header.command == response.original_command
129
+ raise RubySMB::Error::InvalidPacket.new(
130
+ 'The response seems to be an SMB1 NtCreateAndxResponse but an '\
131
+ 'error occurs while parsing it. It is probably missing the '\
132
+ 'required extended information.'
133
+ )
134
+ end
126
135
  raise RubySMB::Error::InvalidPacket.new(
127
136
  expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
128
137
  expected_cmd: RubySMB::SMB1::Packet::NtCreateAndxResponse::COMMAND,
@@ -52,10 +52,10 @@ module RubySMB
52
52
  # @return [RubySMB::SMB2::Tree]
53
53
  attr_accessor :tree
54
54
 
55
- # Whether or not encryption is required (SMB 3.x)
56
- # @!attribute [rw] encryption_required
55
+ # Whether or not the share associated with this tree connect needs to be encrypted (SMB 3.x)
56
+ # @!attribute [rw] tree_connect_encrypt_data
57
57
  # @return [Boolean]
58
- attr_accessor :encryption_required
58
+ attr_accessor :tree_connect_encrypt_data
59
59
 
60
60
  def initialize(tree:, response:, name:, encrypt: false)
61
61
  raise ArgumentError, 'No Tree Provided' if tree.nil?
@@ -71,7 +71,7 @@ module RubySMB
71
71
  @last_write = response.last_write.to_datetime
72
72
  @size = response.end_of_file
73
73
  @size_on_disk = response.allocation_size
74
- @encryption_required = encrypt
74
+ @tree_connect_encrypt_data = encrypt
75
75
  end
76
76
 
77
77
  # Appends the supplied data to the end of the file.
@@ -89,7 +89,7 @@ module RubySMB
89
89
  # @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
90
90
  def close
91
91
  close_request = set_header_fields(RubySMB::SMB2::Packet::CloseRequest.new)
92
- raw_response = tree.client.send_recv(close_request, encrypt: @encryption_required)
92
+ raw_response = tree.client.send_recv(close_request, encrypt: @tree_connect_encrypt_data)
93
93
  response = RubySMB::SMB2::Packet::CloseResponse.read(raw_response)
94
94
  unless response.valid?
95
95
  raise RubySMB::Error::InvalidPacket.new(
@@ -122,7 +122,7 @@ module RubySMB
122
122
  end
123
123
 
124
124
  read_request = read_packet(read_length: atomic_read_size, offset: offset)
125
- raw_response = tree.client.send_recv(read_request, encrypt: @encryption_required)
125
+ raw_response = tree.client.send_recv(read_request, encrypt: @tree_connect_encrypt_data)
126
126
  response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
127
127
  unless response.valid?
128
128
  raise RubySMB::Error::InvalidPacket.new(
@@ -145,7 +145,7 @@ module RubySMB
145
145
  atomic_read_size = remaining_bytes if remaining_bytes < tree.client.server_max_read_size
146
146
 
147
147
  read_request = read_packet(read_length: atomic_read_size, offset: offset)
148
- raw_response = tree.client.send_recv(read_request, encrypt: @encryption_required)
148
+ raw_response = tree.client.send_recv(read_request, encrypt: @tree_connect_encrypt_data)
149
149
  response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
150
150
  unless response.valid?
151
151
  raise RubySMB::Error::InvalidPacket.new(
@@ -179,7 +179,7 @@ module RubySMB
179
179
 
180
180
  def send_recv_read(read_length: 0, offset: 0)
181
181
  read_request = read_packet(read_length: read_length, offset: offset)
182
- raw_response = tree.client.send_recv(read_request, encrypt: @encryption_required)
182
+ raw_response = tree.client.send_recv(read_request, encrypt: @tree_connect_encrypt_data)
183
183
  response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
184
184
  unless response.valid?
185
185
  raise RubySMB::Error::InvalidPacket.new(
@@ -200,7 +200,7 @@ module RubySMB
200
200
  # @return [WindowsError::ErrorCode] the NTStatus Response code
201
201
  # @raise [RubySMB::Error::InvalidPacket] if the response is not a SetInfoResponse packet
202
202
  def delete
203
- raw_response = tree.client.send_recv(delete_packet, encrypt: @encryption_required)
203
+ raw_response = tree.client.send_recv(delete_packet, encrypt: @tree_connect_encrypt_data)
204
204
  response = RubySMB::SMB2::Packet::SetInfoResponse.read(raw_response)
205
205
  unless response.valid?
206
206
  raise RubySMB::Error::InvalidPacket.new(
@@ -250,7 +250,7 @@ module RubySMB
250
250
 
251
251
  while buffer.length > 0 do
252
252
  write_request = write_packet(data: buffer.slice!(0,atomic_write_size), offset: offset)
253
- raw_response = tree.client.send_recv(write_request, encrypt: @encryption_required)
253
+ raw_response = tree.client.send_recv(write_request, encrypt: @tree_connect_encrypt_data)
254
254
  response = RubySMB::SMB2::Packet::WriteResponse.read(raw_response)
255
255
  unless response.valid?
256
256
  raise RubySMB::Error::InvalidPacket.new(
@@ -283,7 +283,7 @@ module RubySMB
283
283
 
284
284
  def send_recv_write(data:'', offset: 0)
285
285
  pkt = write_packet(data: data, offset: offset)
286
- raw_response = tree.client.send_recv(pkt, encrypt: @encryption_required)
286
+ raw_response = tree.client.send_recv(pkt, encrypt: @tree_connect_encrypt_data)
287
287
  response = RubySMB::SMB2::Packet::WriteResponse.read(raw_response)
288
288
  unless response.valid?
289
289
  raise RubySMB::Error::InvalidPacket.new(
@@ -305,7 +305,7 @@ module RubySMB
305
305
  # @return [WindowsError::ErrorCode] the NTStatus Response code
306
306
  # @raise [RubySMB::Error::InvalidPacket] if the response is not a SetInfoResponse packet
307
307
  def rename(new_file_name)
308
- raw_response = tree.client.send_recv(rename_packet(new_file_name), encrypt: @encryption_required)
308
+ raw_response = tree.client.send_recv(rename_packet(new_file_name), encrypt: @tree_connect_encrypt_data)
309
309
  response = RubySMB::SMB2::Packet::SetInfoResponse.read(raw_response)
310
310
  unless response.valid?
311
311
  raise RubySMB::Error::InvalidPacket.new(
@@ -15,7 +15,7 @@ module RubySMB
15
15
  uint16 :dialect_revision, label: 'Dialect Revision'
16
16
  uint16 :negotiate_context_count, label: 'Negotiate Context Count', initial_value: -> { negotiate_context_list.size }, onlyif: -> { has_negotiate_context? }
17
17
  uint16 :reserved1, label: 'Reserved', initial_value: 0, onlyif: -> { !has_negotiate_context? }
18
- string :server_guid, label: 'Server GUID', length: 16
18
+ string :server_guid, label: 'Server GUID', length: 16
19
19
  smb2_capabilities :capabilities
20
20
  uint32 :max_transact_size, label: 'Max Transaction Size'
21
21
  uint32 :max_read_size, label: 'Max Read Size'
@@ -23,10 +23,10 @@ module RubySMB
23
23
  # @return [Integer]
24
24
  attr_accessor :id
25
25
 
26
- # Whether or not encryption is required (SMB 3.x)
27
- # @!attribute [rw] encryption_required
26
+ # Whether or not the share associated with this tree connect needs to be encrypted (SMB 3.x)
27
+ # @!attribute [rw] tree_connect_encrypt_data
28
28
  # @return [Boolean]
29
- attr_accessor :encryption_required
29
+ attr_accessor :tree_connect_encrypt_data
30
30
 
31
31
  def initialize(client:, share:, response:, encrypt: false)
32
32
  @client = client
@@ -34,7 +34,7 @@ module RubySMB
34
34
  @id = response.smb2_header.tree_id
35
35
  @permissions = response.maximal_access
36
36
  @share_type = response.share_type
37
- @encryption_required = encrypt
37
+ @tree_connect_encrypt_data = encrypt
38
38
  end
39
39
 
40
40
  # Disconnects this Tree from the current session
@@ -44,7 +44,7 @@ module RubySMB
44
44
  def disconnect!
45
45
  request = RubySMB::SMB2::Packet::TreeDisconnectRequest.new
46
46
  request = set_header_fields(request)
47
- raw_response = client.send_recv(request, encrypt: @encryption_required)
47
+ raw_response = client.send_recv(request, encrypt: @tree_connect_encrypt_data)
48
48
  response = RubySMB::SMB2::Packet::TreeDisconnectResponse.read(raw_response)
49
49
  unless response.valid?
50
50
  raise RubySMB::Error::InvalidPacket.new(
@@ -102,7 +102,7 @@ module RubySMB
102
102
  create_request.create_disposition = disposition
103
103
  create_request.name = filename
104
104
 
105
- raw_response = client.send_recv(create_request, encrypt: @encryption_required)
105
+ raw_response = client.send_recv(create_request, encrypt: @tree_connect_encrypt_data)
106
106
  response = RubySMB::SMB2::Packet::CreateResponse.read(raw_response)
107
107
  unless response.valid?
108
108
  raise RubySMB::Error::InvalidPacket.new(
@@ -118,7 +118,7 @@ module RubySMB
118
118
 
119
119
  case @share_type
120
120
  when RubySMB::SMB2::Packet::TreeConnectResponse::SMB2_SHARE_TYPE_DISK
121
- RubySMB::SMB2::File.new(name: filename, tree: self, response: response, encrypt: @encryption_required)
121
+ RubySMB::SMB2::File.new(name: filename, tree: self, response: response, encrypt: @tree_connect_encrypt_data)
122
122
  when RubySMB::SMB2::Packet::TreeConnectResponse::SMB2_SHARE_TYPE_PIPE
123
123
  RubySMB::SMB2::Pipe.new(name: filename, tree: self, response: response)
124
124
  # when RubySMB::SMB2::TreeConnectResponse::SMB2_SHARE_TYPE_PRINT
@@ -154,7 +154,7 @@ module RubySMB
154
154
  files = []
155
155
 
156
156
  loop do
157
- response = client.send_recv(directory_request, encrypt: @encryption_required)
157
+ response = client.send_recv(directory_request, encrypt: @tree_connect_encrypt_data)
158
158
  directory_response = RubySMB::SMB2::Packet::QueryDirectoryResponse.read(response)
159
159
  unless directory_response.valid?
160
160
  raise RubySMB::Error::InvalidPacket.new(
@@ -199,7 +199,7 @@ module RubySMB
199
199
 
200
200
  create_request = open_directory_packet(directory: directory, disposition: disposition,
201
201
  impersonation: impersonation, read: read, write: write, delete: delete)
202
- raw_response = client.send_recv(create_request, encrypt: @encryption_required)
202
+ raw_response = client.send_recv(create_request, encrypt: @tree_connect_encrypt_data)
203
203
  response = RubySMB::SMB2::Packet::CreateResponse.read(raw_response)
204
204
  unless response.valid?
205
205
  raise RubySMB::Error::InvalidPacket.new(
@@ -1,3 +1,3 @@
1
1
  module RubySMB
2
- VERSION = '2.0.0'.freeze
2
+ VERSION = '2.0.1'.freeze
3
3
  end
@@ -46,7 +46,7 @@ RSpec.describe RubySMB::Client do
46
46
  it { is_expected.to respond_to :encryption_algorithm }
47
47
  it { is_expected.to respond_to :client_encryption_key }
48
48
  it { is_expected.to respond_to :server_encryption_key }
49
- it { is_expected.to respond_to :encryption_required }
49
+ it { is_expected.to respond_to :session_encrypt_data }
50
50
  it { is_expected.to respond_to :server_encryption_algorithms }
51
51
  it { is_expected.to respond_to :server_compression_algorithms }
52
52
  it { is_expected.to respond_to :negotiated_smb_version }
@@ -106,9 +106,9 @@ RSpec.describe RubySMB::Client do
106
106
  expect(client.password).to eq password
107
107
  end
108
108
 
109
- it 'sets the encryption_required attribute' do
109
+ it 'sets the session_encrypt_data attribute' do
110
110
  client = described_class.new(dispatcher, username: username, password: password, always_encrypt: true)
111
- expect(client.encryption_required).to eq true
111
+ expect(client.session_encrypt_data).to eq true
112
112
  end
113
113
 
114
114
  it 'creates an NTLM client' do
@@ -125,7 +125,7 @@ RSpec.describe RubySMB::Client do
125
125
  expect(opt[:workstation]).to eq(local_workstation)
126
126
  expect(opt[:domain]).to eq(domain)
127
127
  flags = Net::NTLM::Client::DEFAULT_FLAGS |
128
- Net::NTLM::FLAGS[:TARGET_INFO] | 0x02000000
128
+ Net::NTLM::FLAGS[:TARGET_INFO] | 0x02000000 ^ Net::NTLM::FLAGS[:OEM]
129
129
  expect(opt[:flags]).to eq(flags)
130
130
  end
131
131
 
@@ -191,11 +191,6 @@ RSpec.describe RubySMB::Client do
191
191
  allow(dispatcher).to receive(:recv_packet).and_return('A')
192
192
  end
193
193
 
194
- it 'checks the packet version' do
195
- expect(smb1_request).to receive(:packet_smb_version).and_call_original
196
- client.send_recv(smb1_request)
197
- end
198
-
199
194
  context 'when signing' do
200
195
  it 'calls #smb1_sign if it is an SMB1 packet' do
201
196
  expect(client).to receive(:smb1_sign).with(smb1_request).and_call_original
@@ -322,6 +317,11 @@ RSpec.describe RubySMB::Client do
322
317
  expect(client.can_be_encrypted?(packet)).to be true
323
318
  end
324
319
 
320
+ it 'returns false if it is an SMB1 packet' do
321
+ packet = RubySMB::SMB1::Packet::LogoffRequest.new
322
+ expect(client.can_be_encrypted?(packet)).to be false
323
+ end
324
+
325
325
  [RubySMB::SMB2::Packet::SessionSetupRequest, RubySMB::SMB2::Packet::NegotiateRequest].each do |klass|
326
326
  it "returns false if the packet is a #{klass}" do
327
327
  packet = klass.new
@@ -385,6 +385,15 @@ RSpec.describe RubySMB::Client do
385
385
  expect(dispatcher).to have_received(:recv_packet)
386
386
  end
387
387
 
388
+ it 'raises an EncryptionError exception if an error occurs while receiving the response' do
389
+ allow(dispatcher).to receive(:recv_packet).and_raise(RubySMB::Error::CommunicationError)
390
+ expect { client.recv_encrypt }.to raise_error(
391
+ RubySMB::Error::EncryptionError,
392
+ 'Communication error with the remote host: RubySMB::Error::CommunicationError. '\
393
+ 'The server supports encryption but was not able to handle the encrypted request.'
394
+ )
395
+ end
396
+
388
397
  it 'parses the response as a Transform response packet' do
389
398
  expect(RubySMB::SMB2::Packet::TransformHeader).to receive(:read).with(packet.to_binary_s)
390
399
  client.recv_encrypt
@@ -392,7 +401,7 @@ RSpec.describe RubySMB::Client do
392
401
 
393
402
  it 'raises an InvalidPacket exception if an error occurs while parsing the response' do
394
403
  allow(RubySMB::SMB2::Packet::TransformHeader).to receive(:read).and_raise(IOError)
395
- expect { client.recv_encrypt}.to raise_error(RubySMB::Error::InvalidPacket, 'Not a SMB2 TransformHeader packet')
404
+ expect { client.recv_encrypt }.to raise_error(RubySMB::Error::InvalidPacket, 'Not a SMB2 TransformHeader packet')
396
405
  end
397
406
 
398
407
  it 'decrypts the Transform response packet' do
@@ -403,10 +412,10 @@ RSpec.describe RubySMB::Client do
403
412
  end
404
413
 
405
414
  it 'raises an EncryptionError exception if an error occurs while decrypting' do
406
- allow(client).to receive(:smb3_decrypt).and_raise(RubySMB::Error::RubySMBError )
407
- expect { client.recv_encrypt}.to raise_error(
415
+ allow(client).to receive(:smb3_decrypt).and_raise(RubySMB::Error::RubySMBError)
416
+ expect { client.recv_encrypt }.to raise_error(
408
417
  RubySMB::Error::EncryptionError,
409
- "Error while decrypting RubySMB::SMB2::Packet::TransformHeader packet (SMB 0x0300}): RubySMB::Error::RubySMBError"
418
+ 'Error while decrypting RubySMB::SMB2::Packet::TransformHeader packet (SMB 0x0300}): RubySMB::Error::RubySMBError'
410
419
  )
411
420
  end
412
421
  end
@@ -1050,6 +1059,42 @@ RSpec.describe RubySMB::Client do
1050
1059
  it 'returns the string \'SMB2\'' do
1051
1060
  expect(client.parse_negotiate_response(smb3_response)).to eq ('SMB3')
1052
1061
  end
1062
+
1063
+ context 'when the server supports encryption' do
1064
+ before :example do
1065
+ smb3_response.capabilities.encryption = 1
1066
+ end
1067
+
1068
+ it 'keeps session encryption enabled if it was already' do
1069
+ client.session_encrypt_data = true
1070
+ client.parse_negotiate_response(smb3_response)
1071
+ expect(client.session_encrypt_data).to be true
1072
+ end
1073
+
1074
+ it 'keeps session encryption disabled if it was already' do
1075
+ client.session_encrypt_data = false
1076
+ client.parse_negotiate_response(smb3_response)
1077
+ expect(client.session_encrypt_data).to be false
1078
+ end
1079
+ end
1080
+
1081
+ context 'when the server does not support encryption' do
1082
+ before :example do
1083
+ smb3_response.capabilities.encryption = 0
1084
+ end
1085
+
1086
+ it 'disables session encryption if it was already enabled' do
1087
+ client.session_encrypt_data = true
1088
+ client.parse_negotiate_response(smb3_response)
1089
+ expect(client.session_encrypt_data).to be false
1090
+ end
1091
+
1092
+ it 'keeps session encryption disabled if it was already' do
1093
+ client.session_encrypt_data = false
1094
+ client.parse_negotiate_response(smb3_response)
1095
+ expect(client.session_encrypt_data).to be false
1096
+ end
1097
+ end
1053
1098
  end
1054
1099
 
1055
1100
  context 'when the response contains the SMB2 wildcard revision number dialect' do
@@ -1710,22 +1755,22 @@ RSpec.describe RubySMB::Client do
1710
1755
  smb2_client.smb2_authenticate
1711
1756
  end
1712
1757
 
1713
- context 'when setting the encryption_required parameter' do
1758
+ context 'when setting the session_encrypt_data parameter' do
1714
1759
  before :example do
1715
1760
  smb2_client.smb3 = true
1716
- smb2_client.encryption_required = false
1761
+ smb2_client.session_encrypt_data = false
1717
1762
  end
1718
1763
 
1719
- it 'sets the encryption_required parameter to true if the server requires encryption' do
1764
+ it 'sets the session_encrypt_data parameter to true if the server requires encryption' do
1720
1765
  final_response_packet.session_flags.encrypt_data = 1
1721
1766
  smb2_client.smb2_authenticate
1722
- expect(smb2_client.encryption_required).to be true
1767
+ expect(smb2_client.session_encrypt_data).to be true
1723
1768
  end
1724
1769
 
1725
- it 'does not set the encryption_required parameter if the server does not require encryption' do
1770
+ it 'does not set the session_encrypt_data parameter if the server does not require encryption' do
1726
1771
  final_response_packet.session_flags.encrypt_data = 0
1727
1772
  smb2_client.smb2_authenticate
1728
- expect(smb2_client.encryption_required).to be false
1773
+ expect(smb2_client.session_encrypt_data).to be false
1729
1774
  end
1730
1775
  end
1731
1776
  end
@@ -51,9 +51,9 @@ RSpec.describe RubySMB::Dispatcher::Socket do
51
51
  let(:session_header) { RubySMB::Nbss::SessionHeader.new }
52
52
 
53
53
  context 'when reading from the socket results in a nil value' do
54
- it 'should raise Error::NetBiosSessionService' do
54
+ it 'should raise Error::CommunicationError' do
55
55
  smb_socket.tcp_socket = blank_socket
56
- expect { smb_socket.recv_packet }.to raise_error(::RubySMB::Error::NetBiosSessionService)
56
+ expect { smb_socket.recv_packet }.to raise_error(::RubySMB::Error::CommunicationError)
57
57
  end
58
58
  end
59
59
 
@@ -43,7 +43,7 @@ RSpec.describe RubySMB::SMB2::File do
43
43
  it { is_expected.to respond_to :size }
44
44
  it { is_expected.to respond_to :size_on_disk }
45
45
  it { is_expected.to respond_to :tree }
46
- it { is_expected.to respond_to :encryption_required }
46
+ it { is_expected.to respond_to :tree_connect_encrypt_data }
47
47
 
48
48
  it 'pulls the attributes from the response packet' do
49
49
  expect(file.attributes).to eq create_response.file_attributes
@@ -73,8 +73,8 @@ RSpec.describe RubySMB::SMB2::File do
73
73
  expect(file.size_on_disk).to eq create_response.allocation_size
74
74
  end
75
75
 
76
- it 'sets the encryption_required flag to false by default' do
77
- expect(file.encryption_required).to be false
76
+ it 'sets the tree_connect_encrypt_data flag to false by default' do
77
+ expect(file.tree_connect_encrypt_data).to be false
78
78
  end
79
79
 
80
80
  describe '#set_header_fields' do
@@ -132,7 +132,7 @@ RSpec.describe RubySMB::SMB2::File do
132
132
  end
133
133
 
134
134
  it 'calls Client #send_recv with encryption set if required' do
135
- file.encryption_required = true
135
+ file.tree_connect_encrypt_data = true
136
136
  expect(client).to receive(:send_recv).with(small_read, encrypt: true)
137
137
  file.read
138
138
  end
@@ -177,7 +177,7 @@ RSpec.describe RubySMB::SMB2::File do
177
177
  it 'calls Client #send_recv with encryption set if required' do
178
178
  read_request = double('Read Request')
179
179
  allow(file).to receive(:read_packet).and_return(read_request)
180
- file.encryption_required = true
180
+ file.tree_connect_encrypt_data = true
181
181
  expect(client).to receive(:send_recv).twice.with(read_request, encrypt: true)
182
182
  file.read(bytes: (described_class::MAX_PACKET_SIZE * 2))
183
183
  end
@@ -235,7 +235,7 @@ RSpec.describe RubySMB::SMB2::File do
235
235
  it 'calls Client #send_recv with encryption set if required' do
236
236
  write_request = double('Write Request')
237
237
  allow(file).to receive(:write_packet).and_return(write_request)
238
- file.encryption_required = true
238
+ file.tree_connect_encrypt_data = true
239
239
  expect(client).to receive(:send_recv).once.with(write_request, encrypt: true).and_return(write_response.to_binary_s)
240
240
  file.write(data: 'test')
241
241
  end
@@ -250,7 +250,7 @@ RSpec.describe RubySMB::SMB2::File do
250
250
  it 'calls Client #send_recv with encryption set if required' do
251
251
  write_request = double('Write Request')
252
252
  allow(file).to receive(:write_packet).and_return(write_request)
253
- file.encryption_required = true
253
+ file.tree_connect_encrypt_data = true
254
254
  expect(client).to receive(:send_recv).twice.with(write_request, encrypt: true).and_return(write_response.to_binary_s)
255
255
  file.write(data: SecureRandom.random_bytes(described_class::MAX_PACKET_SIZE + 1))
256
256
  end
@@ -307,7 +307,7 @@ RSpec.describe RubySMB::SMB2::File do
307
307
  it 'calls Client #send_recv with encryption set if required' do
308
308
  allow(file).to receive(:delete_packet)
309
309
  allow(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).and_return(small_response)
310
- file.encryption_required = true
310
+ file.tree_connect_encrypt_data = true
311
311
  expect(client).to receive(:send_recv).with(small_delete, encrypt: true)
312
312
  file.delete
313
313
  end
@@ -349,7 +349,7 @@ RSpec.describe RubySMB::SMB2::File do
349
349
 
350
350
  it 'calls Client #send_recv with encryption set if required' do
351
351
  allow(RubySMB::SMB2::Packet::SetInfoResponse).to receive(:read).and_return(small_response)
352
- file.encryption_required = true
352
+ file.tree_connect_encrypt_data = true
353
353
  expect(client).to receive(:send_recv).with(small_rename, encrypt: true)
354
354
  file.rename('new_file.txt')
355
355
  end
@@ -393,7 +393,7 @@ RSpec.describe RubySMB::SMB2::File do
393
393
  end
394
394
 
395
395
  it 'calls Client #send_recv with encryption set if required' do
396
- file.encryption_required = true
396
+ file.tree_connect_encrypt_data = true
397
397
  expect(client).to receive(:send_recv).with(request, encrypt: true)
398
398
  file.close
399
399
  end
@@ -465,7 +465,7 @@ RSpec.describe RubySMB::SMB2::File do
465
465
  it 'calls Client #send_recv with encryption set if required' do
466
466
  request = double('Request')
467
467
  allow(file).to receive(:read_packet).and_return(request)
468
- file.encryption_required = true
468
+ file.tree_connect_encrypt_data = true
469
469
  expect(client).to receive(:send_recv).with(request, encrypt: true)
470
470
  file.send_recv_read
471
471
  end
@@ -528,7 +528,7 @@ RSpec.describe RubySMB::SMB2::File do
528
528
  end
529
529
 
530
530
  it 'calls Client #send_recv with encryption set if required' do
531
- file.encryption_required = true
531
+ file.tree_connect_encrypt_data = true
532
532
  expect(client).to receive(:send_recv).with(request, encrypt: true)
533
533
  file.send_recv_write
534
534
  end
@@ -26,7 +26,7 @@ RSpec.describe RubySMB::SMB2::Tree do
26
26
  it { is_expected.to respond_to :permissions }
27
27
  it { is_expected.to respond_to :share }
28
28
  it { is_expected.to respond_to :id }
29
- it { is_expected.to respond_to :encryption_required }
29
+ it { is_expected.to respond_to :tree_connect_encrypt_data }
30
30
 
31
31
  it 'inherits the client that spawned it' do
32
32
  expect(tree.client).to eq client
@@ -51,7 +51,7 @@ RSpec.describe RubySMB::SMB2::Tree do
51
51
 
52
52
  it 'calls Client #send_recv with encryption set if required' do
53
53
  allow(tree).to receive(:set_header_fields).and_return(disco_req)
54
- tree.encryption_required = true
54
+ tree.tree_connect_encrypt_data = true
55
55
  expect(client).to receive(:send_recv).with(disco_req, encrypt: true).and_return(disco_resp.to_binary_s)
56
56
  tree.disconnect!
57
57
  end
@@ -147,7 +147,7 @@ RSpec.describe RubySMB::SMB2::Tree do
147
147
 
148
148
  it 'calls Client #send_recv with encryption set if required' do
149
149
  allow(tree).to receive(:open_directory_packet).and_return(create_req)
150
- tree.encryption_required = true
150
+ tree.tree_connect_encrypt_data = true
151
151
  expect(client).to receive(:send_recv).with(create_req, encrypt: true).and_return(create_response.to_binary_s)
152
152
  tree.open_directory
153
153
  end
@@ -229,7 +229,7 @@ RSpec.describe RubySMB::SMB2::Tree do
229
229
 
230
230
  it 'calls Client #send_recv with encryption set if required' do
231
231
  allow(tree).to receive(:set_header_fields).and_return(query_dir_req)
232
- tree.encryption_required = true
232
+ tree.tree_connect_encrypt_data = true
233
233
  expect(client).to receive(:send_recv).with(query_dir_req, encrypt: true)
234
234
  tree.list
235
235
  end
@@ -437,7 +437,7 @@ RSpec.describe RubySMB::SMB2::Tree do
437
437
  end
438
438
 
439
439
  it 'calls Client #send_recv with encryption set if required' do
440
- tree.encryption_required = true
440
+ tree.tree_connect_encrypt_data = true
441
441
  expect(client).to receive(:send_recv).with(create_request, encrypt: true).and_return(create_response.to_binary_s)
442
442
  tree.open_file(filename: filename)
443
443
  end
@@ -459,7 +459,7 @@ RSpec.describe RubySMB::SMB2::Tree do
459
459
  context 'when encryption is required' do
460
460
  it 'returns the expected RubySMB::SMB2::File object' do
461
461
  file_obj = RubySMB::SMB2::File.new(name: filename, tree: tree, response: create_response, encrypt: true)
462
- tree.encryption_required = true
462
+ tree.tree_connect_encrypt_data = true
463
463
  expect(RubySMB::SMB2::File).to receive(:new).with(name: filename, tree: tree, response: create_response, encrypt: true).and_return(file_obj)
464
464
  expect(tree.open_file(filename: filename)).to eq(file_obj)
465
465
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_smb
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Metasploit Hackers
@@ -97,7 +97,7 @@ cert_chain:
97
97
  JI/W23RbIRksG2pioMhd4dCXq3FLLlkOV1YfCwWixNB+iIhQPPZVaPNfgPhCn4Dt
98
98
  DeGjje/qA4fkLtRmOtb9PUBq3ToRDE4=
99
99
  -----END CERTIFICATE-----
100
- date: 2020-06-09 00:00:00.000000000 Z
100
+ date: 2020-06-19 00:00:00.000000000 Z
101
101
  dependencies:
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: redcarpet
metadata.gz.sig CHANGED
Binary file