ruby_smb 3.1.2 → 3.1.3

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: 498d32e1eeed4cb410f03dfdc5ea1b23dd5506d89e387a3533494b9f73294ffa
4
- data.tar.gz: 838a864709be049725a3978de10d71a0cf9eb75e91d00468cdee07fc5e614250
3
+ metadata.gz: 0b10829db92d5746b069916440f0e91ca006c370053fdc02621ed75723efbf40
4
+ data.tar.gz: aeeeb396277c47b16ff977e33344ab08da275a0632d6a9a220aac7e733e91311
5
5
  SHA512:
6
- metadata.gz: e60651395300c2f7bc88049e7572a2b5376646615da08a1978d8e71afe694ca2f32396e124cbda71cc203811ff8df0241aa072f58aeffa8265498789cab7696f
7
- data.tar.gz: e9d3bd5ffb781a01e4382d8f0f2327cd384d4be520a394fbf00336fbc23b9913fae58b380c05c1782c320364edd8ac5e729639091c0f54b32208469972810705
6
+ metadata.gz: 7269f0664dd840a83d39d5d1b3a953f87d050bcffbea0b9993685ef1ec91c9047a9117d88ee305d2c467555b475a7c15e82f0f8bfa1b98d077ea00fd401de200
7
+ data.tar.gz: a5997a65e48cd66585896c55cd8a01fbbee4a8b04280a15ecacdd79501fdd42caf772ac712a32228ea6c1991a6db27c9657d8829ca412691df0834e392c45284
checksums.yaml.gz.sig CHANGED
Binary file
@@ -3,81 +3,19 @@
3
3
  require 'bundler/setup'
4
4
  require 'optparse'
5
5
  require 'ruby_smb'
6
- require 'ruby_smb/gss/provider/ntlm'
7
6
 
8
7
  # we just need *a* default encoding to handle the strings from the NTLM messages
9
8
  Encoding.default_internal = 'UTF-8' if Encoding.default_internal.nil?
10
9
 
11
- options = {
12
- allow_anonymous: true,
13
- allow_guests: false,
14
- domain: nil,
15
- username: 'RubySMB',
16
- password: 'password',
17
- share_name: 'home',
18
- share_path: '.',
19
- smbv1: true,
20
- smbv2: true,
21
- smbv3: true
22
- }
23
- OptionParser.new do |opts|
24
- opts.banner = "Usage: #{File.basename(__FILE__)} [options]"
25
- opts.on("--path PATH", "The path to share (default: #{options[:share_path]})") do |path|
10
+ options = RubySMB::Server::Cli.parse(defaults: { share_path: '.' }) do |options, parser|
11
+ parser.banner = "Usage: #{File.basename(__FILE__)} [options]"
12
+
13
+ parser.on("--share-path SHARE_PATH", "The path to share (default: #{options[:share_path]})") do |path|
26
14
  options[:share_path] = path
27
15
  end
28
- opts.on("--share SHARE", "The share name (default: #{options[:share_name]})") do |share|
29
- options[:share_name] = share
30
- end
31
- opts.on("--[no-]anonymous", "Allow anonymous access (default: #{options[:allow_anonymous]})") do |allow_anonymous|
32
- options[:allow_anonymous] = allow_anonymous
33
- end
34
- opts.on("--[no-]smbv1", "Enable or disable SMBv1 (default: #{options[:smbv1] ? 'Enabled' : 'Disabled'})") do |smbv1|
35
- options[:smbv1] = smbv1
36
- end
37
- opts.on("--[no-]smbv2", "Enable or disable SMBv2 (default: #{options[:smbv2] ? 'Enabled' : 'Disabled'})") do |smbv2|
38
- options[:smbv2] = smbv2
39
- end
40
- opts.on("--[no-]smbv3", "Enable or disable SMBv3 (default: #{options[:smbv3] ? 'Enabled' : 'Disabled'})") do |smbv3|
41
- options[:smbv3] = smbv3
42
- end
43
- opts.on("--[no-]guests", "Allow guest accounts (default: #{options[:allow_guests]})") do |allow_guests|
44
- options[:allow_guests] = allow_guests
45
- end
46
- opts.on("--username USERNAME", "The account's username (default: #{options[:username]})") do |username|
47
- if username.include?('\\')
48
- options[:domain], options[:username] = username.split('\\', 2)
49
- else
50
- options[:username] = username
51
- end
52
- end
53
- opts.on("--password PASSWORD", "The account's password (default: #{options[:password]})") do |password|
54
- options[:password] = password
55
- end
56
- end.parse!
57
-
58
- ntlm_provider = RubySMB::Gss::Provider::NTLM.new(
59
- allow_anonymous: options[:allow_anonymous],
60
- allow_guests: options[:allow_guests]
61
- )
62
- ntlm_provider.put_account(options[:username], options[:password], domain: options[:domain]) # password can also be an NTLM hash
63
-
64
- server = RubySMB::Server.new(
65
- gss_provider: ntlm_provider,
66
- logger: :stdout
67
- )
68
- server.dialects.select! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB1 } unless options[:smbv1]
69
- server.dialects.select! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB2 } unless options[:smbv2]
70
- server.dialects.select! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB3 } unless options[:smbv3]
71
-
72
- if server.dialects.empty?
73
- puts "at least one version must be enabled"
74
- exit false
75
16
  end
