ruby_smb 3.1.2 → 3.1.3

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