rubyntlm 0.5.3 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -3
- data/.rspec +2 -2
- data/.travis.yml +10 -11
- data/CHANGELOG.md +5 -5
- data/Gemfile +3 -3
- data/LICENSE +19 -19
- data/Rakefile +22 -22
- data/lib/net/ntlm.rb +266 -263
- data/lib/net/ntlm/blob.rb +28 -28
- data/lib/net/ntlm/channel_binding.rb +65 -0
- data/lib/net/ntlm/client.rb +65 -65
- data/lib/net/ntlm/client/session.rb +237 -223
- data/lib/net/ntlm/encode_util.rb +49 -49
- data/lib/net/ntlm/exceptions.rb +14 -0
- data/lib/net/ntlm/field.rb +34 -34
- data/lib/net/ntlm/field_set.rb +129 -129
- data/lib/net/ntlm/int16_le.rb +25 -25
- data/lib/net/ntlm/int32_le.rb +24 -24
- data/lib/net/ntlm/int64_le.rb +25 -25
- data/lib/net/ntlm/message.rb +129 -129
- data/lib/net/ntlm/message/type0.rb +16 -16
- data/lib/net/ntlm/message/type1.rb +18 -18
- data/lib/net/ntlm/message/type2.rb +102 -102
- data/lib/net/ntlm/message/type3.rb +131 -131
- data/lib/net/ntlm/security_buffer.rb +47 -47
- data/lib/net/ntlm/string.rb +34 -34
- data/lib/net/ntlm/target_info.rb +89 -0
- data/lib/net/ntlm/version.rb +11 -11
- data/rubyntlm.gemspec +28 -28
- data/spec/lib/net/ntlm/blob_spec.rb +16 -16
- data/spec/lib/net/ntlm/channel_binding_spec.rb +17 -0
- data/spec/lib/net/ntlm/client/session_spec.rb +68 -68
- data/spec/lib/net/ntlm/client_spec.rb +64 -64
- data/spec/lib/net/ntlm/encode_util_spec.rb +16 -16
- data/spec/lib/net/ntlm/field_set_spec.rb +33 -33
- data/spec/lib/net/ntlm/field_spec.rb +34 -34
- data/spec/lib/net/ntlm/int16_le_spec.rb +17 -17
- data/spec/lib/net/ntlm/int32_le_spec.rb +18 -18
- data/spec/lib/net/ntlm/int64_le_spec.rb +18 -18
- data/spec/lib/net/ntlm/message/type0_spec.rb +20 -20
- data/spec/lib/net/ntlm/message/type1_spec.rb +131 -131
- data/spec/lib/net/ntlm/message/type2_spec.rb +132 -132
- data/spec/lib/net/ntlm/message/type3_spec.rb +225 -225
- data/spec/lib/net/ntlm/message_spec.rb +16 -16
- data/spec/lib/net/ntlm/security_buffer_spec.rb +64 -64
- data/spec/lib/net/ntlm/string_spec.rb +72 -72
- data/spec/lib/net/ntlm/target_info_spec.rb +76 -0
- data/spec/lib/net/ntlm/version_spec.rb +27 -27
- data/spec/lib/net/ntlm_spec.rb +127 -127
- data/spec/spec_helper.rb +22 -22
- data/spec/support/certificates/sha_256_hash.pem +19 -0
- data/spec/support/shared/examples/net/ntlm/field_shared.rb +25 -25
- data/spec/support/shared/examples/net/ntlm/fieldset_shared.rb +239 -239
- data/spec/support/shared/examples/net/ntlm/int_shared.rb +43 -43
- data/spec/support/shared/examples/net/ntlm/message_shared.rb +35 -35
- metadata +12 -3
@@ -1,17 +1,17 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Net::NTLM::Message do
|
4
|
-
|
5
|
-
fields = []
|
6
|
-
flags = [
|
7
|
-
:UNICODE,
|
8
|
-
:OEM,
|
9
|
-
:REQUEST_TARGET,
|
10
|
-
:NTLM,
|
11
|
-
:ALWAYS_SIGN,
|
12
|
-
:NTLM2_KEY
|
13
|
-
]
|
14
|
-
it_behaves_like 'a fieldset', fields
|
15
|
-
it_behaves_like 'a message', flags
|
16
|
-
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Net::NTLM::Message do
|
4
|
+
|
5
|
+
fields = []
|
6
|
+
flags = [
|
7
|
+
:UNICODE,
|
8
|
+
:OEM,
|
9
|
+
:REQUEST_TARGET,
|
10
|
+
:NTLM,
|
11
|
+
:ALWAYS_SIGN,
|
12
|
+
:NTLM2_KEY
|
13
|
+
]
|
14
|
+
it_behaves_like 'a fieldset', fields
|
15
|
+
it_behaves_like 'a message', flags
|
16
|
+
|
17
17
|
end
|
@@ -1,64 +1,64 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Net::NTLM::SecurityBuffer do
|
4
|
-
|
5
|
-
fields = [
|
6
|
-
{ :name => :length, :class => Net::NTLM::Int16LE, :value => 0, :active => true },
|
7
|
-
{ :name => :allocated, :class => Net::NTLM::Int16LE, :value => 0, :active => true },
|
8
|
-
{ :name => :offset, :class => Net::NTLM::Int32LE, :value => 0, :active => true },
|
9
|
-
]
|
10
|
-
|
11
|
-
it_behaves_like 'a fieldset', fields
|
12
|
-
it_behaves_like 'a field', 'WORKSTATION', true
|
13
|
-
|
14
|
-
|
15
|
-
subject(:domain_security_buffer) do
|
16
|
-
Net::NTLM::SecurityBuffer.new({
|
17
|
-
:value => 'WORKSTATION',
|
18
|
-
:active => true
|
19
|
-
})
|
20
|
-
end
|
21
|
-
|
22
|
-
context 'when setting the value directly' do
|
23
|
-
before(:each) do
|
24
|
-
domain_security_buffer.value = 'DOMAIN1'
|
25
|
-
end
|
26
|
-
it 'should change the value' do
|
27
|
-
expect(domain_security_buffer.value).to eq('DOMAIN1')
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'should adjust the length field to the size of the new value' do
|
31
|
-
expect(domain_security_buffer.length).to eq(7)
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'should adjust the allocated field to the size of the new value' do
|
35
|
-
expect(domain_security_buffer.allocated).to eq(7)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
context '#data_size' do
|
40
|
-
it 'should return the size of the value if active' do
|
41
|
-
expect(domain_security_buffer.data_size).to eq(11)
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'should return 0 if inactive' do
|
45
|
-
domain_security_buffer.active = false
|
46
|
-
expect(domain_security_buffer.data_size).to eq(0)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
context '#parse' do
|
51
|
-
it 'should read in a properly formatted string' do
|
52
|
-
# Length of the string is 8
|
53
|
-
length = "\x08\x00"
|
54
|
-
# Space allocated is 8
|
55
|
-
allocated = "\x08\x00"
|
56
|
-
# The offset that the actual value begins at is also 8
|
57
|
-
offset = "\x08\x00\x00\x00"
|
58
|
-
string_to_parse = "#{length}#{allocated}#{offset}FooBarBaz"
|
59
|
-
expect(domain_security_buffer.parse(string_to_parse)).to eq(8)
|
60
|
-
expect(domain_security_buffer.value).to eq('FooBarBa')
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
end
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Net::NTLM::SecurityBuffer do
|
4
|
+
|
5
|
+
fields = [
|
6
|
+
{ :name => :length, :class => Net::NTLM::Int16LE, :value => 0, :active => true },
|
7
|
+
{ :name => :allocated, :class => Net::NTLM::Int16LE, :value => 0, :active => true },
|
8
|
+
{ :name => :offset, :class => Net::NTLM::Int32LE, :value => 0, :active => true },
|
9
|
+
]
|
10
|
+
|
11
|
+
it_behaves_like 'a fieldset', fields
|
12
|
+
it_behaves_like 'a field', 'WORKSTATION', true
|
13
|
+
|
14
|
+
|
15
|
+
subject(:domain_security_buffer) do
|
16
|
+
Net::NTLM::SecurityBuffer.new({
|
17
|
+
:value => 'WORKSTATION',
|
18
|
+
:active => true
|
19
|
+
})
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when setting the value directly' do
|
23
|
+
before(:each) do
|
24
|
+
domain_security_buffer.value = 'DOMAIN1'
|
25
|
+
end
|
26
|
+
it 'should change the value' do
|
27
|
+
expect(domain_security_buffer.value).to eq('DOMAIN1')
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should adjust the length field to the size of the new value' do
|
31
|
+
expect(domain_security_buffer.length).to eq(7)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should adjust the allocated field to the size of the new value' do
|
35
|
+
expect(domain_security_buffer.allocated).to eq(7)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context '#data_size' do
|
40
|
+
it 'should return the size of the value if active' do
|
41
|
+
expect(domain_security_buffer.data_size).to eq(11)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should return 0 if inactive' do
|
45
|
+
domain_security_buffer.active = false
|
46
|
+
expect(domain_security_buffer.data_size).to eq(0)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context '#parse' do
|
51
|
+
it 'should read in a properly formatted string' do
|
52
|
+
# Length of the string is 8
|
53
|
+
length = "\x08\x00"
|
54
|
+
# Space allocated is 8
|
55
|
+
allocated = "\x08\x00"
|
56
|
+
# The offset that the actual value begins at is also 8
|
57
|
+
offset = "\x08\x00\x00\x00"
|
58
|
+
string_to_parse = "#{length}#{allocated}#{offset}FooBarBaz"
|
59
|
+
expect(domain_security_buffer.parse(string_to_parse)).to eq(8)
|
60
|
+
expect(domain_security_buffer.value).to eq('FooBarBa')
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
@@ -1,72 +1,72 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Net::NTLM::String do
|
4
|
-
|
5
|
-
it_behaves_like 'a field', 'Foo', false
|
6
|
-
|
7
|
-
let(:active) {
|
8
|
-
Net::NTLM::String.new({
|
9
|
-
:value => 'Test',
|
10
|
-
:active => true,
|
11
|
-
:size => 4
|
12
|
-
})
|
13
|
-
}
|
14
|
-
|
15
|
-
let(:inactive) {
|
16
|
-
Net::NTLM::String.new({
|
17
|
-
:value => 'Test',
|
18
|
-
:active => false,
|
19
|
-
:size => 4
|
20
|
-
})
|
21
|
-
}
|
22
|
-
|
23
|
-
context '#serialize' do
|
24
|
-
it 'should return the value when active' do
|
25
|
-
expect(active.serialize).to eq('Test')
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'should return an empty string when inactive' do
|
29
|
-
expect(inactive.serialize).to eq('')
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'should coerce non-string values into strings' do
|
33
|
-
active.value = 15
|
34
|
-
expect(active.serialize).to eq('15')
|
35
|
-
end
|
36
|
-
|
37
|
-
it 'should return empty string on a nil' do
|
38
|
-
active.value = nil
|
39
|
-
expect(active.serialize).to eq('')
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
context '#value=' do
|
44
|
-
it 'should set active to false if it empty' do
|
45
|
-
active.value = ''
|
46
|
-
expect(active.active).to eq(false)
|
47
|
-
end
|
48
|
-
|
49
|
-
it 'should adjust the size based on the value set' do
|
50
|
-
expect(active.size).to eq(4)
|
51
|
-
active.value = 'Foobar'
|
52
|
-
expect(active.size).to eq(6)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
context '#parse' do
|
57
|
-
it 'should read in a string of the proper size' do
|
58
|
-
expect(active.parse('tseT')).to eq(4)
|
59
|
-
expect(active.value).to eq('tseT')
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'should not read in a string that is too small' do
|
63
|
-
expect(active.parse('B')).to eq(0)
|
64
|
-
expect(active.value).to eq('Test')
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'should be able to read from an offset and only for the given size' do
|
68
|
-
expect(active.parse('FooBarBaz',3)).to eq(4)
|
69
|
-
expect(active.value).to eq('BarB')
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Net::NTLM::String do
|
4
|
+
|
5
|
+
it_behaves_like 'a field', 'Foo', false
|
6
|
+
|
7
|
+
let(:active) {
|
8
|
+
Net::NTLM::String.new({
|
9
|
+
:value => 'Test',
|
10
|
+
:active => true,
|
11
|
+
:size => 4
|
12
|
+
})
|
13
|
+
}
|
14
|
+
|
15
|
+
let(:inactive) {
|
16
|
+
Net::NTLM::String.new({
|
17
|
+
:value => 'Test',
|
18
|
+
:active => false,
|
19
|
+
:size => 4
|
20
|
+
})
|
21
|
+
}
|
22
|
+
|
23
|
+
context '#serialize' do
|
24
|
+
it 'should return the value when active' do
|
25
|
+
expect(active.serialize).to eq('Test')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should return an empty string when inactive' do
|
29
|
+
expect(inactive.serialize).to eq('')
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should coerce non-string values into strings' do
|
33
|
+
active.value = 15
|
34
|
+
expect(active.serialize).to eq('15')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should return empty string on a nil' do
|
38
|
+
active.value = nil
|
39
|
+
expect(active.serialize).to eq('')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context '#value=' do
|
44
|
+
it 'should set active to false if it empty' do
|
45
|
+
active.value = ''
|
46
|
+
expect(active.active).to eq(false)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should adjust the size based on the value set' do
|
50
|
+
expect(active.size).to eq(4)
|
51
|
+
active.value = 'Foobar'
|
52
|
+
expect(active.size).to eq(6)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context '#parse' do
|
57
|
+
it 'should read in a string of the proper size' do
|
58
|
+
expect(active.parse('tseT')).to eq(4)
|
59
|
+
expect(active.value).to eq('tseT')
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should not read in a string that is too small' do
|
63
|
+
expect(active.parse('B')).to eq(0)
|
64
|
+
expect(active.value).to eq('Test')
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should be able to read from an offset and only for the given size' do
|
68
|
+
expect(active.parse('FooBarBaz',3)).to eq(4)
|
69
|
+
expect(active.value).to eq('BarB')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Net::NTLM::TargetInfo do
|
4
|
+
let(:key1) { Net::NTLM::TargetInfo::MSV_AV_NB_COMPUTER_NAME }
|
5
|
+
let(:value1) { 'some data' }
|
6
|
+
let(:key2) { Net::NTLM::TargetInfo::MSV_AV_NB_DOMAIN_NAME }
|
7
|
+
let(:value2) { 'some other data' }
|
8
|
+
let(:data) do
|
9
|
+
dt = key1.dup
|
10
|
+
dt << [value1.length].pack('S')
|
11
|
+
dt << value1
|
12
|
+
dt << key2.dup
|
13
|
+
dt << [value2.length].pack('S')
|
14
|
+
dt << value2
|
15
|
+
dt << Net::NTLM::TargetInfo::MSV_AV_EOL
|
16
|
+
dt << [0].pack('S')
|
17
|
+
dt.force_encoding(Encoding::ASCII_8BIT)
|
18
|
+
end
|
19
|
+
|
20
|
+
subject { Net::NTLM::TargetInfo.new(data) }
|
21
|
+
|
22
|
+
describe 'invalid data' do
|
23
|
+
|
24
|
+
context 'invalid pair id' do
|
25
|
+
let(:data) { "\xFF\x00" }
|
26
|
+
|
27
|
+
it 'returns an error' do
|
28
|
+
expect{subject}.to raise_error Net::NTLM::InvalidTargetDataError
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '#av_pairs' do
|
34
|
+
|
35
|
+
it 'returns the pair values with the given keys' do
|
36
|
+
expect(subject.av_pairs[key1]).to eq value1
|
37
|
+
expect(subject.av_pairs[key2]).to eq value2
|
38
|
+
end
|
39
|
+
|
40
|
+
context "target data is nil" do
|
41
|
+
subject { Net::NTLM::TargetInfo.new(nil) }
|
42
|
+
|
43
|
+
it 'returns the pair values with the given keys' do
|
44
|
+
expect(subject.av_pairs).to be_empty
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#to_s' do
|
50
|
+
let(:data) do
|
51
|
+
dt = key1.dup
|
52
|
+
dt << [value1.length].pack('S')
|
53
|
+
dt << value1
|
54
|
+
dt << key2.dup
|
55
|
+
dt << [value2.length].pack('S')
|
56
|
+
dt << value2
|
57
|
+
dt.force_encoding(Encoding::ASCII_8BIT)
|
58
|
+
end
|
59
|
+
let(:new_key) { Net::NTLM::TargetInfo::MSV_AV_CHANNEL_BINDINGS }
|
60
|
+
let(:new_value) { 'bindings' }
|
61
|
+
let(:new_data) do
|
62
|
+
dt = data
|
63
|
+
dt << new_key
|
64
|
+
dt << [new_value.length].pack('S')
|
65
|
+
dt << new_value
|
66
|
+
dt << Net::NTLM::TargetInfo::MSV_AV_EOL
|
67
|
+
dt << [0].pack('S')
|
68
|
+
dt.force_encoding(Encoding::ASCII_8BIT)
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'returns bytes with any new data added' do
|
72
|
+
subject.av_pairs[new_key] = new_value
|
73
|
+
expect(subject.to_s).to eq new_data
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -1,27 +1,27 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require File.expand_path("#{File.dirname(__FILE__)}/../../../../lib/net/ntlm/version")
|
3
|
-
|
4
|
-
describe Net::NTLM::VERSION do
|
5
|
-
|
6
|
-
it 'should contain an integer value for Major Version' do
|
7
|
-
expect(Net::NTLM::VERSION::MAJOR).to be_an Integer
|
8
|
-
end
|
9
|
-
|
10
|
-
it 'should contain an integer value for Minor Version' do
|
11
|
-
expect(Net::NTLM::VERSION::MINOR).to be_an Integer
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'should contain an integer value for Patch Version' do
|
15
|
-
expect(Net::NTLM::VERSION::TINY).to be_an Integer
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'should contain an aggregate version string' do
|
19
|
-
string = [
|
20
|
-
Net::NTLM::VERSION::MAJOR,
|
21
|
-
Net::NTLM::VERSION::MINOR,
|
22
|
-
Net::NTLM::VERSION::TINY
|
23
|
-
].join('.')
|
24
|
-
expect(Net::NTLM::VERSION::STRING).to be_a String
|
25
|
-
expect(Net::NTLM::VERSION::STRING).to eq(string)
|
26
|
-
end
|
27
|
-
end
|
1
|
+
require 'spec_helper'
|
2
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../../../../lib/net/ntlm/version")
|
3
|
+
|
4
|
+
describe Net::NTLM::VERSION do
|
5
|
+
|
6
|
+
it 'should contain an integer value for Major Version' do
|
7
|
+
expect(Net::NTLM::VERSION::MAJOR).to be_an Integer
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should contain an integer value for Minor Version' do
|
11
|
+
expect(Net::NTLM::VERSION::MINOR).to be_an Integer
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should contain an integer value for Patch Version' do
|
15
|
+
expect(Net::NTLM::VERSION::TINY).to be_an Integer
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should contain an aggregate version string' do
|
19
|
+
string = [
|
20
|
+
Net::NTLM::VERSION::MAJOR,
|
21
|
+
Net::NTLM::VERSION::MINOR,
|
22
|
+
Net::NTLM::VERSION::TINY
|
23
|
+
].join('.')
|
24
|
+
expect(Net::NTLM::VERSION::STRING).to be_a String
|
25
|
+
expect(Net::NTLM::VERSION::STRING).to eq(string)
|
26
|
+
end
|
27
|
+
end
|
data/spec/lib/net/ntlm_spec.rb
CHANGED
@@ -1,127 +1,127 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Net::NTLM do
|
4
|
-
let(:passwd) {"SecREt01"}
|
5
|
-
let(:user) {"user"}
|
6
|
-
let(:domain) {"DOMAIN"}
|
7
|
-
let(:challenge) {["0123456789abcdef"].pack("H*")}
|
8
|
-
let(:client_ch) {["ffffff0011223344"].pack("H*")}
|
9
|
-
let(:timestamp) {1055844000}
|
10
|
-
let(:trgt_info) {[
|
11
|
-
"02000c0044004f004d00410049004e00" +
|
12
|
-
"01000c00530045005200560045005200" +
|
13
|
-
"0400140064006f006d00610069006e00" +
|
14
|
-
"2e0063006f006d000300220073006500" +
|
15
|
-
"72007600650072002e0064006f006d00" +
|
16
|
-
"610069006e002e0063006f006d000000" +
|
17
|
-
"0000"
|
18
|
-
].pack("H*")}
|
19
|
-
let(:padded_pwd) { passwd.upcase.ljust(14, "\0")}
|
20
|
-
let(:keys) { Net::NTLM.gen_keys(padded_pwd)}
|
21
|
-
|
22
|
-
it 'should convert a value to 64-bit LE Integer' do
|
23
|
-
expect(Net::NTLM.pack_int64le(42)).to eq("\x2A\x00\x00\x00\x00\x00\x00\x00")
|
24
|
-
end
|
25
|
-
|
26
|
-
it 'should split a string into an array of slices, 7 chars or less' do
|
27
|
-
expect(Net::NTLM.split7("HelloWorld!")).to eq([ 'HelloWo', 'rld!'])
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'should generate DES keys from the supplied string' do
|
31
|
-
first_key = ["52a2516b252a5161"].pack('H*')
|
32
|
-
second_key = ["3180010101010101"].pack('H*')
|
33
|
-
expect(Net::NTLM.gen_keys(padded_pwd)).to eq([first_key, second_key])
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'should encrypt the string with DES for each key supplied' do
|
37
|
-
first_crypt = ["ff3750bcc2b22412"].pack('H*')
|
38
|
-
second_crypt = ["c2265b23734e0dac"].pack('H*')
|
39
|
-
expect(Net::NTLM::apply_des(Net::NTLM::LM_MAGIC, keys)).to eq([first_crypt, second_crypt])
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'should generate an lm_hash' do
|
43
|
-
expect(Net::NTLM::lm_hash(passwd)).to eq(["ff3750bcc2b22412c2265b23734e0dac"].pack("H*"))
|
44
|
-
end
|
45
|
-
|
46
|
-
it 'should generate an ntlm_hash' do
|
47
|
-
expect(Net::NTLM::ntlm_hash(passwd)).to eq(["cd06ca7c7e10c99b1d33b7485a2ed808"].pack("H*"))
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'should generate an ntlmv2_hash' do
|
51
|
-
expect(Net::NTLM::ntlmv2_hash(user, passwd, domain)).to eq(["04b8e0ba74289cc540826bab1dee63ae"].pack("H*"))
|
52
|
-
end
|
53
|
-
|
54
|
-
context 'when a user passes an NTLM hash for pass-the-hash' do
|
55
|
-
let(:passwd) { Net::NTLM::EncodeUtil.encode_utf16le('ff3750bcc2b22412c2265b23734e0dac:cd06ca7c7e10c99b1d33b7485a2ed808') }
|
56
|
-
|
57
|
-
it 'should return the correct ntlmv2 hash' do
|
58
|
-
expect(Net::NTLM::ntlmv2_hash(user, passwd, domain)).to eq(["04b8e0ba74289cc540826bab1dee63ae"].pack("H*"))
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'should generate an lm_response' do
|
63
|
-
expect(Net::NTLM::lm_response(
|
64
|
-
{
|
65
|
-
:lm_hash => Net::NTLM::lm_hash(passwd),
|
66
|
-
:challenge => challenge
|
67
|
-
}
|
68
|
-
)).to eq(["c337cd5cbd44fc9782a667af6d427c6de67c20c2d3e77c56"].pack("H*"))
|
69
|
-
end
|
70
|
-
|
71
|
-
it 'should generate an ntlm_response' do
|
72
|
-
ntlm_hash = Net::NTLM::ntlm_hash(passwd)
|
73
|
-
expect(Net::NTLM::ntlm_response(
|
74
|
-
{
|
75
|
-
:ntlm_hash => ntlm_hash,
|
76
|
-
:challenge => challenge
|
77
|
-
}
|
78
|
-
)).to eq(["25a98c1c31e81847466b29b2df4680f39958fb8c213a9cc6"].pack("H*"))
|
79
|
-
end
|
80
|
-
|
81
|
-
it 'should generate a lvm2_response' do
|
82
|
-
expect(Net::NTLM::lmv2_response(
|
83
|
-
{
|
84
|
-
:ntlmv2_hash => Net::NTLM::ntlmv2_hash(user, passwd, domain),
|
85
|
-
:challenge => challenge
|
86
|
-
},
|
87
|
-
{ :client_challenge => client_ch }
|
88
|
-
)).to eq(["d6e6152ea25d03b7c6ba6629c2d6aaf0ffffff0011223344"].pack("H*"))
|
89
|
-
end
|
90
|
-
|
91
|
-
it 'should generate a ntlmv2_response' do
|
92
|
-
expect(Net::NTLM::ntlmv2_response(
|
93
|
-
{
|
94
|
-
:ntlmv2_hash => Net::NTLM::ntlmv2_hash(user, passwd, domain),
|
95
|
-
:challenge => challenge,
|
96
|
-
:target_info => trgt_info
|
97
|
-
},
|
98
|
-
{
|
99
|
-
:timestamp => timestamp,
|
100
|
-
:client_challenge => client_ch
|
101
|
-
}
|
102
|
-
)).to eq([
|
103
|
-
"cbabbca713eb795d04c97abc01ee4983" +
|
104
|
-
"01010000000000000090d336b734c301" +
|
105
|
-
"ffffff00112233440000000002000c00" +
|
106
|
-
"44004f004d00410049004e0001000c00" +
|
107
|
-
"53004500520056004500520004001400" +
|
108
|
-
"64006f006d00610069006e002e006300" +
|
109
|
-
"6f006d00030022007300650072007600" +
|
110
|
-
"650072002e0064006f006d0061006900" +
|
111
|
-
"6e002e0063006f006d00000000000000" +
|
112
|
-
"0000"
|
113
|
-
].pack("H*"))
|
114
|
-
end
|
115
|
-
|
116
|
-
it 'should generate a ntlm2_session' do
|
117
|
-
session = Net::NTLM::ntlm2_session(
|
118
|
-
{
|
119
|
-
:ntlm_hash => Net::NTLM::ntlm_hash(passwd),
|
120
|
-
:challenge => challenge
|
121
|
-
},
|
122
|
-
{ :client_challenge => client_ch }
|
123
|
-
)
|
124
|
-
expect(session[0]).to eq(["ffffff001122334400000000000000000000000000000000"].pack("H*"))
|
125
|
-
expect(session[1]).to eq(["10d550832d12b2ccb79d5ad1f4eed3df82aca4c3681dd455"].pack("H*"))
|
126
|
-
end
|
127
|
-
end
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Net::NTLM do
|
4
|
+
let(:passwd) {"SecREt01"}
|
5
|
+
let(:user) {"user"}
|
6
|
+
let(:domain) {"DOMAIN"}
|
7
|
+
let(:challenge) {["0123456789abcdef"].pack("H*")}
|
8
|
+
let(:client_ch) {["ffffff0011223344"].pack("H*")}
|
9
|
+
let(:timestamp) {1055844000}
|
10
|
+
let(:trgt_info) {[
|
11
|
+
"02000c0044004f004d00410049004e00" +
|
12
|
+
"01000c00530045005200560045005200" +
|
13
|
+
"0400140064006f006d00610069006e00" +
|
14
|
+
"2e0063006f006d000300220073006500" +
|
15
|
+
"72007600650072002e0064006f006d00" +
|
16
|
+
"610069006e002e0063006f006d000000" +
|
17
|
+
"0000"
|
18
|
+
].pack("H*")}
|
19
|
+
let(:padded_pwd) { passwd.upcase.ljust(14, "\0")}
|
20
|
+
let(:keys) { Net::NTLM.gen_keys(padded_pwd)}
|
21
|
+
|
22
|
+
it 'should convert a value to 64-bit LE Integer' do
|
23
|
+
expect(Net::NTLM.pack_int64le(42)).to eq("\x2A\x00\x00\x00\x00\x00\x00\x00")
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should split a string into an array of slices, 7 chars or less' do
|
27
|
+
expect(Net::NTLM.split7("HelloWorld!")).to eq([ 'HelloWo', 'rld!'])
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should generate DES keys from the supplied string' do
|
31
|
+
first_key = ["52a2516b252a5161"].pack('H*')
|
32
|
+
second_key = ["3180010101010101"].pack('H*')
|
33
|
+
expect(Net::NTLM.gen_keys(padded_pwd)).to eq([first_key, second_key])
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should encrypt the string with DES for each key supplied' do
|
37
|
+
first_crypt = ["ff3750bcc2b22412"].pack('H*')
|
38
|
+
second_crypt = ["c2265b23734e0dac"].pack('H*')
|
39
|
+
expect(Net::NTLM::apply_des(Net::NTLM::LM_MAGIC, keys)).to eq([first_crypt, second_crypt])
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should generate an lm_hash' do
|
43
|
+
expect(Net::NTLM::lm_hash(passwd)).to eq(["ff3750bcc2b22412c2265b23734e0dac"].pack("H*"))
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should generate an ntlm_hash' do
|
47
|
+
expect(Net::NTLM::ntlm_hash(passwd)).to eq(["cd06ca7c7e10c99b1d33b7485a2ed808"].pack("H*"))
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should generate an ntlmv2_hash' do
|
51
|
+
expect(Net::NTLM::ntlmv2_hash(user, passwd, domain)).to eq(["04b8e0ba74289cc540826bab1dee63ae"].pack("H*"))
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when a user passes an NTLM hash for pass-the-hash' do
|
55
|
+
let(:passwd) { Net::NTLM::EncodeUtil.encode_utf16le('ff3750bcc2b22412c2265b23734e0dac:cd06ca7c7e10c99b1d33b7485a2ed808') }
|
56
|
+
|
57
|
+
it 'should return the correct ntlmv2 hash' do
|
58
|
+
expect(Net::NTLM::ntlmv2_hash(user, passwd, domain)).to eq(["04b8e0ba74289cc540826bab1dee63ae"].pack("H*"))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should generate an lm_response' do
|
63
|
+
expect(Net::NTLM::lm_response(
|
64
|
+
{
|
65
|
+
:lm_hash => Net::NTLM::lm_hash(passwd),
|
66
|
+
:challenge => challenge
|
67
|
+
}
|
68
|
+
)).to eq(["c337cd5cbd44fc9782a667af6d427c6de67c20c2d3e77c56"].pack("H*"))
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should generate an ntlm_response' do
|
72
|
+
ntlm_hash = Net::NTLM::ntlm_hash(passwd)
|
73
|
+
expect(Net::NTLM::ntlm_response(
|
74
|
+
{
|
75
|
+
:ntlm_hash => ntlm_hash,
|
76
|
+
:challenge => challenge
|
77
|
+
}
|
78
|
+
)).to eq(["25a98c1c31e81847466b29b2df4680f39958fb8c213a9cc6"].pack("H*"))
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should generate a lvm2_response' do
|
82
|
+
expect(Net::NTLM::lmv2_response(
|
83
|
+
{
|
84
|
+
:ntlmv2_hash => Net::NTLM::ntlmv2_hash(user, passwd, domain),
|
85
|
+
:challenge => challenge
|
86
|
+
},
|
87
|
+
{ :client_challenge => client_ch }
|
88
|
+
)).to eq(["d6e6152ea25d03b7c6ba6629c2d6aaf0ffffff0011223344"].pack("H*"))
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should generate a ntlmv2_response' do
|
92
|
+
expect(Net::NTLM::ntlmv2_response(
|
93
|
+
{
|
94
|
+
:ntlmv2_hash => Net::NTLM::ntlmv2_hash(user, passwd, domain),
|
95
|
+
:challenge => challenge,
|
96
|
+
:target_info => trgt_info
|
97
|
+
},
|
98
|
+
{
|
99
|
+
:timestamp => timestamp,
|
100
|
+
:client_challenge => client_ch
|
101
|
+
}
|
102
|
+
)).to eq([
|
103
|
+
"cbabbca713eb795d04c97abc01ee4983" +
|
104
|
+
"01010000000000000090d336b734c301" +
|
105
|
+
"ffffff00112233440000000002000c00" +
|
106
|
+
"44004f004d00410049004e0001000c00" +
|
107
|
+
"53004500520056004500520004001400" +
|
108
|
+
"64006f006d00610069006e002e006300" +
|
109
|
+
"6f006d00030022007300650072007600" +
|
110
|
+
"650072002e0064006f006d0061006900" +
|
111
|
+
"6e002e0063006f006d00000000000000" +
|
112
|
+
"0000"
|
113
|
+
].pack("H*"))
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should generate a ntlm2_session' do
|
117
|
+
session = Net::NTLM::ntlm2_session(
|
118
|
+
{
|
119
|
+
:ntlm_hash => Net::NTLM::ntlm_hash(passwd),
|
120
|
+
:challenge => challenge
|
121
|
+
},
|
122
|
+
{ :client_challenge => client_ch }
|
123
|
+
)
|
124
|
+
expect(session[0]).to eq(["ffffff001122334400000000000000000000000000000000"].pack("H*"))
|
125
|
+
expect(session[1]).to eq(["10d550832d12b2ccb79d5ad1f4eed3df82aca4c3681dd455"].pack("H*"))
|
126
|
+
end
|
127
|
+
end
|