76
17
 
18
+ server = RubySMB::Server::Cli.build(options)
77
19
  server.add_share(RubySMB::Server::Share::Provider::Disk.new(options[:share_name], options[:share_path]))
78
- puts "server is running"
79
- server.run do
80
- puts "received connection"
81
- true
82
- end
83
20
 
21
+ RubySMB::Server::Cli.run(server)
@@ -3,7 +3,6 @@
3
3
  require 'bundler/setup'
4
4
  require 'optparse'
5
5
  require 'ruby_smb'
6
- require 'ruby_smb/gss/provider/ntlm'
7
6
 
8
7
  # we just need *a* default encoding to handle the strings from the NTLM messages
9
8
  Encoding.default_internal = 'UTF-8' if Encoding.default_internal.nil?
@@ -32,70 +31,23 @@ MAGIC_8_BALL_ANSWERS = [
32
31
  'Very doubtful'
33
32
  ]
34
33
 
35
- options = {
36
- allow_anonymous: true,
37
- domain: nil,
38
- username: 'RubySMB',
39
- password: 'password',
40
- share_name: 'home',
41
- smbv1: true,
42
- smbv2: true,
43
- smbv3: true
44
- }
45
- OptionParser.new do |opts|
46
- opts.banner = "Usage: #{File.basename(__FILE__)} [options]"
47
- opts.on("--share SHARE", "The share name (default: #{options[:share_name]})") do |share|
48
- options[:share_name] = share
49
- end
50
- opts.on("--[no-]anonymous", "Allow anonymous access (default: #{options[:allow_anonymous]})") do |allow_anonymous|
51
- options[:allow_anonymous] = allow_anonymous
52
- end
53
- opts.on("--[no-]smbv1", "Enable or disable SMBv1 (default: #{options[:smbv1] ? 'Enabled' : 'Disabled'})") do |smbv1|
54
- options[:smbv1] = smbv1
55
- end
56
- opts.on("--[no-]smbv2", "Enable or disable SMBv2 (default: #{options[:smbv2] ? 'Enabled' : 'Disabled'})") do |smbv2|
57
- options[:smbv2] = smbv2
58
- end
59
- opts.on("--[no-]smbv3", "Enable or disable SMBv3 (default: #{options[:smbv3] ? 'Enabled' : 'Disabled'})") do |smbv3|
60
- options[:smbv3] = smbv3
61
- end
62
- opts.on("--username USERNAME", "The account's username (default: #{options[:username]})") do |username|
63
- if username.include?('\\')
64
- options[:domain], options[:username] = username.split('\\', 2)
65
- else
66
- options[:username] = username
67
- end
68
- end
69
- opts.on("--password PASSWORD", "The account's password (default: #{options[:password]})") do |password|
70
- options[:password] = password
71
- end
72
- opts.on("--virtual-content CONTENT", "The virtual share contents") do |virtual_content|
34
+ options = RubySMB::Server::Cli.parse do |options, parser|
35
+ parser.banner = "Usage: #{File.basename(__FILE__)} [options]"
36
+
37
+ parser.on("--virtual-content CONTENT", "The virtual share contents") do |virtual_content|
73
38
  options[:virtual_content] = virtual_content
74
39
  end
