ruby_smb 3.2.0 → 3.2.2

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: 9ce8d4ea99335efaf6bbc1ef003231ffa8a809382760e54dc26be04b76e53529
4
- data.tar.gz: f284dabf7fe032ae02933a517abb2371f7c7c37eb641876f1cbf2b8cc0e4c2ac
3
+ metadata.gz: 20c59ae356835caa5149193af377ecb8aaf5f1e635f34d8f660d9da1df6a94d5
4
+ data.tar.gz: dbb749afb04c0a9909af9667e0b602ebf43cf00770a7a1d2a4df0e0a520db897
5
5
  SHA512:
6
- metadata.gz: 5cf115ffd4c634f593bceef2bb503d2c0a2b19c5cfa73391887d35ce2691472fabda03e47462b716f8c870d7dedbc5dc815f644887b259d1268658752396ea17
7
- data.tar.gz: 46ba6053ca246692ef29c545c8a9682b6675c4bf50d10d3611107bf537470226986aeece854516d59d99afa1642ee2d72fed99f39c1731112292fcbb6d8138d2
6
+ metadata.gz: 0d826659151d98a13517cb5026dde99852ec2feaaeb6af17559782c2147026ae8cebc5ba0c19a576fb4e87e1c0950e33a3f9c9026fe8752d6503fe263796fdaf
7
+ data.tar.gz: 057f902a9540bdf4b312ec3000441fcdba9a930021a15ca12935c2b486647edae85475991c0837876e1f3b365d9c791aeecb11533970f9a63e4d9df6fe13d48a
checksums.yaml.gz.sig CHANGED
Binary file
@@ -33,17 +33,16 @@ jobs:
33
33
  fail-fast: true
34
34
  matrix:
35
35
  ruby:
36
- - 2.6
37
- - 2.7
38
- - 3.0
39
- - 3.1
36
+ - '2.7'
37
+ - '3.0'
38
+ - '3.1'
39
+ - '3.2'
40
40
  os:
41
- - ubuntu-18.04
42
- - ubuntu-22.04
41
+ - ubuntu-20.04
42
+ - ubuntu-latest
43
43
  exclude:
44
- - { os: ubuntu-22.04, ruby: 2.6 }
45
- - { os: ubuntu-22.04, ruby: 2.7 }
46
- - { os: ubuntu-22.04, ruby: 3.0 }
44
+ - { os: ubuntu-latest, ruby: '2.7' }
45
+ - { os: ubuntu-latest, ruby: '3.0' }
47
46
  test_cmd:
48
47
  - bundle exec rspec
49
48
 
data/README.md CHANGED
@@ -184,6 +184,7 @@ Example:
184
184
  2.3.3 :013 > packet.to_binary_s
185
185
  => "\xFFSMB+\x00\x00\x00\x00\x98\x01`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00"
