ruby_smb 2.0.0 → 2.0.1

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.
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