ruby_smb 3.3.22 → 3.3.23

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: ef6a12241de5bf3b7f37028f5dd927f1bc71249e37c77f2bb8d1575836bc9889
4
- data.tar.gz: 624c0708b392f448c17d163b71ef821902d83d17f5f632d7416f6a691041bb79
3
+ metadata.gz: 9d886dad5cf6f498c65899db9f1e92e90ada198ec372944b1342aee7f080a75e
4
+ data.tar.gz: f0449b0250fcd31a7828011f0aff42695fe9c42c8bcb1317bacb7290726bacdb
5
5
  SHA512:
6
- metadata.gz: 5b518493f293005ce5b805221625a03cb937d7b2218029824f5cabb577f70cfdf8a1cd6ed6b08b6fc75a57c490200c20b469b8e347a3625d4e633f716d05929c
7
- data.tar.gz: 92e4ce7a72b4d7c8b9f140df9bb94e8798810f9ec0491bff81c295e68b0ebc07b17bd1f0c72e38cc7f8a2fb86ae14b08065296d83969adfe99b22038a1c24f33
6
+ metadata.gz: f905b9bb1f1e300203da9ba5cecc6c171398e88df7dd810a16b6cbe96974412f0ea5c076dfd7af792601944a86d42c93587fdf379ce5e6879bf9761b8d88dacd
7
+ data.tar.gz: 2a2f83457861f8dd05f95bb3cc67364bde774ff9190986cf7b2704a1ddafc55e69645a1964e33c42a735db2f89fbfe241073bc4687ed034528830dc026e3e9dd
@@ -85,7 +85,7 @@ module RubySMB
85
85
 
86
86
  @server_challenge = @provider.generate_server_challenge
87
87
  msg.challenge = @server_challenge.unpack1('Q<') # 64-bit unsigned, little endian (uint64_t)