75
- opts.on("--virtual-name NAME", "The virtual share file name") do |virtual_name|
40
+
41
+ parser.on("--virtual-name NAME", "The virtual share file name") do |virtual_name|
76
42
  options[:virtual_name] = virtual_name
77
43
  end
78
- opts.on("--virtual-type TYPE", "The virtual share type") do |virtual_type|
44
+
45
+ parser.on("--virtual-type TYPE", "The virtual share type") do |virtual_type|
79
46
  options[:virtual_type] = virtual_type
80
47
  end
81
- end.parse!
82
-
83
- ntlm_provider = RubySMB::Gss::Provider::NTLM.new(allow_anonymous: options[:allow_anonymous])
84
- ntlm_provider.put_account(options[:username], options[:password], domain: options[:domain]) # password can also be an NTLM hash
85
-
86
- server = RubySMB::Server.new(
87
- gss_provider: ntlm_provider,
88
- logger: :stdout
89
- )
90
- server.dialects.select! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB1 } unless options[:smbv1]
91
- server.dialects.select! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB2 } unless options[:smbv2]
92
- server.dialects.select! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB3 } unless options[:smbv3]
93
-
94
- if server.dialects.empty?
95
- puts "at least one version must be enabled"
96
- exit false
97
48
  end
98
49
 
50
+ server = RubySMB::Server::Cli.build(options)
99
51
  virtual_disk = RubySMB::Server::Share::Provider::VirtualDisk.new(options[:share_name])
100
52
 
101
53
  # greeting is a static text file
