rubyntlm 0.5.3 → 0.6.0
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/.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
data/lib/net/ntlm/int32_le.rb
CHANGED
@@ -1,25 +1,25 @@
|
|
1
|
-
module Net
|
2
|
-
module NTLM
|
3
|
-
|
4
|
-
class Int32LE < Field
|
5
|
-
def initialize(opt)
|
6
|
-
super(opt)
|
7
|
-
@size = 4
|
8
|
-
end
|
9
|
-
|
10
|
-
def parse(str, offset=0)
|
11
|
-
if @active and str.size >= offset + @size
|
12
|
-
@value = str.slice(offset, @size).unpack("V")[0]
|
13
|
-
@size
|
14
|
-
else
|
15
|
-
0
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def serialize
|
20
|
-
[@value].pack("V") if @active
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
1
|
+
module Net
|
2
|
+
module NTLM
|
3
|
+
|
4
|
+
class Int32LE < Field
|
5
|
+
def initialize(opt)
|
6
|
+
super(opt)
|
7
|
+
@size = 4
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse(str, offset=0)
|
11
|
+
if @active and str.size >= offset + @size
|
12
|
+
@value = str.slice(offset, @size).unpack("V")[0]
|
13
|
+
@size
|
14
|
+
else
|
15
|
+
0
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def serialize
|
20
|
+
[@value].pack("V") if @active
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
25
|
end
|
data/lib/net/ntlm/int64_le.rb
CHANGED
@@ -1,26 +1,26 @@
|
|
1
|
-
module Net
|
2
|
-
module NTLM
|
3
|
-
|
4
|
-
class Int64LE < Field
|
5
|
-
def initialize(opt)
|
6
|
-
super(opt)
|
7
|
-
@size = 8
|
8
|
-
end
|
9
|
-
|
10
|
-
def parse(str, offset=0)
|
11
|
-
if @active and str.size >= offset + @size
|
12
|
-
d, u = str.slice(offset, @size).unpack("V2")
|
13
|
-
@value = (u * 0x100000000 + d)
|
14
|
-
@size
|
15
|
-
else
|
16
|
-
0
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def serialize
|
21
|
-
[@value & 0x00000000ffffffff, @value >> 32].pack("V2") if @active
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
1
|
+
module Net
|
2
|
+
module NTLM
|
3
|
+
|
4
|
+
class Int64LE < Field
|
5
|
+
def initialize(opt)
|
6
|
+
super(opt)
|
7
|
+
@size = 8
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse(str, offset=0)
|
11
|
+
if @active and str.size >= offset + @size
|
12
|
+
d, u = str.slice(offset, @size).unpack("V2")
|
13
|
+
@value = (u * 0x100000000 + d)
|
14
|
+
@size
|
15
|
+
else
|
16
|
+
0
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def serialize
|
21
|
+
[@value & 0x00000000ffffffff, @value >> 32].pack("V2") if @active
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
26
|
end
|
data/lib/net/ntlm/message.rb
CHANGED
@@ -1,129 +1,129 @@
|
|
1
|
-
module Net
|
2
|
-
module NTLM
|
3
|
-
|
4
|
-
SSP_SIGN = "NTLMSSP\0"
|
5
|
-
|
6
|
-
FLAGS = {
|
7
|
-
:UNICODE => 0x00000001,
|
8
|
-
:OEM => 0x00000002,
|
9
|
-
:REQUEST_TARGET => 0x00000004,
|
10
|
-
:MBZ9 => 0x00000008,
|
11
|
-
:SIGN => 0x00000010,
|
12
|
-
:SEAL => 0x00000020,
|
13
|
-
:NEG_DATAGRAM => 0x00000040,
|
14
|
-
:NETWARE => 0x00000100,
|
15
|
-
:NTLM => 0x00000200,
|
16
|
-
:NEG_NT_ONLY => 0x00000400,
|
17
|
-
:MBZ7 => 0x00000800,
|
18
|
-
:DOMAIN_SUPPLIED => 0x00001000,
|
19
|
-
:WORKSTATION_SUPPLIED => 0x00002000,
|
20
|
-
:LOCAL_CALL => 0x00004000,
|
21
|
-
:ALWAYS_SIGN => 0x00008000,
|
22
|
-
:TARGET_TYPE_DOMAIN => 0x00010000,
|
23
|
-
:NTLM2_KEY => 0x00080000,
|
24
|
-
:TARGET_INFO => 0x00800000,
|
25
|
-
:KEY128 => 0x20000000,
|
26
|
-
:KEY_EXCHANGE => 0x40000000,
|
27
|
-
:KEY56 => 0x80000000
|
28
|
-
}.freeze
|
29
|
-
|
30
|
-
FLAG_KEYS = FLAGS.keys.sort{|a, b| FLAGS[a] <=> FLAGS[b] }
|
31
|
-
|
32
|
-
DEFAULT_FLAGS = {
|
33
|
-
:TYPE1 => FLAGS[:UNICODE] | FLAGS[:OEM] | FLAGS[:REQUEST_TARGET] | FLAGS[:NTLM] | FLAGS[:ALWAYS_SIGN] | FLAGS[:NTLM2_KEY],
|
34
|
-
:TYPE2 => FLAGS[:UNICODE],
|
35
|
-
:TYPE3 => FLAGS[:UNICODE] | FLAGS[:REQUEST_TARGET] | FLAGS[:NTLM] | FLAGS[:ALWAYS_SIGN] | FLAGS[:NTLM2_KEY]
|
36
|
-
}
|
37
|
-
|
38
|
-
|
39
|
-
# @private false
|
40
|
-
class Message < FieldSet
|
41
|
-
class << Message
|
42
|
-
def parse(str)
|
43
|
-
m = Type0.new
|
44
|
-
m.parse(str)
|
45
|
-
case m.type
|
46
|
-
when 1
|
47
|
-
t = Type1.new.parse(str)
|
48
|
-
when 2
|
49
|
-
t = Type2.new.parse(str)
|
50
|
-
when 3
|
51
|
-
t = Type3.new.parse(str)
|
52
|
-
else
|
53
|
-
raise ArgumentError, "unknown type: #{m.type}"
|
54
|
-
end
|
55
|
-
t
|
56
|
-
end
|
57
|
-
|
58
|
-
def decode64(str)
|
59
|
-
parse(Base64.decode64(str))
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# @return [self]
|
64
|
-
def parse(str)
|
65
|
-
super
|
66
|
-
|
67
|
-
while has_disabled_fields? && serialize.size < str.size
|
68
|
-
# enable the next disabled field
|
69
|
-
self.class.names.find { |name| !self[name].active && enable(name) }
|
70
|
-
super
|
71
|
-
end
|
72
|
-
|
73
|
-
self
|
74
|
-
end
|
75
|
-
|
76
|
-
def has_flag?(flag)
|
77
|
-
(self[:flag].value & FLAGS[flag]) == FLAGS[flag]
|
78
|
-
end
|
79
|
-
|
80
|
-
def set_flag(flag)
|
81
|
-
self[:flag].value |= FLAGS[flag]
|
82
|
-
end
|
83
|
-
|
84
|
-
def dump_flags
|
85
|
-
FLAG_KEYS.each{ |k| print(k, "=", has_flag?(k), "\n") }
|
86
|
-
end
|
87
|
-
|
88
|
-
def serialize
|
89
|
-
deflag
|
90
|
-
super + security_buffers.map{|n, f| f.value}.join
|
91
|
-
end
|
92
|
-
|
93
|
-
def encode64
|
94
|
-
Base64.encode64(serialize).gsub(/\n/, '')
|
95
|
-
end
|
96
|
-
|
97
|
-
def decode64(str)
|
98
|
-
parse(Base64.decode64(str))
|
99
|
-
end
|
100
|
-
|
101
|
-
alias head_size size
|
102
|
-
|
103
|
-
def data_size
|
104
|
-
security_buffers.inject(0){|sum, a| sum += a[1].data_size}
|
105
|
-
end
|
106
|
-
|
107
|
-
def size
|
108
|
-
head_size + data_size
|
109
|
-
end
|
110
|
-
|
111
|
-
|
112
|
-
def security_buffers
|
113
|
-
@alist.find_all{|n, f| f.instance_of?(SecurityBuffer)}
|
114
|
-
end
|
115
|
-
|
116
|
-
def deflag
|
117
|
-
security_buffers.inject(head_size){|cur, a|
|
118
|
-
a[1].offset = cur
|
119
|
-
cur += a[1].data_size
|
120
|
-
}
|
121
|
-
end
|
122
|
-
|
123
|
-
def data_edge
|
124
|
-
security_buffers.map{ |n, f| f.active ? f.offset : size}.min
|
125
|
-
end
|
126
|
-
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
1
|
+
module Net
|
2
|
+
module NTLM
|
3
|
+
|
4
|
+
SSP_SIGN = "NTLMSSP\0"
|
5
|
+
|
6
|
+
FLAGS = {
|
7
|
+
:UNICODE => 0x00000001,
|
8
|
+
:OEM => 0x00000002,
|
9
|
+
:REQUEST_TARGET => 0x00000004,
|
10
|
+
:MBZ9 => 0x00000008,
|
11
|
+
:SIGN => 0x00000010,
|
12
|
+
:SEAL => 0x00000020,
|
13
|
+
:NEG_DATAGRAM => 0x00000040,
|
14
|
+
:NETWARE => 0x00000100,
|
15
|
+
:NTLM => 0x00000200,
|
16
|
+
:NEG_NT_ONLY => 0x00000400,
|
17
|
+
:MBZ7 => 0x00000800,
|
18
|
+
:DOMAIN_SUPPLIED => 0x00001000,
|
19
|
+
:WORKSTATION_SUPPLIED => 0x00002000,
|
20
|
+
:LOCAL_CALL => 0x00004000,
|
21
|
+
:ALWAYS_SIGN => 0x00008000,
|
22
|
+
:TARGET_TYPE_DOMAIN => 0x00010000,
|
23
|
+
:NTLM2_KEY => 0x00080000,
|
24
|
+
:TARGET_INFO => 0x00800000,
|
25
|
+
:KEY128 => 0x20000000,
|
26
|
+
:KEY_EXCHANGE => 0x40000000,
|
27
|
+
:KEY56 => 0x80000000
|
28
|
+
}.freeze
|
29
|
+
|
30
|
+
FLAG_KEYS = FLAGS.keys.sort{|a, b| FLAGS[a] <=> FLAGS[b] }
|
31
|
+
|
32
|
+
DEFAULT_FLAGS = {
|
33
|
+
:TYPE1 => FLAGS[:UNICODE] | FLAGS[:OEM] | FLAGS[:REQUEST_TARGET] | FLAGS[:NTLM] | FLAGS[:ALWAYS_SIGN] | FLAGS[:NTLM2_KEY],
|
34
|
+
:TYPE2 => FLAGS[:UNICODE],
|
35
|
+
:TYPE3 => FLAGS[:UNICODE] | FLAGS[:REQUEST_TARGET] | FLAGS[:NTLM] | FLAGS[:ALWAYS_SIGN] | FLAGS[:NTLM2_KEY]
|
36
|
+
}
|
37
|
+
|
38
|
+
|
39
|
+
# @private false
|
40
|
+
class Message < FieldSet
|
41
|
+
class << Message
|
42
|
+
def parse(str)
|
43
|
+
m = Type0.new
|
44
|
+
m.parse(str)
|
45
|
+
case m.type
|
46
|
+
when 1
|
47
|
+
t = Type1.new.parse(str)
|
48
|
+
when 2
|
49
|
+
t = Type2.new.parse(str)
|
50
|
+
when 3
|
51
|
+
t = Type3.new.parse(str)
|
52
|
+
else
|
53
|
+
raise ArgumentError, "unknown type: #{m.type}"
|
54
|
+
end
|
55
|
+
t
|
56
|
+
end
|
57
|
+
|
58
|
+
def decode64(str)
|
59
|
+
parse(Base64.decode64(str))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# @return [self]
|
64
|
+
def parse(str)
|
65
|
+
super
|
66
|
+
|
67
|
+
while has_disabled_fields? && serialize.size < str.size
|
68
|
+
# enable the next disabled field
|
69
|
+
self.class.names.find { |name| !self[name].active && enable(name) }
|
70
|
+
super
|
71
|
+
end
|
72
|
+
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
76
|
+
def has_flag?(flag)
|
77
|
+
(self[:flag].value & FLAGS[flag]) == FLAGS[flag]
|
78
|
+
end
|
79
|
+
|
80
|
+
def set_flag(flag)
|
81
|
+
self[:flag].value |= FLAGS[flag]
|
82
|
+
end
|
83
|
+
|
84
|
+
def dump_flags
|
85
|
+
FLAG_KEYS.each{ |k| print(k, "=", has_flag?(k), "\n") }
|
86
|
+
end
|
87
|
+
|
88
|
+
def serialize
|
89
|
+
deflag
|
90
|
+
super + security_buffers.map{|n, f| f.value}.join
|
91
|
+
end
|
92
|
+
|
93
|
+
def encode64
|
94
|
+
Base64.encode64(serialize).gsub(/\n/, '')
|
95
|
+
end
|
96
|
+
|
97
|
+
def decode64(str)
|
98
|
+
parse(Base64.decode64(str))
|
99
|
+
end
|
100
|
+
|
101
|
+
alias head_size size
|
102
|
+
|
103
|
+
def data_size
|
104
|
+
security_buffers.inject(0){|sum, a| sum += a[1].data_size}
|
105
|
+
end
|
106
|
+
|
107
|
+
def size
|
108
|
+
head_size + data_size
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
def security_buffers
|
113
|
+
@alist.find_all{|n, f| f.instance_of?(SecurityBuffer)}
|
114
|
+
end
|
115
|
+
|
116
|
+
def deflag
|
117
|
+
security_buffers.inject(head_size){|cur, a|
|
118
|
+
a[1].offset = cur
|
119
|
+
cur += a[1].data_size
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
def data_edge
|
124
|
+
security_buffers.map{ |n, f| f.active ? f.offset : size}.min
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -1,16 +1,16 @@
|
|
1
|
-
module Net
|
2
|
-
module NTLM
|
3
|
-
class Message
|
4
|
-
|
5
|
-
# sub class definitions
|
6
|
-
class Type0 < Message
|
7
|
-
string :sign, {:size => 8, :value => SSP_SIGN}
|
8
|
-
int32LE :type, {:value => 0}
|
9
|
-
end
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
|
1
|
+
module Net
|
2
|
+
module NTLM
|
3
|
+
class Message
|
4
|
+
|
5
|
+
# sub class definitions
|
6
|
+
class Type0 < Message
|
7
|
+
string :sign, {:size => 8, :value => SSP_SIGN}
|
8
|
+
int32LE :type, {:value => 0}
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
@@ -1,18 +1,18 @@
|
|
1
|
-
module Net
|
2
|
-
module NTLM
|
3
|
-
class Message
|
4
|
-
|
5
|
-
# @private false
|
6
|
-
class Type1 < Message
|
7
|
-
|
8
|
-
string :sign, {:size => 8, :value => SSP_SIGN}
|
9
|
-
int32LE :type, {:value => 1}
|
10
|
-
int32LE :flag, {:value => DEFAULT_FLAGS[:TYPE1] }
|
11
|
-
security_buffer :domain, {:value => ""}
|
12
|
-
security_buffer :workstation, {:value => Socket.gethostname }
|
13
|
-
string :os_version, {:size => 8, :value => "", :active => false }
|
14
|
-
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
1
|
+
module Net
|
2
|
+
module NTLM
|
3
|
+
class Message
|
4
|
+
|
5
|
+
# @private false
|
6
|
+
class Type1 < Message
|
7
|
+
|
8
|
+
string :sign, {:size => 8, :value => SSP_SIGN}
|
9
|
+
int32LE :type, {:value => 1}
|
10
|
+
int32LE :flag, {:value => DEFAULT_FLAGS[:TYPE1] }
|
11
|
+
security_buffer :domain, {:value => ""}
|
12
|
+
security_buffer :workstation, {:value => Socket.gethostname }
|
13
|
+
string :os_version, {:size => 8, :value => "", :active => false }
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,102 +1,102 @@
|
|
1
|
-
module Net
|
2
|
-
module NTLM
|
3
|
-
class Message
|
4
|
-
|
5
|
-
# @private false
|
6
|
-
class Type2 < Message
|
7
|
-
|
8
|
-
string :sign, { :size => 8, :value => SSP_SIGN }
|
9
|
-
int32LE :type, { :value => 2 }
|
10
|
-
security_buffer :target_name, { :size => 0, :value => "" }
|
11
|
-
int32LE :flag, { :value => DEFAULT_FLAGS[:TYPE2] }
|
12
|
-
int64LE :challenge, { :value => 0}
|
13
|
-
int64LE :context, { :value => 0, :active => false }
|
14
|
-
security_buffer :target_info, { :value => "", :active => false }
|
15
|
-
string :os_version, { :size => 8, :value => "", :active => false }
|
16
|
-
|
17
|
-
# Generates a Type 3 response based on the Type 2 Information
|
18
|
-
# @return [Type3]
|
19
|
-
# @option arg [String] :username The username to authenticate with
|
20
|
-
# @option arg [String] :password The user's password
|
21
|
-
# @option arg [String] :domain ('') The domain to authenticate to
|
22
|
-
# @option opt [String] :workstation (Socket.gethostname) The name of the calling workstation
|
23
|
-
# @option opt [Boolean] :use_default_target (false) Use the domain supplied by the server in the Type 2 packet
|
24
|
-
# @note An empty :domain option authenticates to the local machine.
|
25
|
-
# @note The :use_default_target has precedence over the :domain option
|
26
|
-
def response(arg, opt = {})
|
27
|
-
usr = arg[:user]
|
28
|
-
pwd = arg[:password]
|
29
|
-
domain = arg[:domain] ? arg[:domain].upcase : ""
|
30
|
-
if usr.nil? or pwd.nil?
|
31
|
-
raise ArgumentError, "user and password have to be supplied"
|
32
|
-
end
|
33
|
-
|
34
|
-
if opt[:workstation]
|
35
|
-
ws = opt[:workstation]
|
36
|
-
else
|
37
|
-
ws = Socket.gethostname
|
38
|
-
end
|
39
|
-
|
40
|
-
if opt[:client_challenge]
|
41
|
-
cc = opt[:client_challenge]
|
42
|
-
else
|
43
|
-
cc = rand(MAX64)
|
44
|
-
end
|
45
|
-
cc = NTLM::pack_int64le(cc) if cc.is_a?(Integer)
|
46
|
-
opt[:client_challenge] = cc
|
47
|
-
|
48
|
-
if has_flag?(:OEM) and opt[:unicode]
|
49
|
-
usr = NTLM::EncodeUtil.decode_utf16le(usr)
|
50
|
-
pwd = NTLM::EncodeUtil.decode_utf16le(pwd)
|
51
|
-
ws = NTLM::EncodeUtil.decode_utf16le(ws)
|
52
|
-
domain = NTLM::EncodeUtil.decode_utf16le(domain)
|
53
|
-
opt[:unicode] = false
|
54
|
-
end
|
55
|
-
|
56
|
-
if has_flag?(:UNICODE) and !opt[:unicode]
|
57
|
-
usr = NTLM::EncodeUtil.encode_utf16le(usr)
|
58
|
-
pwd = NTLM::EncodeUtil.encode_utf16le(pwd)
|
59
|
-
ws = NTLM::EncodeUtil.encode_utf16le(ws)
|
60
|
-
domain = NTLM::EncodeUtil.encode_utf16le(domain)
|
61
|
-
opt[:unicode] = true
|
62
|
-
end
|
63
|
-
|
64
|
-
if opt[:use_default_target]
|
65
|
-
domain = self.target_name
|
66
|
-
end
|
67
|
-
|
68
|
-
ti = self.target_info
|
69
|
-
|
70
|
-
chal = self[:challenge].serialize
|
71
|
-
|
72
|
-
if opt[:ntlmv2]
|
73
|
-
ar = {:ntlmv2_hash => NTLM::ntlmv2_hash(usr, pwd, domain, opt), :challenge => chal, :target_info => ti}
|
74
|
-
lm_res = NTLM::lmv2_response(ar, opt)
|
75
|
-
ntlm_res = NTLM::ntlmv2_response(ar, opt)
|
76
|
-
elsif has_flag?(:NTLM2_KEY)
|
77
|
-
ar = {:ntlm_hash => NTLM::ntlm_hash(pwd, opt), :challenge => chal}
|
78
|
-
lm_res, ntlm_res = NTLM::ntlm2_session(ar, opt)
|
79
|
-
else
|
80
|
-
ar = {:lm_hash => NTLM::lm_hash(pwd), :challenge => chal}
|
81
|
-
lm_res = NTLM::lm_response(ar)
|
82
|
-
ar = {:ntlm_hash => NTLM::ntlm_hash(pwd, opt), :challenge => chal}
|
83
|
-
ntlm_res = NTLM::ntlm_response(ar)
|
84
|
-
end
|
85
|
-
|
86
|
-
Type3.create({
|
87
|
-
:lm_response => lm_res,
|
88
|
-
:ntlm_response => ntlm_res,
|
89
|
-
:domain => domain,
|
90
|
-
:user => usr,
|
91
|
-
:workstation => ws,
|
92
|
-
:flag => self.flag
|
93
|
-
})
|
94
|
-
end
|
95
|
-
|
96
|
-
end
|
97
|
-
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
|
1
|
+
module Net
|
2
|
+
module NTLM
|
3
|
+
class Message
|
4
|
+
|
5
|
+
# @private false
|
6
|
+
class Type2 < Message
|
7
|
+
|
8
|
+
string :sign, { :size => 8, :value => SSP_SIGN }
|
9
|
+
int32LE :type, { :value => 2 }
|
10
|
+
security_buffer :target_name, { :size => 0, :value => "" }
|
11
|
+
int32LE :flag, { :value => DEFAULT_FLAGS[:TYPE2] }
|
12
|
+
int64LE :challenge, { :value => 0}
|
13
|
+
int64LE :context, { :value => 0, :active => false }
|
14
|
+
security_buffer :target_info, { :value => "", :active => false }
|
15
|
+
string :os_version, { :size => 8, :value => "", :active => false }
|
16
|
+
|
17
|
+
# Generates a Type 3 response based on the Type 2 Information
|
18
|
+
# @return [Type3]
|
19
|
+
# @option arg [String] :username The username to authenticate with
|
20
|
+
# @option arg [String] :password The user's password
|
21
|
+
# @option arg [String] :domain ('') The domain to authenticate to
|
22
|
+
# @option opt [String] :workstation (Socket.gethostname) The name of the calling workstation
|
23
|
+
# @option opt [Boolean] :use_default_target (false) Use the domain supplied by the server in the Type 2 packet
|
24
|
+
# @note An empty :domain option authenticates to the local machine.
|
25
|
+
# @note The :use_default_target has precedence over the :domain option
|
26
|
+
def response(arg, opt = {})
|
27
|
+
usr = arg[:user]
|
28
|
+
pwd = arg[:password]
|
29
|
+
domain = arg[:domain] ? arg[:domain].upcase : ""
|
30
|
+
if usr.nil? or pwd.nil?
|
31
|
+
raise ArgumentError, "user and password have to be supplied"
|
32
|
+
end
|
33
|
+
|
34
|
+
if opt[:workstation]
|
35
|
+
ws = opt[:workstation]
|
36
|
+
else
|
37
|
+
ws = Socket.gethostname
|
38
|
+
end
|
39
|
+
|
40
|
+
if opt[:client_challenge]
|
41
|
+
cc = opt[:client_challenge]
|
42
|
+
else
|
43
|
+
cc = rand(MAX64)
|
44
|
+
end
|
45
|
+
cc = NTLM::pack_int64le(cc) if cc.is_a?(Integer)
|
46
|
+
opt[:client_challenge] = cc
|
47
|
+
|
48
|
+
if has_flag?(:OEM) and opt[:unicode]
|
49
|
+
usr = NTLM::EncodeUtil.decode_utf16le(usr)
|
50
|
+
pwd = NTLM::EncodeUtil.decode_utf16le(pwd)
|
51
|
+
ws = NTLM::EncodeUtil.decode_utf16le(ws)
|
52
|
+
domain = NTLM::EncodeUtil.decode_utf16le(domain)
|
53
|
+
opt[:unicode] = false
|
54
|
+
end
|
55
|
+
|
56
|
+
if has_flag?(:UNICODE) and !opt[:unicode]
|
57
|
+
usr = NTLM::EncodeUtil.encode_utf16le(usr)
|
58
|
+
pwd = NTLM::EncodeUtil.encode_utf16le(pwd)
|
59
|
+
ws = NTLM::EncodeUtil.encode_utf16le(ws)
|
60
|
+
domain = NTLM::EncodeUtil.encode_utf16le(domain)
|
61
|
+
opt[:unicode] = true
|
62
|
+
end
|
63
|
+
|
64
|
+
if opt[:use_default_target]
|
65
|
+
domain = self.target_name
|
66
|
+
end
|
67
|
+
|
68
|
+
ti = self.target_info
|
69
|
+
|
70
|
+
chal = self[:challenge].serialize
|
71
|
+
|
72
|
+
if opt[:ntlmv2]
|
73
|
+
ar = {:ntlmv2_hash => NTLM::ntlmv2_hash(usr, pwd, domain, opt), :challenge => chal, :target_info => ti}
|
74
|
+
lm_res = NTLM::lmv2_response(ar, opt)
|
75
|
+
ntlm_res = NTLM::ntlmv2_response(ar, opt)
|
76
|
+
elsif has_flag?(:NTLM2_KEY)
|
77
|
+
ar = {:ntlm_hash => NTLM::ntlm_hash(pwd, opt), :challenge => chal}
|
78
|
+
lm_res, ntlm_res = NTLM::ntlm2_session(ar, opt)
|
79
|
+
else
|
80
|
+
ar = {:lm_hash => NTLM::lm_hash(pwd), :challenge => chal}
|
81
|
+
lm_res = NTLM::lm_response(ar)
|
82
|
+
ar = {:ntlm_hash => NTLM::ntlm_hash(pwd, opt), :challenge => chal}
|
83
|
+
ntlm_res = NTLM::ntlm_response(ar)
|
84
|
+
end
|
85
|
+
|
86
|
+
Type3.create({
|
87
|
+
:lm_response => lm_res,
|
88
|
+
:ntlm_response => ntlm_res,
|
89
|
+
:domain => domain,
|
90
|
+
:user => usr,
|
91
|
+
:workstation => ws,
|
92
|
+
:flag => self.flag
|
93
|
+
})
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
|