88
- target_info = Net::NTLM::TargetInfo.new('')
88
+ target_info = Net::NTLM::TargetInfo.new(nil)
89
89
  target_info.av_pairs.merge!({
90
90
  Net::NTLM::TargetInfo::MSV_AV_NB_DOMAIN_NAME => @provider.netbios_domain.encode('UTF-16LE').b,
91
91
  Net::NTLM::TargetInfo::MSV_AV_NB_COMPUTER_NAME => @provider.netbios_hostname.encode('UTF-16LE').b,
@@ -3,8 +3,10 @@ module RubySMB
3
3
  # Extract and store useful information about the peer/server from the
4
4
  # NTLM Type 2 (challenge) TargetInfo fields.
5
5
  #
6
- # @param target_info_str [String] the Target Info string
6
+ # @param target_info_str [String, nil] the Target Info string
7
7
  def store_target_info(target_info_str)
8
+ return if target_info_str.nil? || target_info_str.empty?
9
+
8
10
  target_info = Net::NTLM::TargetInfo.new(target_info_str)
9
11
  {
10
12
  Net::NTLM::TargetInfo::MSV_AV_NB_COMPUTER_NAME => :@default_name,
@@ -1,3 +1,3 @@
1
1
  module RubySMB
2
- VERSION = '3.3.22'.freeze
2
+ VERSION = '3.3.23'.freeze
3
3
  end
@@ -1614,6 +1614,15 @@ RSpec.describe RubySMB::Client do
1614
1614
  expect(smb1_client.session_key).to eq ntlm_client.session_key
1615
1615
  end
1616
1616
 
1617
+ it 'continues authentication when the server advertises empty target info' do
1618
+ challenge = Net::NTLM::Message.decode64(type2_string)
1619
+ challenge.set_flag(:TARGET_INFO)
1620
+ challenge.target_info = ''.b
1621
+ allow(smb1_client).to receive(:smb1_type2_message).and_return(challenge.encode64)
1622
+
1623
+ expect(smb1_client.smb1_authenticate).to eq WindowsError::NTStatus::STATUS_SUCCESS
1624
+ end
1625
+
1617
1626
  it 'stores the OS version number from the challenge message' do
1618
1627
  smb1_client.smb1_authenticate
1619
1628
  expect(smb1_client.os_version).to eq '6.1.7601'
@@ -1860,6 +1869,15 @@ RSpec.describe RubySMB::Client do
1860
1869
  expect(smb2_client.session_key).to eq ntlm_client.session_key
1861
1870
  end
1862
1871
 
1872
+ it 'continues authentication when the server advertises empty target info' do
1873
+ challenge = Net::NTLM::Message.decode64(type2_string)
1874
+ challenge.set_flag(:TARGET_INFO)
1875
+ challenge.target_info = ''.b
1876
+ allow(smb2_client).to receive(:smb2_type2_message).and_return(challenge.encode64)
1877
+
1878
+ expect(smb2_client.smb2_authenticate).to eq WindowsError::NTStatus::STATUS_SUCCESS
1879
+ end
1880
+
1863
1881
  it 'stores the OS version number from the challenge message' do
1864
1882
  smb2_client.smb2_authenticate
1865
1883
  expect(smb2_client.os_version).to eq '6.1.7601'
@@ -2068,6 +2086,25 @@ RSpec.describe RubySMB::Client do
2068
2086
  client.store_target_info(target_info_str)
2069
2087
  end
2070
2088
 
2089
+ it 'preserves existing peer information when given empty target info' do
2090
+ client.store_target_info(target_info_str)
2091
+ expect { client.store_target_info(''.b) }.to_not change {
2092
+ [client.default_name, client.default_domain, client.dns_host_name, client.dns_domain_name, client.dns_tree_name]
2093
+ }
2094
+ end
2095
+
2096
+ it 'accepts nil target info' do
2097
+ expect { client.store_target_info(nil) }.to_not raise_error
2098
+ end
2099
+
2100
+ it 'accepts empty target info encoded with an end-of-list marker' do
2101
+ expect { client.store_target_info("\x00\x00\x00\x00".b) }.to_not raise_error
2102
+ end
2103
+
2104
+ it 'rejects nonempty invalid target info' do
2105
+ expect { client.store_target_info("\xff\xff\x00\x00".b) }.to raise_error(Net::NTLM::InvalidTargetDataError)
2106
+ end
2107
+
2071
2108
  it 'sets the expected Client\'s attribute' do
2072
2109
  client.store_target_info(target_info_str)
2073
2110
  expect(client.default_name).to eq 'TESTNAME'
@@ -173,6 +173,14 @@ RSpec.describe RubySMB::Dcerpc::Client do
173
173
  expect(auth_client.process_ntlm_type2(type2_message)).to start_with("NTLMSSP\x00\x03\x00\x00\x00")
174
174
  end
175
175
 
176
+ it 'returns a type3 message when the server advertises empty target info' do
177
+ challenge = Net::NTLM::Message.parse(type2_message)
178
+ challenge.set_flag(:TARGET_INFO)
179
+ challenge.target_info = ''.b
180
+
181
+ expect(auth_client.process_ntlm_type2(challenge.serialize)).to start_with("NTLMSSP\x00\x03\x00\x00\x00")
182
+ end
183
+
176
184
  it 'stores the session key' do
177
185
  auth_client.process_ntlm_type2(type2_message)
178
186
  expect(auth_client.instance_variable_get(:@session_key).size).to eq(16)
@@ -65,6 +65,19 @@ RSpec.describe RubySMB::Gss::Provider::NTLM::Authenticator do
65
65
  it 'should process a NTLM type 1 message and return a type2 message' do
66
66
  expect(authenticator.process_ntlm_type1(type1_msg)).to be_a Net::NTLM::Message::Type2
67
67
  end
68
+
69
+ it 'includes the server names in the serialized target info' do
70
+ type2_msg = Net::NTLM::Message.parse(authenticator.process_ntlm_type1(type1_msg).serialize)
71
+ target_info = Net::NTLM::TargetInfo.new(type2_msg.target_info)
72
+
73
+ expect(target_info.av_pairs).to include(
74
+ Net::NTLM::TargetInfo::MSV_AV_NB_DOMAIN_NAME => provider.netbios_domain.encode('UTF-16LE').b,
75
+ Net::NTLM::TargetInfo::MSV_AV_NB_COMPUTER_NAME => provider.netbios_hostname.encode('UTF-16LE').b,
76
+ Net::NTLM::TargetInfo::MSV_AV_DNS_DOMAIN_NAME => provider.dns_domain.encode('UTF-16LE').b,
77
+ Net::NTLM::TargetInfo::MSV_AV_DNS_COMPUTER_NAME => provider.dns_hostname.encode('UTF-16LE').b
78
+ )
79
+ expect(target_info.av_pairs[Net::NTLM::TargetInfo::MSV_AV_TIMESTAMP].bytesize).to eq 8
80
+ end
68
81
  end
69
82
 
70
83
  describe '#process_ntlm_type3' do
@@ -8,7 +8,9 @@ RSpec.describe RubySMB::NTLM::Client::Session do
8
8
  AGwAbwBjAGEAbAADADgAVwBJAE4ALQAzAE0AUwBQADgASwAyAEwAQwBHAEMA
9
9
  LgBtAHMAZgBsAGEAYgAuAGwAbwBjAGEAbAAHAAgAS6UAWjxl2AEAAAAA
10
10
  }) }