186
186
  ```
187
+
187
188
  ### Using the Client
188
189
 
189
190
  Sitting on top of the packet layer in RubySMB is the RubySMB::Client class. This is the abstraction that most users of RubySMB will interact with. It provides simple convenience methods for performing SMB actions. It handles the creation, sending and receiving of packets for the user, providing reasonable defaults in many cases.
@@ -4,6 +4,7 @@ module RubySMB
4
4
  class Client
5
5
  require 'ruby_smb/ntlm'
6
6
  require 'ruby_smb/signing'
7
+ require 'ruby_smb/utils'
7
8
  require 'ruby_smb/client/negotiation'
8
9
  require 'ruby_smb/client/authentication'
9
10
  require 'ruby_smb/client/tree_connect'
@@ -13,6 +14,7 @@ module RubySMB
13
14
  require 'ruby_smb/client/encryption'
14
15
 
15
16
  include RubySMB::Signing
17
+ include RubySMB::NTLM
16
18
  include RubySMB::Client::Negotiation
17
19
  include RubySMB::Client::Authentication
18
20
  include RubySMB::Client::TreeConnect
@@ -322,7 +324,7 @@ module RubySMB
322
324
  @pid = rand(0xFFFF)
323
325
  @domain = domain
324
326
  @local_workstation = local_workstation
325
- @password = password.encode('utf-8') || ''.encode('utf-8')
327
+ @password = RubySMB::Utils.safe_encode((password||''), 'utf-8')
326
328
  @sequence_counter = 0
327
329
  @session_id = 0x00
328
330
  @session_key = ''
@@ -332,7 +334,7 @@ module RubySMB
332
334
  @smb1 = smb1
333
335
  @smb2 = smb2
334
336
  @smb3 = smb3
335
- @username = username.encode('utf-8') || ''.encode('utf-8')
337
+ @username = RubySMB::Utils.safe_encode((username||''), 'utf-8')
336
338
  @max_buffer_size = MAX_BUFFER_SIZE
337
339
  # These sizes will be modified during negotiation
338
340
  @server_max_buffer_size = SERVER_MAX_BUFFER_SIZE
@@ -415,8 +417,8 @@ module RubySMB
415
417
  local_workstation: self.local_workstation, ntlm_flags: NTLM::DEFAULT_CLIENT_FLAGS)
416
418
  @domain = domain
417
419
  @local_workstation = local_workstation
418
- @password = pass.encode('utf-8') || ''.encode('utf-8')
419
- @username = user.encode('utf-8') || ''.encode('utf-8')
420
+ @password = RubySMB::Utils.safe_encode((pass||''), 'utf-8')
421
+ @username = RubySMB::Utils.safe_encode((user||''), 'utf-8')
420
422
 
421
423
  @ntlm_client = RubySMB::NTLM::Client.new(
422
424
  @username,
@@ -5,14 +5,16 @@ module RubySMB
5
5
  class Client
6
6
  require 'bindata'
7
7
  require 'windows_error'
8
- require 'net/ntlm'
8
+ require 'ruby_smb/ntlm'
9
9
  require 'ruby_smb/dcerpc'
10
10
  require 'ruby_smb/gss'
11
11
  require 'ruby_smb/peer_info'
12
+ require 'ruby_smb/utils'
12
13
 
13
14
  include Dcerpc
14
15
  include Epm
15
16
  include PeerInfo
17
+ include Utils
16
18
 
17
19
  # The default maximum size of a RPC message that the Client accepts (in bytes)
18
20
  MAX_BUFFER_SIZE = 64512
@@ -118,15 +120,15 @@ module RubySMB
118
120
  @read_timeout = read_timeout
119
121
  @domain = domain
120
122
  @local_workstation = local_workstation
121
- @username = username.encode('utf-8')
122
- @password = password.encode('utf-8')
123
+ @username = RubySMB::Utils.safe_encode(username, 'utf-8')
124
+ @password = RubySMB::Utils.safe_encode(password, 'utf-8')
123
125
  @max_buffer_size = MAX_BUFFER_SIZE
124
126
  @call_id = 1
125
127
  @ctx_id = 0
126
128
  @auth_ctx_id_base = rand(0xFFFFFFFF)
127
129
 
128
130
  unless username.empty? && password.empty?
129
- @ntlm_client = Net::NTLM::Client.new(
131
+ @ntlm_client = RubySMB::NTLM::Client.new(
130
132
  @username,
131
133
  @password,
132
134
  workstation: @local_workstation,
@@ -35,7 +35,7 @@ module RubySMB
35
35
  def cert_server_request(attributes:, authority:, csr:)
36
36
  cert_server_request_request = CertServerRequestRequest.new(
37
37
  pwsz_authority: authority,
38
- pctb_attribs: { pb: (attributes.map { |k,v| "#{k}:#{v}" }.join("\n").encode('UTF-16le').force_encoding('ASCII-8bit') + "\x00\x00".b) },
38
+ pctb_attribs: { pb: (RubySMB::Utils.safe_encode(attributes.map { |k,v| "#{k}:#{v}" }.join("\n"), 'UTF-16le').force_encoding('ASCII-8bit') + "\x00\x00".b) },
39
39
  pctb_request: { pb: csr.to_der }
40
40
  )
41
41
 
@@ -51,6 +51,7 @@ module RubySMB
51
51
  end
52
52
 
53
53
  ret = {
54
+ certificate: nil,
54
55
  disposition: cert_server_request_response.pdw_disposition.value,
55
56
  disposition_message: cert_server_request_response.pctb_disposition_message.buffer.chomp("\x00\x00").force_encoding('utf-16le').encode,
56
57
  status: {
@@ -72,7 +73,7 @@ module RubySMB
72
73
  status_code: status_code
73
74
  )
74
75
  end
75
- else
76
+ elsif !cert_server_request_response.pctb_encoded_cert.buffer.empty?
76
77
  ret[:certificate] = OpenSSL::X509::Certificate.new(cert_server_request_response.pctb_encoded_cert.buffer)
77
78
  end
78
79
 
@@ -247,12 +247,22 @@ module RubySMB::Dcerpc::Ndr
247
247
 
248
248
  def do_read(io)
249
249
  if is_a?(ConfPlugin) && should_process_max_count?
250
- set_max_count(io.readbytes(4).unpack('L<').first)
250
+ max_count = io.readbytes(4).unpack1('L<')
251
+ BinData.trace_message do |tracer|
252
+ tracer.trace_obj("#{debug_name}.max_count", max_count.to_s)
253
+ end
254
+ set_max_count(max_count)
251
255
  end
252
256
 
253
257
  if is_a?(VarPlugin)
254
258
  @offset = io.readbytes(4).unpack('L<').first
259
+ BinData.trace_message do |tracer|
260
+ tracer.trace_obj("#{debug_name}.offset", @offset.to_s)
261
+ end
255
262
  @actual_count = @read_until_index = io.readbytes(4).unpack('L<').first
263
+ BinData.trace_message do |tracer|
264
+ tracer.trace_obj("#{debug_name}.actual_count", @actual_count.to_s)
265
+ end
256
266
  end
257
267
 
258
268
  if has_elements_to_read?
@@ -523,7 +533,11 @@ module RubySMB::Dcerpc::Ndr
523
533
 
524
534
  def do_read(io)
525
535
  if should_process_max_count?
526
- set_max_count(io.readbytes(4).unpack('L<').first)
536
+ max_count = io.readbytes(4).unpack1('L<')
537
+ BinData.trace_message do |tracer|
538
+ tracer.trace_obj("#{debug_name}.max_count", max_count.to_s)
539
+ end
540
+ set_max_count(max_count)
527
541
  end
528
542
  super
529
543
  end
@@ -582,7 +596,13 @@ module RubySMB::Dcerpc::Ndr
582
596
 
583
597
  def do_read(io)
584
598
  @offset = io.readbytes(4).unpack('L<').first
599
+ BinData.trace_message do |tracer|
600
+ tracer.trace_obj("#{debug_name}.offset", @offset.to_s)
601
+ end
585
602
  @actual_count = io.readbytes(4).unpack('L<').first
603
+ BinData.trace_message do |tracer|
604
+ tracer.trace_obj("#{debug_name}.actual_count", @actual_count.to_s)
605
+ end
586
606
  super if @actual_count > 0
587
607
  end
588
608
 
@@ -702,7 +722,11 @@ module RubySMB::Dcerpc::Ndr
702
722
 
703
723
  def do_read(io)
704
724
  if should_process_max_count?
705
- set_max_count(io.readbytes(4).unpack('L<').first)
725
+ max_count = io.readbytes(4).unpack1('L<')
726
+ BinData.trace_message do |tracer|
727
+ tracer.trace_obj("#{debug_name}.max_count", max_count.to_s)
728
+ end
729
+ set_max_count(max_count)
706
730
 
707
731
  # Align the structure according to the alignment rules for the structure
708
732
  if respond_to?(:referent_bytes_align)
@@ -1034,6 +1058,9 @@ module RubySMB::Dcerpc::Ndr
1034
1058
  end
1035
1059
  else
1036
1060
  @ref_id = io.readbytes(4).unpack('L<').first
1061
+ BinData.trace_message do |tracer|
1062
+ tracer.trace_obj("#{debug_name}.ref_id", @ref_id.to_s)
1063
+ end
1037
1064
  parent_obj = nil
1038
1065
  if parent&.is_a?(ConstructedTypePlugin)
1039
1066
  parent_obj = parent.get_top_level_constructed_type
@@ -320,7 +320,7 @@ module RubySMB
320
320
 
321
321
  def self.encrypt_password(password, key)
322
322
  # see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/5fe3c4c4-e71b-440d-b2fd-8448bfaf6e04
323
- password = password.encode('UTF-16LE').force_encoding('ASCII-8bit')
323
+ password = RubySMB::Utils.safe_encode(password, 'UTF-16LE').force_encoding('ASCII-8bit')
324
324
  buffer = password.rjust(512, "\x00") + [ password.length ].pack('V')
325
325
  salt = SecureRandom.random_bytes(16)
326
326
  key = OpenSSL::Digest::MD5.new(salt + key).digest
@@ -24,7 +24,7 @@ module RubySMB
24
24
  end
25
25
 
26
26
  # @param host [String] passed to TCPSocket.new
27
- # @param port [Fixnum] passed to TCPSocket.new
27
+ # @param port [Integer] passed to TCPSocket.new
28
28
  def self.connect(host, port: 445, socket: TCPSocket.new(host, port))
29
29
  new(socket)
30
30
  end
@@ -18,12 +18,12 @@ module RubySMB
18
18
  val
19
19
  end
20
20
 
21
- # Sets the value of the field from a DateTime,Time,Fixnum, or object
21
+ # Sets the value of the field from a DateTime,Time,Integer, or object
22
22
  # that can be converted to an integer. Datetime and Time objects get
23
23
  # converted to account for the Windows/Unix Epoch difference. Any other
24
24
  # parameter passed in will be assumed to already be correct.
25
25
  #
26
- # @param value [DateTime,Time,Fixnum,#to_i] the value to set
26
+ # @param value [DateTime,Time,Integer,#to_i] the value to set
27
27
  # @return
28
28
  def set(value)
29
29
  case value
@@ -16,11 +16,11 @@ module RubySMB
16
16
  val
17
17
  end
18
18
 
19
- # Sets the value of the field from a DateTime,Time,Fixnum, or object
19
+ # Sets the value of the field from a DateTime,Time,Integer, or object
20
20
  # that can be converted to an integer. Any other
21
21
  # parameter passed in will be assumed to already be correct.
22
22
  #
23
- # @param value [DateTime,Time,Fixnum,#to_i] the value to set
23
+ # @param value [DateTime,Time,Integer,#to_i] the value to set
24
24
  # @return
25
25
  def set(value)
26
26
  case value
@@ -129,7 +129,7 @@ module RubySMB
129
129
  # string representation.
130
130
  #
131
131
  # @param field [Hash] the hash representing the field
132
- # @param depth [Fixnum] the recursive depth level to track indentation
132
+ # @param depth [Integer] the recursive depth level to track indentation
133
133
  # @return [String] the formatted string representation of the field
134
134
  def self.format_field(field, depth = 0)
135
135
  name = field[:name].to_s
@@ -181,7 +181,7 @@ module RubySMB
181
181
  # into a string representing the contents of that field.
182
182
  #
183
183
  # @param field [Hash] hash representation of the field to display
184
- # @param depth [Fixnum] the recursion depth for setting indent levels
184
+ # @param depth [Integer] the recursion depth for setting indent levels
185
185
  # @param parents [Array<Symbol>] the name of the parent field, if any, of this field
186
186
  # @return [String] a formatted string representing the field and it's current contents
187
187
  def display_field(field, depth = 0, parents = [])
@@ -18,6 +18,7 @@ module RubySMB
18
18
  end
19
19
 
20
20
  class Authenticator < Authenticator::Base
21
+
21
22
  def reset!
22
23
  super
23
24
  @server_challenge = nil
@@ -141,7 +142,10 @@ module RubySMB
141
142
  case type3_msg.ntlm_version
142
143
  when :ntlmv1
143
144
  my_ntlm_response = Net::NTLM::ntlm_response(
144
- ntlm_hash: Net::NTLM::ntlm_hash(account.password.encode('UTF-16LE'), unicode: true),
145
+ ntlm_hash: Net::NTLM::ntlm_hash(
146
+ RubySMB::Utils.safe_encode(account.password, 'UTF-16LE'),
147
+ unicode: true
148
+ ),
145
149
  challenge: @server_challenge
146
150
  )
147
151
  matches = my_ntlm_response == type3_msg.ntlm_response
@@ -151,9 +155,9 @@ module RubySMB
151
155
  their_blob = type3_msg.ntlm_response[digest.digest_length..-1]
152
156
 
153
157
  ntlmv2_hash = Net::NTLM.ntlmv2_hash(
154
- account.username.encode('UTF-16LE'),
155
- account.password.encode('UTF-16LE'),
156
- type3_msg.domain.encode('UTF-16LE'), # don't use the account domain because of the special '.' value
158
+ RubySMB::Utils.safe_encode(account.username, 'UTF-16LE'),
159
+ RubySMB::Utils.safe_encode(account.password, 'UTF-16LE'),
160
+ RubySMB::Utils.safe_encode(type3_msg.domain, 'UTF-16LE'), # don't use the account domain because of the special '.' value
157
161
  {client_challenge: their_blob[16...24], unicode: true}
158
162
  )
159
163
 
@@ -305,7 +309,10 @@ module RubySMB
305
309
  username = username.downcase
306
310
  domain = @default_domain if domain.nil? || domain == '.'.encode(domain.encoding)
307
311
  domain = domain.downcase
308
- @accounts.find { |account| account.username.encode(username.encoding).downcase == username && account.domain.encode(domain.encoding).downcase == domain }
312
+ @accounts.find do |account|
313
+ RubySMB::Utils.safe_encode(account.username, username.encoding).downcase == username &&
314
+ RubySMB::Utils.safe_encode(account.domain, domain.encoding).downcase == domain
315
+ end
309
316
  end
310
317
 
311
318
  #
@@ -51,6 +51,10 @@ module RubySMB::NTLM
51
51
  !challenge_message.has_flag?(:UNICODE) && challenge_message.has_flag?(:OEM)
52
52
  end
53
53
 
54
+ def ntlmv2_hash
55
+ @ntlmv2_hash ||= RubySMB::NTLM.ntlmv2_hash(username, password, domain, {:client_challenge => client_challenge, :unicode => !use_oem_strings?})
56
+ end
57
+
54
58
  def calculate_user_session_key!
55
59
  if is_anonymous?
56
60
  # see MS-NLMP section 3.4
@@ -0,0 +1,19 @@
1
+ require 'net/ntlm'
2
+
3
+ module Custom
4
+ module NTLM
5
+
6
+ def self.prepended(base)
7
+ base.singleton_class.send(:prepend, ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ def encode_utf16le(str)
12
+ str.dup.force_encoding('UTF-8').encode(Encoding::UTF_16LE, Encoding::UTF_8).force_encoding('ASCII-8BIT')
13
+ end
14
+ end
15
+
16
+ end
17
+ end
18
+
19
+ Net::NTLM::EncodeUtil.send(:prepend, Custom::NTLM)
data/lib/ruby_smb/ntlm.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'ruby_smb/ntlm/custom/ntlm'
2
+
1
3
  module RubySMB
2
4
  module NTLM
3
5
  # [[MS-NLMP] 2.2.2.5](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/99d90ff4-957f-4c8a-80e4-5bfe5a9a9832)
@@ -56,6 +58,41 @@ module RubySMB
56
58
  "Version #{major}.#{minor} (Build #{build}); NTLM Current Revision #{ntlm_revision}"
57
59
  end
58
60
  end
61
+
62
+ class << self
63
+
64
+ # Generate a NTLMv2 Hash
65
+ # @param [String] user The username
66
+ # @param [String] password The password
67
+ # @param [String] target The domain or workstation to authenticate to
68
+ # @option opt :unicode (false) Unicode encode the domain
69
+ def ntlmv2_hash(user, password, target, opt={})
70
+ if Net::NTLM.is_ntlm_hash? password
71
+ decoded_password = Net::NTLM::EncodeUtil.decode_utf16le(password)
72
+ ntlmhash = [decoded_password.upcase[33,65]].pack('H32')
73
+ else
74
+ ntlmhash = Net::NTLM.ntlm_hash(password, opt)
75
+ end
76
+
77
+ if opt[:unicode]
78
+ # Uppercase operation on username containing non-ASCII characters
79
+ # after being unicode encoded with `EncodeUtil.encode_utf16le`
80
+ # doesn't play well. Upcase should be done before encoding.
81
+ user_upcase = Net::NTLM::EncodeUtil.decode_utf16le(user).upcase
82
+ user_upcase = Net::NTLM::EncodeUtil.encode_utf16le(user_upcase)
83
+ else
84
+ user_upcase = user.upcase
85
+ end
86
+ userdomain = user_upcase + target
87
+
88
+ unless opt[:unicode]
89
+ userdomain = Net::NTLM::EncodeUtil.encode_utf16le(userdomain)
90
+ end
91
+ OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmhash, userdomain)
92
+ end
93
+
94
+ end
95
+
59
96
  end
60
97
  end
61
98
 
@@ -7,7 +7,7 @@ module RubySMB
7
7
  # see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/b062f3e3-1b65-4a9a-854a-0ee432499d8f
8
8
  response = RubySMB::SMB1::Packet::TreeConnectResponse.new
9
9
 
10
- share_name = request.data_block.path.encode('UTF-8').split('\\', 4).last
10
+ share_name = RubySMB::Utils.safe_encode(request.data_block.path, 'UTF-8').split('\\', 4).last
11
11
  share_provider = @server.shares.transform_keys(&:downcase)[share_name.downcase]
12
12
  if share_provider.nil?
13
13
  logger.warn("Received TREE_CONNECT request for non-existent share: #{share_name}")
@@ -49,7 +49,7 @@ module RubySMB
49
49
  return response
50
50
  end
51
51
 
52
- share_name = request.path.encode('UTF-8').split('\\', 4).last
52
+ share_name = RubySMB::Utils.safe_encode(request.path, 'UTF-8').split('\\', 4).last
53
53
  share_provider = @server.shares.transform_keys(&:downcase)[share_name.downcase]
54
54
 
55
55
  if share_provider.nil?
@@ -11,7 +11,7 @@ module RubySMB
11
11
  # Class method to stub byte count calculation during
12
12
  # lazy evaluation.
13
13
  #
14
- # @return [Fixnum] will always return 0
14
+ # @return [Integer] will always return 0
15
15
  def self.calculate_byte_count
16
16
  0
17
17
  end
@@ -28,7 +28,7 @@ module RubySMB
28
28
  # Calculates the size of the other fields in the DataBlock
29
29
  # in Bytes.
30
30
  #
31
- # @return [Fixnum] The size of the DataBlock in Words
31
+ # @return [Integer] The size of the DataBlock in Words
32
32
  def calculate_byte_count
33
33
  total_count = 0
34
34
  self.class.data_fields.each do |field_name|
@@ -11,7 +11,7 @@ module RubySMB
11
11
  # Class method to stub word count calculation during
12
12
  # lazy evaluation.
13
13
  #
14
- # @param [Fixnum] will always return 0
14
+ # @param [Integer] will always return 0
15
15
  def self.calculate_word_count
16
16
  0
17
17
  end
@@ -28,7 +28,7 @@ module RubySMB
28
28
  # Calculates the size of the other fields in the ParameterBlock
29
29
  # in Words.
30
30
  #
31
- # @return [Fixnum] The size of the ParameterBlock in Words
31
+ # @return [Integer] The size of the ParameterBlock in Words
32
32
  def calculate_word_count
33
33
  total_count = 0
34
34
  self.class.parameter_fields.each do |field_name|
@@ -147,6 +147,10 @@ module RubySMB
147
147
  break if dcerpc_response.pdu_header.pfc_flags.last_frag == 1
148
148
  raw_data = read(bytes: @tree.client.max_buffer_size)
149
149
  dcerpc_response = dcerpc_response_from_raw_response(raw_data)
150
+ if options[:auth_level] &&
151
+ [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(options[:auth_level])
152
+ handle_integrity_privacy(dcerpc_response, auth_level: options[:auth_level], auth_type: options[:auth_type])
153
+ end
150
154
  stub_data << dcerpc_response.stub.to_s
151
155
  end
152
156
  stub_data
@@ -28,8 +28,8 @@ module RubySMB
28
28
 
29
29
  # Adds a dialect to the Dialects array
30
30
  #
31
- # @param [Fixnum] the numeric code for the dialect you wish to add
32
- # @return [Array<Fixnum>] the array of all currently selected dialects
31
+ # @param [Integer] the numeric code for the dialect you wish to add
32
+ # @return [Array<Integer>] the array of all currently selected dialects
33
33
  # @raise [ArgumentError] if the dialect is not an Integer
34
34
  def add_dialect(dialect)
35
35
  raise ArgumentError, 'Must be a number' unless dialect.is_a? Integer
@@ -40,8 +40,8 @@ module RubySMB
40
40
  # the dialect_count field appropriately. Will erase any previously set
41
41
  # dialects.
42
42
  #
43
- # @param [Array<Fixnum>] the array of dialects to set
44
- # @return [Array<Fixnum>] the current value of the dialects array
43
+ # @param [Array<Integer>] the array of dialects to set
44
+ # @return [Array<Integer>] the current value of the dialects array
45
45
  def set_dialects(add_dialects = [])
46
46
  self.dialects = []
47
47
  add_dialects.each do |dialect|
@@ -53,7 +53,7 @@ module RubySMB
53
53
  # Adds a Negotiate Context to the #negotiate_context_list
54
54
  #
55
55
  # @param [NegotiateContext] the Negotiate Context structure you wish to add
56
- # @return [Array<Fixnum>] the array of all currently added Negotiate Contexts
56
+ # @return [Array<Integer>] the array of all currently added Negotiate Contexts
57
57
  # @raise [ArgumentError] if the dialect is not a NegotiateContext structure
58
58
  def add_negotiate_context(nc)
59
59
  raise ArgumentError, 'Must be a NegotiateContext' unless nc.is_a? NegotiateContext
@@ -48,7 +48,7 @@ module RubySMB
48
48
  # Adds a Negotiate Context to the #negotiate_context_list
49
49
  #
50
50
  # @param [NegotiateContext] the Negotiate Context structure you wish to add
51
- # @return [Array<Fixnum>] the array of all currently added Negotiate Contexts
51
+ # @return [Array<Integer>] the array of all currently added Negotiate Contexts
52
52
  # @raise [ArgumentError] if the dialect is not a NegotiateContext structure
53
53
  def add_negotiate_context(nc)
54
54
  raise ArgumentError, 'Must be a NegotiateContext' unless nc.is_a? NegotiateContext
@@ -145,6 +145,10 @@ module RubySMB
145
145
  break if dcerpc_response.pdu_header.pfc_flags.last_frag == 1
146
146
  raw_data = read(bytes: @tree.client.max_buffer_size)
147
147
  dcerpc_response = dcerpc_response_from_raw_response(raw_data)
148
+ if options[:auth_level] &&
149
+ [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(options[:auth_level])
150
+ handle_integrity_privacy(dcerpc_response, auth_level: options[:auth_level], auth_type: options[:auth_type])
151
+ end
148
152
  stub_data << dcerpc_response.stub.to_s
149
153
  end
150
154
  stub_data
@@ -0,0 +1,15 @@
1
+ module RubySMB
2
+ module Utils
3
+
4
+ def self.safe_encode(str, encoding)
5
+ str.encode(encoding)
6
+ rescue EncodingError
7
+ if str.encoding == ::Encoding::ASCII_8BIT
8
+ str.dup.force_encoding(encoding)
9
+ else
10
+ raise
11
+ end
12
+ end
13
+
14
+ end
15
+ end
@@ -1,3 +1,3 @@
1
1
  module RubySMB
2
- VERSION = '3.2.0'.freeze
2
+ VERSION = '3.2.2'.freeze
3
3
  end
data/lib/ruby_smb.rb CHANGED
@@ -6,11 +6,13 @@ require 'openssl/ccm'
6
6
  require 'openssl/cmac'
7
7
  require 'windows_error'
8
8
  require 'windows_error/nt_status'
9
+ require 'ruby_smb/ntlm/custom/ntlm'
9
10
  # A packet parsing and manipulation library for the SMB1 and SMB2 protocols
10
11
  #
11
12
  # [[MS-SMB] Server Message Block (SMB) Protocol Version 1](https://msdn.microsoft.com/en-us/library/cc246482.aspx)
12
13
  # [[MS-SMB2] Server Message Block (SMB) Protocol Versions 2 and 3](https://msdn.microsoft.com/en-us/library/cc246482.aspx)
13
14
  module RubySMB
15
+ require 'ruby_smb/utils'
14
16
  require 'ruby_smb/error'
15
17
  require 'ruby_smb/create_actions'
16
18
  require 'ruby_smb/dispositions'
@@ -2701,7 +2701,7 @@ RSpec.describe RubySMB::Client do
2701
2701
  session_key,
2702
2702
  "SMB2AESCCM\x00",
2703
2703
  "ServerIn \x00",
2704
- {length: 128}
2704
+ length: 128
2705
2705
  ).and_call_original
2706
2706
  client.smb3_encrypt(data)
2707
2707
  end
@@ -2717,7 +2717,7 @@ RSpec.describe RubySMB::Client do
2717
2717
  session_key,
2718
2718
  "SMBC2SCipherKey\x00",
2719
2719
  '',
2720
- {length: 128}
2720
+ length: 128
2721
2721
  ).and_call_original
2722
2722
  client.smb3_encrypt(data)
2723
2723
  end
@@ -2791,7 +2791,7 @@ RSpec.describe RubySMB::Client do
2791
2791
  session_key,
2792
2792
  "SMB2AESCCM\x00",
2793
2793
  "ServerOut\x00",
2794
- {length: 128}
2794
+ length: 128
2795
2795
  ).and_call_original
2796
2796
  client.smb3_decrypt(transform_packet)
2797
2797
  end
@@ -2807,7 +2807,7 @@ RSpec.describe RubySMB::Client do
2807
2807
  session_key,
2808
2808
  "SMBS2CCipherKey\x00",
2809
2809
  '',
2810
- {length: 128}
2810
+ length: 128
2811
2811
  ).and_call_original
2812
2812
  client.smb3_decrypt(transform_packet)
2813
2813
  end
@@ -631,7 +631,7 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
631
631
 
632
632
  it 'calls #enum_key the expected number of times' do
633
633
  winreg.enum_registry_key(key)
634
- expect(winreg).to have_received(:enum_key).with(subkey_handle, instance_of(Fixnum)).twice
634
+ expect(winreg).to have_received(:enum_key).with(subkey_handle, instance_of(Integer)).twice
635
635
  end
636
636
 
637
637
  it 'closes the key' do
@@ -710,7 +710,7 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
710
710
 
711
711
  it 'calls #enum_key the expected number of times' do
712
712
  winreg.enum_registry_values(key)
713
- expect(winreg).to have_received(:enum_value).with(subkey_handle, instance_of(Fixnum)).twice
713
+ expect(winreg).to have_received(:enum_value).with(subkey_handle, instance_of(Integer)).twice
714
714
  end
715
715
 
716
716
  it 'closes the key' do
@@ -112,7 +112,7 @@ RSpec.describe RubySMB::SMB1::Packet::ReadAndxRequest do
112
112
  expect { packet.set_read_from_named_pipe('true') }.to raise_error(ArgumentError)
113
113
  end
114
114
 
115
- it 'raises an exception when the value is a Numeric' do
115
+ it 'raises an exception when the value is a Integer' do
116
116
  expect { packet.set_read_from_named_pipe(1) }.to raise_error(ArgumentError)
117
117
  end
118
118
 
@@ -138,7 +138,7 @@ RSpec.describe RubySMB::SMB1::Packet::ReadAndxRequest do
138
138
  expect { packet.set_64_bit_offset('true') }.to raise_error(ArgumentError)
139
139
  end
140
140
 
141
- it 'raises an exception when the value is a Numeric' do
141
+ it 'raises an exception when the value is a Integer' do
142
142
  expect { packet.set_64_bit_offset(1) }.to raise_error(ArgumentError)
143
143
  end
144
144
 
@@ -137,7 +137,7 @@ RSpec.describe RubySMB::SMB1::Packet::WriteAndxRequest do
137
137
  expect { packet.set_64_bit_offset('true') }.to raise_error(ArgumentError)
138
138
  end
139
139
 
140
- it 'raises an exception when the value is a Numeric' do
140
+ it 'raises an exception when the value is a Integer' do
141
141
  expect { packet.set_64_bit_offset(1) }.to raise_error(ArgumentError)
142
142
  end
143
143
 
data.tar.gz.sig CHANGED
Binary file
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: 3.2.0
4
+ version: 3.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Metasploit Hackers
@@ -97,7 +97,7 @@ cert_chain:
97
97
  EknWpNgVhohbot1lfVAMmIhdtOVaRVcQQixWPwprDj/ydB8ryDMDosIMcw+fkoXU
98
98
  9GJsSaSRRYQ9UUkVL27b64okU8D48m8=
99
99
  -----END CERTIFICATE-----
100
- date: 2022-08-30 00:00:00.000000000 Z
100
+ date: 2023-01-18 00:00:00.000000000 Z
101
101
  dependencies:
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: redcarpet
@@ -493,6 +493,7 @@ files:
493
493
  - lib/ruby_smb/nbss/session_request.rb
494
494
  - lib/ruby_smb/ntlm.rb
495
495
  - lib/ruby_smb/ntlm/client.rb
496
+ - lib/ruby_smb/ntlm/custom/ntlm.rb
496
497
  - lib/ruby_smb/peer_info.rb
497
498
  - lib/ruby_smb/server.rb
498
499
  - lib/ruby_smb/server/cli.rb
@@ -673,6 +674,7 @@ files:
673
674
  - lib/ruby_smb/smb2/smb2_header.rb
674
675
  - lib/ruby_smb/smb2/tree.rb
675
676
  - lib/ruby_smb/smb_error.rb
677
+ - lib/ruby_smb/utils.rb
676
678
  - lib/ruby_smb/version.rb
677
679
  - ruby_smb.gemspec
678
680
  - spec/lib/ruby_smb/client_spec.rb
@@ -999,8 +1001,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
999
1001
  - !ruby/object:Gem::Version
1000
1002
  version: '0'
1001
1003
  requirements: []
1002
- rubyforge_project:
1003
- rubygems_version: 2.7.10
1004
+ rubygems_version: 3.3.26
1004
1005
  signing_key:
1005
1006
  specification_version: 4
1006
1007
  summary: A pure Ruby implementation of the SMB Protocol Family
metadata.gz.sig CHANGED
Binary file