CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/spec/lib/rex/proto/ldap/auth_spec.rb
Views: 1904
1
# frozen_string_literal: true
2
3
require 'rex/text'
4
require 'rex/proto/ntlm/message'
5
6
RSpec.describe Rex::Proto::LDAP::Auth do
7
subject(:nil_parameter_auth) do
8
described_class.new(nil, nil, nil, nil, nil)
9
end
10
11
subject(:parameter_auth) do
12
described_class.new('1122334455667788', 'my_domain', 'my_server', 'my_dnsname', 'my_dnsdomain')
13
end
14
15
before do
16
@type3 = "0\x82\x01D\x02\x01\x01`\x82\x01=\x02\x01\x03\x04\x00\xA3\x82\x014\x04\nGSS-SPNEGO\x04\x82\x01$NTLMSSP\x00\x03\x00\x00\x00\x18\x00\x18\x00@"\
17
"\x00\x00\x00\x92\x00\x92\x00X\x00\x00\x00\f\x00\f\x00\xEA\x00\x00\x00\b\x00\b\x00\xF6\x00\x00\x00\x16\x00\x16\x00\xFE\x00\x00\x00\x10\x00\x10"\
18
"\x00\x14\x01\x00\x00\x05\x02\x80BN\x98\xF8\x84,\x8At\b\x98\xEC\xB7\xC8\x15\x12l\x01\x92\xDDO\x88<\xFA\x0F\xF4Q\x9AA\x12\xC4\x991\xE2\xA0\xCETk"\
19
"\x83\x00\xCA\x8D\x01\x01\x00\x00\x00\x00\x00\x00\x80\x15sIU\t\xDA\x01\x92\xDDO\x88<\xFA\x0F\xF4\x00\x00\x00\x00\x02\x00\f\x00D\x00O\x00M\x00A\x00I\x00N"\
20
"\x00\x01\x00\f\x00S\x00E\x00R\x00V\x00E\x00R\x00\x04\x00\x16\x00e\x00x\x00a\x00m\x00p\x00l\x00e\x00.\x00c\x00o\x00m\x00\x03\x00$\x00S\x00E\x00R\x00V"\
21
"\x00E\x00R\x00.\x00e\x00x\x00a\x00m\x00p\x00l\x00e\x00.\x00c\x00o\x00m\x00\x00\x00\x00\x00D\x00O\x00M\x00A\x00I\x00N\x00U\x00s\x00e\x00r\x00W\x00O\x00R"\
22
"\x00K\x00S\x00T\x00A\x00T\x00I\x00O\x00N\x00\xFD\xF0\x01l#bF\xD2\x87\x14\x119#c*\xBA"
23
end
24
25
let(:user_login) { OpenStruct.new }
26
let(:ntlm_type1) do
27
ntlm1 = Net::NTLM::Message::Type1.new.serialize
28
29
sasl = ['GSS-SPNEGO'.to_ber, ntlm1.to_ber].to_ber_contextspecific(3)
30
br = [
31
Net::LDAP::Connection::LdapVersion.to_ber, ''.to_ber, sasl
32
].to_ber_appsequence(Net::LDAP::PDU::BindRequest)
33
34
type1 = [0.to_ber, br, nil].compact.to_ber_sequence.read_ber(Net::LDAP::AsnSyntax)
35
pdu = Net::LDAP::PDU.new(type1)
36
pdu.bind_parameters
37
end
38
let(:ntlm_type3) do
39
pdu = Net::LDAP::PDU.new(@type3.read_ber(Net::LDAP::AsnSyntax))
40
pdu.bind_parameters
41
end
42
43
context '#initialize' do
44
it 'sets default values when called with nil arguments' do
45
expect(nil_parameter_auth.instance_variable_get(:@domain)).to eq('DOMAIN')
46
expect(nil_parameter_auth.instance_variable_get(:@server)).to eq('SERVER')
47
expect(nil_parameter_auth.instance_variable_get(:@dnsname)).to eq('server')
48
expect(nil_parameter_auth.instance_variable_get(:@dnsdomain)).to eq('example.com')
49
expect(nil_parameter_auth.instance_variable_get(:@challenge).length).to eq(8)
50
end
51
52
it 'sets provided values when called with arguments' do
53
expect(parameter_auth.instance_variable_get(:@domain)).to eq('my_domain')
54
expect(parameter_auth.instance_variable_get(:@server)).to eq('my_server')
55
expect(parameter_auth.instance_variable_get(:@dnsname)).to eq('my_dnsname')
56
expect(parameter_auth.instance_variable_get(:@dnsdomain)).to eq('my_dnsdomain')
57
expect(parameter_auth.instance_variable_get(:@challenge).length).to eq(8)
58
end
59
end
60
61
context '#handle_anonymous_request' do
62
before do
63
user_login.name = ''
64
user_login.authentication = ''
65
end
66
67
it 'returns a hash with expected values for anonymous requests' do
68
result = parameter_auth.handle_anonymous_request(user_login)
69
70
expect(result[:user]).to eq('')
71
expect(result[:pass]).to eq('')
72
expect(result[:domain]).to be_nil
73
expect(result[:auth_type]).to eq('Anonymous')
74
expect(result[:result_code]).to eq(Net::LDAP::ResultCodeSuccess)
75
end
76
end
77
78
context '#handle_simple_request' do
79
it 'handles requests with an username and domain in a DN object' do
80
user_login.name = 'cn=username,dc=domain,dc=com'
81
user_login.authentication = 'password'
82
83
result = parameter_auth.handle_simple_request(user_login)
84
85
expect(result[:user]).to eq('username')
86
expect(result[:domain]).to eq('domain.com')
87
expect(result[:private]).to eq('password')
88
expect(result[:private_type]).to eq(:password)
89
expect(result[:result_code]).to eq(Net::LDAP::ResultCodeAuthMethodNotSupported)
90
expect(result[:auth_type]).to eq('Simple')
91
end
92
93
it 'handles requests with an username and multiple DC components for domain in a DN object' do
94
user_login.name = 'cn=username,dc=domain1,dc=domain2,dc=domain3'
95
user_login.authentication = 'password'
96
97
result = parameter_auth.handle_simple_request(user_login)
98
99
expect(result[:user]).to eq('username')
100
expect(result[:domain]).to eq('domain1.domain2.domain3')
101
expect(result[:private]).to eq('password')
102
expect(result[:private_type]).to eq(:password)
103
expect(result[:result_code]).to eq(Net::LDAP::ResultCodeAuthMethodNotSupported)
104
expect(result[:auth_type]).to eq('Simple')
105
end
106
107
it 'handles requests with information in the form of username@domain' do
108
user_login.name = '[email protected]'
109
user_login.authentication = 'password'
110
111
result = parameter_auth.handle_simple_request(user_login)
112
113
expect(result[:user]).to eq('username')
114
expect(result[:domain]).to eq('domain.com')
115
expect(result[:private]).to eq('password')
116
expect(result[:private_type]).to eq(:password)
117
expect(result[:result_code]).to eq(Net::LDAP::ResultCodeAuthMethodNotSupported)
118
expect(result[:auth_type]).to eq('Simple')
119
end
120
121
it 'handles requests with invalid DN and CN components' do
122
user_login.name = 'cn=user,name,mydomain,dc=com'
123
user_login.authentication = 'password'
124
125
expect { parameter_auth.handle_simple_request(user_login) }.to raise_error(Net::LDAP::InvalidDNError)
126
end
127
128
it 'handles requests with username and domain in NETBIOS format' do
129
user_login.name = 'domain\\username'
130
user_login.authentication = 'password'
131
132
result = parameter_auth.handle_simple_request(user_login)
133
134
expect(result[:user]).to eq('username')
135
expect(result[:domain]).to eq('domain')
136
expect(result[:private]).to eq('password')
137
expect(result[:private_type]).to eq(:password)
138
expect(result[:result_code]).to eq(Net::LDAP::ResultCodeAuthMethodNotSupported)
139
expect(result[:auth_type]).to eq('Simple')
140
end
141
142
it 'handles authentication requests with incorrect request format' do
143
user_login.name = 'username'
144
user_login.authentication = 'password'
145
146
result = parameter_auth.handle_simple_request(user_login)
147
148
expect(result[:user]).to eq('username')
149
expect(result[:domain]).to be_nil
150
expect(result[:private]).to eq('password')
151
expect(result[:private_type]).to eq(:password)
152
expect(result[:result_code]).to eq(Net::LDAP::ResultCodeInvalidCredentials)
153
expect(result[:auth_type]).to eq('Simple')
154
end
155
end
156
157
context '#handle_sasl_request' do
158
context 'using GSS-SPNEGO mechanism' do
159
context 'using LM/NTLM authentication' do
160
it 'handles NTLM Type1 requests with an NTLM type2 response' do
161
result = parameter_auth.handle_sasl_request(ntlm_type1)
162
163
expect(result[:server_creds]).to be_a(String)
164
expect(Net::NTLM::Message.parse(result[:server_creds])).to(be_a(Net::NTLM::Message::Type2))
165
expect(result[:result_code]).to eq(Net::LDAP::ResultCodeSaslBindInProgress)
166
expect(result[:auth_type]).to eq('SASL')
167
end
168
169
it 'handles NTLM Type3 requests containing client information' do
170
result = parameter_auth.handle_sasl_request(ntlm_type3)
171
172
expect(result[:domain]).to eq('DOMAIN')
173
expect(result[:user]).to eq('User')
174
expect(result[:private]).not_to be_nil
175
expect(result[:private_type]).to eq(:ntlm_hash)
176
expect(result[:auth_type]).to eq('SASL')
177
expect(result[:result_code]).to eq(Net::LDAP::ResultCodeAuthMethodNotSupported)
178
expect(result[:auth_type]).to eq('SASL')
179
end
180
end
181
182
context 'unsupprted SASL value' do
183
let(:request) do
184
auth_message = 'INVALIDSSP'
185
sasl = ['GSS-SPNEGO'.to_ber, auth_message.to_ber].to_ber_contextspecific(3)
186
br = [
187
Net::LDAP::Connection::LdapVersion.to_ber, ''.to_ber, sasl
188
].to_ber_appsequence(Net::LDAP::PDU::BindRequest)
189
190
type1 = [0.to_ber, br, nil].compact.to_ber_sequence.read_ber(Net::LDAP::AsnSyntax)
191
pdu = Net::LDAP::PDU.new(type1)
192
pdu.bind_parameters
193
end
194
it 'hanldes and unknown SASL header as unsuppoted' do
195
result = parameter_auth.handle_sasl_request(request)
196
expect(result[:auth_type]).to eq('SASL')
197
expect(result[:result_code]).to eq(Net::LDAP::ResultCodeAuthMethodNotSupported)
198
end
199
end
200
end
201
end
202
203
context 'private methods' do
204
context '#generate_type2_response' do
205
it 'returns a valid NTLM Type2 message from NTLM Type1 message' do
206
message = Net::NTLM::Message.parse(ntlm_type1.authentication[1])
207
result = parameter_auth.send(:generate_type2_response, message)
208
209
expect(result).to be_a(String)
210
end
211
end
212
213
context '#handle_type3_message' do
214
it 'handles NTLM Type3 message and returns the expected authentication information' do
215
message = Net::NTLM::Message.parse(ntlm_type3.authentication[1])
216
result = parameter_auth.send(:handle_type3_message, message)
217
218
expect(result[:domain]).to eq('DOMAIN')
219
expect(result[:user]).to eq('User')
220
expect(result[:private]).not_to be_nil
221
expect(result[:private_type]).to eq(:ntlm_hash)
222
expect(result[:ntlm_ver]).not_to be_nil
223
end
224
end
225
226
context '#process_ntlm_hash' do
227
it 'processes NTLM hash from Type3 message and returns the expected information' do
228
ntlm_info = {
229
ntlm_ver: NTLM_CONST::NTLM_V2_RESPONSE,
230
lm_hash: '054ab6f7f2d60c068bf03a4e27d99834',
231
lm_cli_challenge: '2464587cc5ef2d6c',
232
nt_hash: '93d3aa55263a1d37931a67a5b54710b8',
233
nt_cli_challenge: '0101000000000000006e8eed5507da012464587cc5ef2d6c0000000002000c004
234
4004f004d00410049004e0001000c005300450052005600450052000400160065
235
00780061006d0070006c0065002e0063006f006d0003002400530045005200560
236
0450052002e006500780061006d0070006c0065002e0063006f006d0000000000',
237
domain: "D\x00O\x00M\x00A\x00I\x00N\x00",
238
user: "U\x00s\x00e\x00r\x00",
239
host: "W\x00O\x00R\x00K\x00S\x00T\x00A\x00T\x00I\x00O\x00N\x00"
240
}
241
242
result = parameter_auth.send(:process_ntlm_hash, ntlm_info)
243
244
expect(result[:domain]).to eq('DOMAIN')
245
expect(result[:user]).to eq('User')
246
expect(result[:private]).not_to be_nil
247
expect(result[:private_type]).to eq(:ntlm_hash)
248
expect(result[:ntlm_ver]).not_to be_nil
249
end
250
end
251
end
252
end
253
254