11
- subject(:client) { RubySMB::NTLM::Client.new('rubysmb', 'rubysmb', flags: RubySMB::NTLM::DEFAULT_CLIENT_FLAGS) }
11
+ let(:username) { 'rubysmb' }
12
+ let(:password) { 'rubysmb' }
13
+ let(:client) { RubySMB::NTLM::Client.new(username, password, flags: RubySMB::NTLM::DEFAULT_CLIENT_FLAGS) }
12
14
  subject(:session) { described_class.new(client, message) }
13
15
 
14
16
  describe '#authenticate!' do
@@ -17,72 +19,49 @@ RSpec.describe RubySMB::NTLM::Client::Session do
17
19
  session.authenticate!
18
20
  end
19
21
 
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
22
  it 'returns a Type3 message' do
26
23
  expect(session.authenticate!).to be_a Net::NTLM::Message::Type3
27
24
  expect(session.authenticate!).to be_a Net::NTLM::Message
28
25
  end
29
26
 
30
27
  context 'when it is anonymous' do
31
- before(:each) { allow(session).to receive(:is_anonymous?).and_return(true) }
32
- after(:each) { session.authenticate! }
28
+ let(:username) { '' }
29
+ let(:password) { '' }
33
30
 
34
31
  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
32
+ expect(session.authenticate!.lm_response).to eq "\x00".b
41
33
  end
42
34
 
43
35
  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
36
+ expect(session.authenticate!.ntlm_response).to eq ''
50
37
  end
51
38
  end
52
39
 
53
40
  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
41
  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
42
+ expect(session.authenticate!.lm_response.length).to be > 16
64
43
  end
65
44
 
66
45
  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
46
+ expect(session.authenticate!.ntlm_response.length).to be > 16
73
47
  end
74
48
  end
75
49
  end
76
50
 
77
51
  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
52
+ context 'when it is anonymous' do
53
+ let(:username) { '' }
54
+ let(:password) { '' }
55
+
56
+ it 'returns an all zero key' do
57
+ expect(session.send(:calculate_user_session_key!)).to eq "\x00".b * 16
58
+ end
81
59
  end
82
60
 
83
61
  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
62
+ session_key = session.send(:calculate_user_session_key!)
63
+ expect(session_key.bytesize).to eq 16
64
+ expect(session_key).to_not eq "\x00".b * 16
86
65
  end
87
66
  end
88
67
 
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.3.22
4
+ version: 3.3.23
5
5
  platform: ruby
6
6
  authors:
7
7
  - Metasploit Hackers
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2026-07-31 00:00:00.000000000 Z
16
+ date: 2026-09-28 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: redcarpet