@@ -135,9 +87,5 @@ elsif options[:virtual_content] || options[:virtual_name] || options[:virtual_ty
135
87
  end
136
88
 
137
89
  server.add_share(virtual_disk)
138
- puts "server is running"
139
- server.run do |server_client|
140
- puts "received connection"
141
- true
142
- end
143
90
 
91
+ RubySMB::Server::Cli.run(server)
@@ -332,7 +332,7 @@ module RubySMB
332
332
  # session setup response is received
333
333
  @session_encrypt_data = always_encrypt
334
334
 
335
- @ntlm_client = Net::NTLM::Client.new(
335
+ @ntlm_client = RubySMB::NTLM::Client.new(
336
336
  @username,
337
337
  @password,
338
338
  workstation: @local_workstation,
@@ -404,7 +404,7 @@ module RubySMB
404
404
  @password = pass.encode('utf-8') || ''.encode('utf-8')
405
405
  @username = user.encode('utf-8') || ''.encode('utf-8')
406
406
 
407
- @ntlm_client = Net::NTLM::Client.new(
407
+ @ntlm_client = RubySMB::NTLM::Client.new(
408
408
  @username,
409
409
  @password,
410
410
  workstation: @local_workstation,
@@ -0,0 +1,74 @@
1
+ module RubySMB::NTLM
2
+ module Message
3
+ def deflag
4
+ security_buffers.inject(head_size) do |cur, a|
5
+ a[1].offset = cur
6
+ cur += a[1].data_size
7
+ has_flag?(:UNICODE) ? cur + cur % 2 : cur
8
+ end
9
+ end
10
+
11
+ def serialize
12
+ deflag
13
+ @alist.map { |n, f| f.serialize }.join + security_buffers.map { |n, f| f.value + (has_flag?(:UNICODE) ? "\x00".b * (f.value.length % 2) : '') }.join
14
+ end
15
+ end
16
+
17
+ class Client < Net::NTLM::Client
18
+ class Session < Net::NTLM::Client::Session
19
+ def authenticate!
20
+ calculate_user_session_key!
21
+ type3_opts = {
22
+ :lm_response => is_anonymous? ? "\x00".b : lmv2_resp,
23
+ :ntlm_response => is_anonymous? ? '' : ntlmv2_resp,
24
+ :domain => domain,
25
+ :user => username,
26
+ :workstation => workstation,
27
+ :flag => (challenge_message.flag & client.flags)
28
+ }
29
+ t3 = Net::NTLM::Message::Type3.create type3_opts
30
+ t3.extend(Message)
31
+ if negotiate_key_exchange?
32
+ t3.enable(:session_key)
33
+ rc4 = OpenSSL::Cipher.new("rc4")
34
+ rc4.encrypt
35
+ rc4.key = user_session_key
36
+ sk = rc4.update exported_session_key
37
+ sk << rc4.final
38
+ t3.session_key = sk
39
+ end
40
+ t3
41
+ end
42
+
43
+ def is_anonymous?
44
+ username == '' && password == ''
45
+ end
46
+
47
+ private
48
+
49
+ def use_oem_strings?
50
+ # @see https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/99d90ff4-957f-4c8a-80e4-5bfe5a9a9832
51
+ !challenge_message.has_flag?(:UNICODE) && challenge_message.has_flag?(:OEM)
52
+ end
53
+
54
+ def calculate_user_session_key!
55
+ if is_anonymous?
56
+ # see MS-NLMP section 3.4
57
+ @user_session_key = "\x00".b * 16
58
+ else
59
+ @user_session_key = OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmv2_hash, nt_proof_str)
60
+ end
61
+ end
62
+ end
63
+
64
+ def init_context(resp = nil, channel_binding = nil)
65
+ if resp.nil?
66
+ @session = nil
67
+ type1_message
68
+ else
69
+ @session = Client::Session.new(self, Net::NTLM::Message.decode64(resp), channel_binding)
70
+ @session.authenticate!
71
+ end
72
+ end
73
+ end
74
+ end
data/lib/ruby_smb/ntlm.rb CHANGED
@@ -59,3 +59,4 @@ module RubySMB
59
59
  end
60
60
  end
61
61
 
62
+ require 'ruby_smb/ntlm/client'
@@ -0,0 +1,121 @@
1
+ require 'optparse'
2
+
3
+ module RubySMB
4
+ class Server
5
+ module Cli
6
+ DEFAULT_OPTIONS = {
7
+ allow_anonymous: true,
8
+ allow_guests: false,
9
+ domain: nil,
10
+ username: 'RubySMB',
11
+ password: 'password',
12
+ share_name: 'home',
13
+ smbv1: true,
14
+ smbv2: true,
15
+ smbv3: true
16
+ }.freeze
17
+
18
+ # Parse options from the command line. The resulting option hash is suitable for passing to {build}.
19
+ #
20
+ # @yield [options, parser] A block that can be used to update the built option parser.
21
+ # @yieldparam [Hash<Symbol => >] options The options hash that should be assigned to.
22
+ # @yieldparam [OptionParser] parser The built option parser.
23
+ # @param [Hash] defaults Default option values to use.
24
+ # @return [Hash<Symbol => >] The options hash.
25
+ # * :allow_anonymous [Boolean] Whether or not to allow anonymous authentication.
26
+ # * :allow_guest [Boolean] Whether or not to allow guest authentication.
27
+ # * :username [String] The username of the account to add for authentication.
28
+ # * :password [String] The password of the account to add for authentication.
29
+ # * :domain [String] The domain of the account to add for authentication.
30
+ # * :smbv1 [Boolean] Whether or not to enable SMBv1 dialects.
31
+ # * :smbv2 [Boolean] Whether or not to enable SMBv2 dialects.
32
+ # * :smbv3 [Boolean] Whether or not to enable SMBv3 dialects.
33
+ # * :share_name [String] The name of the share to add.
34
+ def self.parse(defaults: {}, &block)
35
+ defaults = DEFAULT_OPTIONS.merge(defaults)
36
+ options = defaults.clone
37
+ OptionParser.new do |parser|
38
+ parser.on("--share-name SHARE_NAME", "The share name (default: #{defaults[:share_name]})") do |share|
39
+ options[:share_name] = share
40
+ end
41
+
42
+ parser.on("--[no-]anonymous", "Allow anonymous access (default: #{defaults[:allow_anonymous]})") do |allow_anonymous|
43
+ options[:allow_anonymous] = allow_anonymous
44
+ end
45
+
46
+ parser.on("--[no-]guests", "Allow guest accounts (default: #{defaults[:allow_guests]})") do |allow_guests|
47
+ options[:allow_guests] = allow_guests
48
+ end
49
+
50
+ parser.on("--[no-]smbv1", "Enable or disable SMBv1 (default: #{defaults[:smbv1] ? 'Enabled' : 'Disabled'})") do |smbv1|
51
+ options[:smbv1] = smbv1
52
+ end
53
+
54
+ parser.on("--[no-]smbv2", "Enable or disable SMBv2 (default: #{defaults[:smbv2] ? 'Enabled' : 'Disabled'})") do |smbv2|
55
+ options[:smbv2] = smbv2
56
+ end
57
+
58
+ parser.on("--[no-]smbv3", "Enable or disable SMBv3 (default: #{defaults[:smbv3] ? 'Enabled' : 'Disabled'})") do |smbv3|
59
+ options[:smbv3] = smbv3
60
+ end
61
+
62
+ parser.on("--username USERNAME", "The account's username (default: #{defaults[:username]})") do |username|
63
+ if username.include?('\\')
64
+ options[:domain], options[:username] = username.split('\\', 2)
65
+ else
66
+ options[:username] = username
67
+ end
68
+ end
69
+
70
+ parser.on("--password PASSWORD", "The account's password (default: #{defaults[:password]})") do |password|
71
+ options[:password] = password
72
+ end
73
+
74
+ block.call(options, parser) if block_given?
75
+ end.parse!
76
+
77
+ options
78
+ end
79
+
80
+ # Build a server instance from the specified options. The NTLM provider will be used for authentication.
81
+ #
82
+ # @param [Hash] options the options to use while building the server. See the return value of {parse} for a
83
+ # comprehensive list of keys.
84
+ def self.build(options)
85
+ ntlm_provider = RubySMB::Gss::Provider::NTLM.new(
86
+ allow_anonymous: options[:allow_anonymous],
87
+ allow_guests: options[:allow_guests]
88
+ )
89
+ ntlm_provider.put_account(options[:username], options[:password], domain: options[:domain]) # password can also be an NTLM hash
90
+
91
+ server = RubySMB::Server.new(
92
+ gss_provider: ntlm_provider,
93
+ logger: :stdout
94
+ )
95
+ server.dialects.filter! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB1 } unless options[:smbv1]
96
+ server.dialects.filter! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB2 } unless options[:smbv2]
97
+ server.dialects.filter! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB3 } unless options[:smbv3]
98
+
99
+ server
100
+ end
101
+
102
+ # Run the server forever. At least 1 SMB dialect must be enabled.
103
+ #
104
+ # @param [RubySMB::Server] server The server instance to run.
105
+ # @param [#puts] out The stream to write standard output messages to.
106
+ # @param [#puts] err The stream to write error messages to.
107
+ def self.run(server, out: $stdout, err: $stderr)
108
+ if server.dialects.empty?
109
+ err.puts 'at least one version must be enabled'
110
+ return
111
+ end
112
+
113
+ out.puts 'server is running'
114
+ server.run do |server_client|
115
+ out.puts 'received connection'
116
+ true
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -6,6 +6,7 @@ module RubySMB
6
6
  # Currently, the server only supports negotiating and authenticating requests. No other server functionality is
7
7
  # available at this time. The negotiating and authentication is supported for SMB versions 1 through 3.1.1.
8
8
  class Server
9
+ require 'ruby_smb/server/cli'
9
10
  require 'ruby_smb/server/server_client'
10
11
  require 'ruby_smb/server/session'
11
12
  require 'ruby_smb/server/share'
@@ -1,3 +1,3 @@
1
1
  module RubySMB
2
- VERSION = '3.1.2'.freeze
2
+ VERSION = '3.1.3'.freeze
3
3
  end
@@ -0,0 +1,114 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe RubySMB::NTLM::Client::Session do
4
+ let(:message) { Net::NTLM::Message.decode64(%Q{
5
+ TlRMTVNTUAACAAAADAAMADgAAAA1goni+fNfw+cInOgAAAAAAAAAAJoAmgBE
6
+ AAAACgBjRQAAAA9NAFMARgBMAEEAQgACAAwATQBTAEYATABBAEIAAQAeAFcA
7
+ SQBOAC0AMwBNAFMAUAA4AEsAMgBMAEMARwBDAAQAGABtAHMAZgBsAGEAYgAu
8
+ AGwAbwBjAGEAbAADADgAVwBJAE4ALQAzAE0AUwBQADgASwAyAEwAQwBHAEMA
9
+ LgBtAHMAZgBsAGEAYgAuAGwAbwBjAGEAbAAHAAgAS6UAWjxl2AEAAAAA
10
+ }) }
11
+ subject(:client) { RubySMB::NTLM::Client.new('rubysmb', 'rubysmb', flags: RubySMB::NTLM::DEFAULT_CLIENT_FLAGS) }
12
+ subject(:session) { described_class.new(client, message) }
13
+
14
+ describe '#authenticate!' do
15
+ it 'calculates the user session key' do
16
+ expect(session).to receive(:calculate_user_session_key!).and_call_original
17
+ session.authenticate!
18
+ end
19
+
20
+ it 'checks if it is anonymous' do
21
+ expect(session).to receive(:is_anonymous?).at_least(1).times.and_call_original
22
+ session.authenticate!
23
+ end
24
+
25
+ it 'returns a Type3 message' do
26
+ expect(session.authenticate!).to be_a Net::NTLM::Message::Type3
27
+ expect(session.authenticate!).to be_a RubySMB::NTLM::Message
28
+ end
29
+
30
+ context 'when it is anonymous' do
31
+ before(:each) { allow(session).to receive(:is_anonymous?).and_return(true) }
32
+ after(:each) { session.authenticate! }
33
+
34
+ it 'uses the correct lm response' do
35
+ expect(session).to_not receive(:lmv2_resp)
36
+ expect(Net::NTLM::Message::Type3).to receive(:create).and_wrap_original do |method, params|
37
+ expect(params).to include :lm_response
38
+ expect(params[:lm_response]).to eq "\x00".b
39
+ method.call(params)
40
+ end
41
+ end
42
+
43
+ it 'uses the correct ntlm response' do
44
+ expect(session).to_not receive(:ntlmv2_resp)
45
+ expect(Net::NTLM::Message::Type3).to receive(:create).and_wrap_original do |method, params|
46
+ expect(params).to include :ntlm_response
47
+ expect(params[:ntlm_response]).to eq ''
48
+ method.call(params)
49
+ end
50
+ end
51
+ end
52
+
53
+ context 'when it is not anonymous' do
54
+ before(:each) { allow(session).to receive(:is_anonymous?).and_return(false) }
55
+ after(:each) { session.authenticate! }
56
+
57
+ it 'uses the correct lm response' do
58
+ expect(session).to receive(:lmv2_resp).and_call_original
59
+ expect(Net::NTLM::Message::Type3).to receive(:create).and_wrap_original do |method, params|
60
+ expect(params).to include :lm_response
61
+ expect(params[:lm_response].length).to be > 16
62
+ method.call(params)
63
+ end
64
+ end
65
+
66
+ it 'uses the correct ntlm response' do
67
+ expect(session).to receive(:ntlmv2_resp).and_call_original
68
+ expect(Net::NTLM::Message::Type3).to receive(:create).and_wrap_original do |method, params|
69
+ expect(params).to include :ntlm_response
70
+ expect(params[:ntlm_response].length).to be > 16
71
+ method.call(params)
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ describe '#calculate_user_session_key!' do
78
+ it 'returns an all zero key when it is anonymous' do
79
+ expect(session).to receive(:is_anonymous?).and_return(true)
80
+ expect(session.send(:calculate_user_session_key!)).to eq "\x00".b * 16
81
+ end
82
+
83
+ it 'returns a session key' do
84
+ expect(session).to receive(:is_anonymous?).and_return(false)
85
+ expect(session.send(:calculate_user_session_key!)).to_not eq "\x00".b * 16
86
+ end
87
+ end
88
+
89
+ describe '#is_anonymous?' do
90
+ it 'returns false when the username is not blank' do
91
+ allow(session).to receive(:username).and_return('username')
92
+ allow(session).to receive(:password).and_return('')
93
+ expect(session.is_anonymous?).to be false
94
+ end
95
+
96
+ it 'returns false when the password is not blank' do
97
+ allow(session).to receive(:username).and_return('')
98
+ allow(session).to receive(:password).and_return('password')
99
+ expect(session.is_anonymous?).to be false
100
+ end
101
+
102
+ it 'returns false when the username is not blank and the password is not blank' do
103
+ allow(session).to receive(:username).and_return('username')
104
+ allow(session).to receive(:password).and_return('password')
105
+ expect(session.is_anonymous?).to be false
106
+ end
107
+
108
+ it 'returns true when the username is blank and the password is blank' do
109
+ allow(session).to receive(:username).and_return('')
110
+ allow(session).to receive(:password).and_return('')
111
+ expect(session.is_anonymous?).to be true
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe RubySMB::NTLM::Client do
4
+ subject(:client) { described_class.new('rubysmb', 'rubysmb', flags: RubySMB::NTLM::DEFAULT_CLIENT_FLAGS) }
5
+
6
+ describe '#init_context' do
7
+ context 'when a response is provided' do
8
+ let(:resp) { %Q{
9
+ TlRMTVNTUAACAAAADAAMADgAAAA1goni+fNfw+cInOgAAAAAAAAAAJoAmgBE
10
+ AAAACgBjRQAAAA9NAFMARgBMAEEAQgACAAwATQBTAEYATABBAEIAAQAeAFcA
11
+ SQBOAC0AMwBNAFMAUAA4AEsAMgBMAEMARwBDAAQAGABtAHMAZgBsAGEAYgAu
12
+ AGwAbwBjAGEAbAADADgAVwBJAE4ALQAzAE0AUwBQADgASwAyAEwAQwBHAEMA
13
+ LgBtAHMAZgBsAGEAYgAuAGwAbwBjAGEAbAAHAAgAS6UAWjxl2AEAAAAA
14
+ } }
15
+ it 'returns a Type3 message' do
16
+ expect(client.init_context(resp)).to be_a Net::NTLM::Message::Type3
17
+ end
18
+
19
+ it 'creates a new session object' do
20
+ expect(RubySMB::NTLM::Client::Session).to receive(:new).and_call_original
21
+ client.init_context(resp)
22
+ end
23
+ end
24
+
25
+ context 'when a response is not provided' do
26
+ it 'returns a Type1 message' do
27
+ expect(client.init_context).to be_a Net::NTLM::Message::Type1
28
+ end
29
+
30
+ it 'does not create a new session object' do
31
+ expect(RubySMB::NTLM::Client::Session).to_not receive(:new)
32
+ client.init_context
33
+ end
34
+ end
35
+ end
36
+ end
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.1.2
4
+ version: 3.1.3
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-05-04 00:00:00.000000000 Z
100
+ date: 2022-05-24 00:00:00.000000000 Z
101
101
  dependencies:
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: redcarpet
@@ -473,7 +473,9 @@ files:
473
473
  - lib/ruby_smb/nbss/session_header.rb
474
474
  - lib/ruby_smb/nbss/session_request.rb
475
475
  - lib/ruby_smb/ntlm.rb
476
+ - lib/ruby_smb/ntlm/client.rb
476
477
  - lib/ruby_smb/server.rb
478
+ - lib/ruby_smb/server/cli.rb
477
479
  - lib/ruby_smb/server/server_client.rb
478
480
  - lib/ruby_smb/server/server_client/encryption.rb
479
481
  - lib/ruby_smb/server/server_client/negotiation.rb
@@ -802,6 +804,8 @@ files:
802
804
  - spec/lib/ruby_smb/nbss/netbios_name_spec.rb
803
805
  - spec/lib/ruby_smb/nbss/session_header_spec.rb
804
806
  - spec/lib/ruby_smb/nbss/session_request_spec.rb
807
+ - spec/lib/ruby_smb/ntlm/client/session_spec.rb
808
+ - spec/lib/ruby_smb/ntlm/client_spec.rb
805
809
  - spec/lib/ruby_smb/server/server_client_spec.rb
806
810
  - spec/lib/ruby_smb/server/session_spec.rb
807
811
  - spec/lib/ruby_smb/server/share/provider/disk_spec.rb
@@ -1112,6 +1116,8 @@ test_files:
1112
1116
  - spec/lib/ruby_smb/nbss/netbios_name_spec.rb
1113
1117
  - spec/lib/ruby_smb/nbss/session_header_spec.rb
1114
1118
  - spec/lib/ruby_smb/nbss/session_request_spec.rb
1119
+ - spec/lib/ruby_smb/ntlm/client/session_spec.rb
1120
+ - spec/lib/ruby_smb/ntlm/client_spec.rb
1115
1121
  - spec/lib/ruby_smb/server/server_client_spec.rb
1116
1122
  - spec/lib/ruby_smb/server/session_spec.rb
1117
1123
  - spec/lib/ruby_smb/server/share/provider/disk_spec.rb
metadata.gz.sig CHANGED
Binary file