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 +4 -4
- data/lib/ruby_smb/gss/provider/ntlm.rb +1 -1
- data/lib/ruby_smb/peer_info.rb +3 -1
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +37 -0
- data/spec/lib/ruby_smb/dcerpc/client_spec.rb +8 -0
- data/spec/lib/ruby_smb/gss/provider/ntlm/authenticator_spec.rb +13 -0
- data/spec/lib/ruby_smb/ntlm/client/session_spec.rb +19 -40
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9d886dad5cf6f498c65899db9f1e92e90ada198ec372944b1342aee7f080a75e
|
|
4
|
+
data.tar.gz: f0449b0250fcd31a7828011f0aff42695fe9c42c8bcb1317bacb7290726bacdb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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,
|
data/lib/ruby_smb/peer_info.rb
CHANGED
|
@@ -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,
|
data/lib/ruby_smb/version.rb
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
32
|
-
|
|
28
|
+
let(:username) { '' }
|
|
29
|
+
let(:password) { '' }
|
|
33
30
|
|
|
34
31
|
it 'uses the correct lm response' do
|
|
35
|
-
expect(session).
|
|
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).
|
|
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
|
|
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
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
|
|
85
|
-
expect(
|
|
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.
|
|
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-
|
|
16
|
+
date: 2026-09-28 00:00:00.000000000 Z
|
|
17
17
|
dependencies:
|
|
18
18
|
- !ruby/object:Gem::Dependency
|
|
19
19
|
name: redcarpet
|