CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/rex/proto/ntlm/base.rb
Views: 11704
1
# -*- coding: binary -*-
2
#
3
# An NTLM Authentication Library for Ruby
4
#
5
# This code is a derivative of "dbf2.rb" written by yrock
6
# and Minero Aoki. You can find original code here:
7
# http://jp.rubyist.net/magazine/?0013-CodeReview
8
# -------------------------------------------------------------
9
# Copyright (c) 2005,2006 yrock
10
#
11
# This program is free software.
12
# You can distribute/modify this program under the terms of the
13
# Ruby License.
14
#
15
# 2011-02-23 refactored by Alexandre Maloteaux for Metasploit Project
16
# -------------------------------------------------------------
17
#
18
# 2006-02-11 refactored by Minero Aoki
19
# -------------------------------------------------------------
20
#
21
# All protocol information used to write this code stems from
22
# "The NTLM Authentication Protocol" by Eric Glass. The author
23
# would thank to him for this tremendous work and making it
24
# available on the net.
25
# http://davenport.sourceforge.net/ntlm.html
26
# -------------------------------------------------------------
27
# Copyright (c) 2003 Eric Glass
28
#
29
# Permission to use, copy, modify, and distribute this document
30
# for any purpose and without any fee is hereby granted,
31
# provided that the above copyright notice and this list of
32
# conditions appear in all copies.
33
# -------------------------------------------------------------
34
#
35
# The author also looked Mozilla-Firefox-1.0.7 source code,
36
# namely, security/manager/ssl/src/nsNTLMAuthModule.cpp and
37
# Jonathan Bastien-Filiatrault's libntlm-ruby.
38
# "http://x2a.org/websvn/filedetails.php?
39
# repname=libntlm-ruby&path=%2Ftrunk%2Fntlm.rb&sc=1"
40
# The latter has a minor bug in its separate_keys function.
41
# The third key has to begin from the 14th character of the
42
# input string instead of 13th:)
43
44
45
module Rex
46
module Proto
47
module NTLM
48
# The base type needed for other modules like message and crypt
49
class Base
50
51
CONST = Rex::Proto::NTLM::Constants
52
53
# base classes for primitives
54
class Field
55
attr_accessor :active, :value
56
57
def initialize(opts)
58
@value = opts[:value]
59
@active = opts[:active].nil? ? true : opts[:active]
60
end
61
62
def size
63
@active ? @size : 0
64
end
65
end
66
67
class String < Field
68
def initialize(opts)
69
super(opts)
70
@size = opts[:size]
71
end
72
73
def parse(str, offset=0)
74
if @active and str.size >= offset + @size
75
@value = str[offset, @size]
76
@size
77
else
78
0
79
end
80
end
81
82
def serialize
83
if @active
84
@value
85
else
86
""
87
end
88
end
89
90
def value=(val)
91
@value = val
92
@size = @value.nil? ? 0 : @value.size
93
@active = (@size > 0)
94
end
95
end
96
97
class Int16LE < Field
98
def initialize(opt)
99
super(opt)
100
@size = 2
101
end
102
103
def parse(str, offset=0)
104
if @active and str.size >= offset + @size
105
@value = str[offset, @size].unpack("v")[0]
106
@size
107
else
108
0
109
end
110
end
111
112
def serialize
113
[@value].pack("v")
114
end
115
end
116
117
class Int32LE < Field
118
def initialize(opt)
119
super(opt)
120
@size = 4
121
end
122
123
def parse(str, offset=0)
124
if @active and str.size >= offset + @size
125
@value = str.slice(offset, @size).unpack("V")[0]
126
@size
127
else
128
0
129
end
130
end
131
132
def serialize
133
[@value].pack("V") if @active
134
end
135
end
136
137
class Int64LE < Field
138
def initialize(opt)
139
super(opt)
140
@size = 8
141
end
142
143
def parse(str, offset=0)
144
if @active and str.size >= offset + @size
145
d, u = str.slice(offset, @size).unpack("V2")
146
@value = (u * 0x100000000 + d)
147
@size
148
else
149
0
150
end
151
end
152
153
def serialize
154
[@value & 0x00000000ffffffff, @value >> 32].pack("V2") if @active
155
end
156
end
157
158
# base class of data structure
159
class FieldSet
160
class << FieldSet
161
def define(&block)
162
klass = Class.new(self) do
163
def self.inherited(subclass)
164
proto = @proto
165
166
subclass.instance_eval do
167
@proto = proto
168
end
169
end
170
end
171
172
klass.module_eval(&block)
173
174
klass
175
end
176
177
def string(name, opts)
178
add_field(name, String, opts)
179
end
180
181
def int16LE(name, opts)
182
add_field(name, Int16LE, opts)
183
end
184
185
def int32LE(name, opts)
186
add_field(name, Int32LE, opts)
187
end
188
189
def int64LE(name, opts)
190
add_field(name, Int64LE, opts)
191
end
192
193
def security_buffer(name, opts)
194
add_field(name, SecurityBuffer, opts)
195
end
196
197
def prototypes
198
@proto
199
end
200
201
def names
202
@proto.map{|n, t, o| n}
203
end
204
205
def types
206
@proto.map{|n, t, o| t}
207
end
208
209
def opts
210
@proto.map{|n, t, o| o}
211
end
212
213
private
214
215
def add_field(name, type, opts)
216
(@proto ||= []).push [name, type, opts]
217
define_accessor name
218
end
219
220
def define_accessor(name)
221
module_eval(<<-End, __FILE__, __LINE__ + 1)
222
def #{name}
223
self['#{name}'].value
224
end
225
226
def #{name}=(val)
227
self['#{name}'].value = val
228
end
229
End
230
end
231
end #self
232
233
def initialize
234
@alist = self.class.prototypes.map{ |n, t, o| [n, t.new(o)] }
235
end
236
237
def serialize
238
@alist.map{|n, f| f.serialize }.join
239
end
240
241
def parse(str, offset=0)
242
@alist.inject(offset){|cur, a| cur += a[1].parse(str, cur)}
243
end
244
245
def size
246
@alist.inject(0){|sum, a| sum += a[1].size}
247
end
248
249
def [](name)
250
a = @alist.assoc(name.to_s.intern)
251
raise ArgumentError, "no such field: #{name}" unless a
252
a[1]
253
end
254
255
def []=(name, val)
256
a = @alist.assoc(name.to_s.intern)
257
raise ArgumentError, "no such field: #{name}" unless a
258
a[1] = val
259
end
260
261
def enable(name)
262
self[name].active = true
263
end
264
265
def disable(name)
266
self[name].active = false
267
end
268
end
269
270
Blob = FieldSet.define {
271
int32LE :blob_signature, {:value => CONST::BLOB_SIGN}
272
int32LE :reserved, {:value => 0}
273
int64LE :timestamp, {:value => 0}
274
string :challenge, {:value => "", :size => 8}
275
int32LE :unknown1, {:value => 0}
276
string :target_info, {:value => "", :size => 0}
277
int32LE :unknown2, {:value => 0}
278
}
279
280
SecurityBuffer = FieldSet.define {
281
int16LE :length, {:value => 0}
282
int16LE :allocated, {:value => 0}
283
int32LE :offset, {:value => 0}
284
}
285
286
287
class SecurityBuffer
288
attr_accessor :active
289
def initialize(opts)
290
super()
291
@value = opts[:value]
292
@active = opts[:active].nil? ? true : opts[:active]
293
@size = 8
294
end
295
296
def parse(str, offset=0)
297
if @active and str.size >= offset + @size
298
super(str, offset)
299
@value = str[self.offset, self.length]
300
@size
301
else
302
0
303
end
304
end
305
306
def serialize
307
super if @active
308
end
309
310
def value
311
@value
312
end
313
314
def value=(val)
315
@value = val
316
self.length = self.allocated = val.size
317
end
318
319
def data_size
320
@active ? @value.size : 0
321
end
322
end
323
end
324
end
325
end
326
end
327
328