librex 0.0.6 → 0.0.7
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.
- data/README.md +3 -5
- data/Rakefile +26 -0
- data/lib/rex/compat.rb +1 -1
- data/lib/rex/exploitation/javascriptosdetect.rb +125 -62
- data/lib/rex/file.rb +15 -0
- data/lib/rex/io/stream.rb +1 -1
- data/lib/rex/parser/nmap_xml.rb +6 -0
- data/lib/rex/poly/block.rb +9 -0
- data/lib/rex/post/meterpreter/client.rb +0 -8
- data/lib/rex/post/meterpreter/extensions/priv/priv.rb +6 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +1 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_advapi32.rb +49 -35
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_netapi32.rb +26 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb +9 -2
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb +630 -0
- data/lib/rex/post/meterpreter/packet.rb +3 -1
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +143 -57
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +6 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +9 -3
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +6 -4
- data/lib/rex/proto.rb +1 -0
- data/lib/rex/proto/dhcp/server.rb +4 -2
- data/lib/rex/proto/http/packet.rb +5 -6
- data/lib/rex/proto/ntlm.rb +7 -0
- data/lib/rex/proto/ntlm.rb.ut.rb +177 -0
- data/lib/rex/proto/ntlm/base.rb +326 -0
- data/lib/rex/proto/ntlm/constants.rb +74 -0
- data/lib/rex/proto/ntlm/crypt.rb +340 -0
- data/lib/rex/proto/ntlm/exceptions.rb +9 -0
- data/lib/rex/proto/ntlm/message.rb +533 -0
- data/lib/rex/proto/ntlm/utils.rb +358 -0
- data/lib/rex/proto/smb/client.rb +548 -86
- data/lib/rex/proto/smb/client.rb.ut.rb +4 -4
- data/lib/rex/proto/smb/constants.rb +7 -24
- data/lib/rex/proto/smb/crypt.rb +12 -71
- data/lib/rex/proto/smb/exceptions.rb +12 -0
- data/lib/rex/proto/smb/simpleclient.rb +17 -5
- data/lib/rex/proto/smb/utils.rb +3 -460
- data/lib/rex/proto/tftp/server.rb +2 -2
- data/lib/rex/script/base.rb +2 -2
- data/lib/rex/socket.rb +12 -0
- data/lib/rex/socket.rb.ut.rb +31 -10
- data/lib/rex/socket/ssl_tcp_server.rb.ut.rb +15 -5
- data/lib/rex/text.rb +55 -4
- data/lib/rex/ui/output.rb +0 -2
- data/lib/rex/ui/text/dispatcher_shell.rb +95 -10
- data/lib/rex/ui/text/output/buffer.rb +0 -4
- data/lib/rex/ui/text/shell.rb +8 -0
- data/lib/rex/ui/text/table.rb +21 -1
- metadata +15 -19
- data/lib/rex/proto/smb/crypt.rb.ut.rb +0 -20
@@ -0,0 +1,533 @@
|
|
1
|
+
#
|
2
|
+
# An NTLM Authentication Library for Ruby
|
3
|
+
#
|
4
|
+
# This code is a derivative of "dbf2.rb" written by yrock
|
5
|
+
# and Minero Aoki. You can find original code here:
|
6
|
+
# http://jp.rubyist.net/magazine/?0013-CodeReview
|
7
|
+
# -------------------------------------------------------------
|
8
|
+
# Copyright (c) 2005,2006 yrock
|
9
|
+
#
|
10
|
+
# This program is free software.
|
11
|
+
# You can distribute/modify this program under the terms of the
|
12
|
+
# Ruby License.
|
13
|
+
#
|
14
|
+
# 2011-02-23 refactored by Alexandre Maloteaux for Metasploit Project
|
15
|
+
# -------------------------------------------------------------
|
16
|
+
#
|
17
|
+
# 2006-02-11 refactored by Minero Aoki
|
18
|
+
# -------------------------------------------------------------
|
19
|
+
#
|
20
|
+
# All protocol information used to write this code stems from
|
21
|
+
# "The NTLM Authentication Protocol" by Eric Glass. The author
|
22
|
+
# would thank to him for this tremendous work and making it
|
23
|
+
# available on the net.
|
24
|
+
# http://davenport.sourceforge.net/ntlm.html
|
25
|
+
# -------------------------------------------------------------
|
26
|
+
# Copyright (c) 2003 Eric Glass
|
27
|
+
#
|
28
|
+
# Permission to use, copy, modify, and distribute this document
|
29
|
+
# for any purpose and without any fee is hereby granted,
|
30
|
+
# provided that the above copyright notice and this list of
|
31
|
+
# conditions appear in all copies.
|
32
|
+
# -------------------------------------------------------------
|
33
|
+
#
|
34
|
+
# The author also looked Mozilla-Firefox-1.0.7 source code,
|
35
|
+
# namely, security/manager/ssl/src/nsNTLMAuthModule.cpp and
|
36
|
+
# Jonathan Bastien-Filiatrault's libntlm-ruby.
|
37
|
+
# "http://x2a.org/websvn/filedetails.php?
|
38
|
+
# repname=libntlm-ruby&path=%2Ftrunk%2Fntlm.rb&sc=1"
|
39
|
+
# The latter has a minor bug in its separate_keys function.
|
40
|
+
# The third key has to begin from the 14th character of the
|
41
|
+
# input string instead of 13th:)
|
42
|
+
#--
|
43
|
+
# $Id: ntlm.rb 11678 2011-01-30 19:26:35Z hdm $
|
44
|
+
#++
|
45
|
+
|
46
|
+
#this module defines the message class , useful for easily handling type 1/2/3 ntlm messages
|
47
|
+
|
48
|
+
require 'rex/proto/ntlm/base'
|
49
|
+
require 'rex/proto/ntlm/constants'
|
50
|
+
require 'rex/proto/ntlm/crypt'
|
51
|
+
|
52
|
+
|
53
|
+
module Rex
|
54
|
+
module Proto
|
55
|
+
module NTLM
|
56
|
+
class Message < Rex::Proto::NTLM::Base::FieldSet
|
57
|
+
|
58
|
+
BASE = Rex::Proto::NTLM::Base
|
59
|
+
CONST = Rex::Proto::NTLM::Constants
|
60
|
+
|
61
|
+
|
62
|
+
class << Message
|
63
|
+
def parse(str)
|
64
|
+
m = Type0.new
|
65
|
+
m.parse(str)
|
66
|
+
case m.type
|
67
|
+
when 1
|
68
|
+
t = Type1.parse(str)
|
69
|
+
when 2
|
70
|
+
t = Type2.parse(str)
|
71
|
+
when 3
|
72
|
+
t = Type3.parse(str)
|
73
|
+
else
|
74
|
+
raise ArgumentError, "unknown type: #{m.type}"
|
75
|
+
end
|
76
|
+
t
|
77
|
+
end
|
78
|
+
|
79
|
+
def decode64(str)
|
80
|
+
parse(Rex::Text::decode_base64(str))
|
81
|
+
end
|
82
|
+
end#self
|
83
|
+
|
84
|
+
def has_flag?(flag)
|
85
|
+
(self[:flag].value & CONST::FLAGS[flag]) == CONST::FLAGS[flag]
|
86
|
+
end
|
87
|
+
|
88
|
+
def set_flag(flag)
|
89
|
+
self[:flag].value |= CONST::FLAGS[flag]
|
90
|
+
end
|
91
|
+
|
92
|
+
def dump_flags
|
93
|
+
CONST::FLAG_KEYS.each{ |k| print(k, "=", flag?(k), "\n") }
|
94
|
+
end
|
95
|
+
|
96
|
+
def serialize
|
97
|
+
deflag
|
98
|
+
super + security_buffers.map{|n, f| f.value}.join
|
99
|
+
end
|
100
|
+
|
101
|
+
def encode64
|
102
|
+
Rex::Text::encode_base64(serialize)
|
103
|
+
end
|
104
|
+
|
105
|
+
def decode64(str)
|
106
|
+
parse(Rex::Text::decode_base64(str))
|
107
|
+
end
|
108
|
+
|
109
|
+
alias head_size size
|
110
|
+
|
111
|
+
def data_size
|
112
|
+
security_buffers.inject(0){|sum, a| sum += a[1].data_size}
|
113
|
+
end
|
114
|
+
|
115
|
+
def size
|
116
|
+
head_size + data_size
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def security_buffers
|
122
|
+
@alist.find_all{|n, f| f.instance_of?(BASE::SecurityBuffer)}
|
123
|
+
end
|
124
|
+
|
125
|
+
def deflag
|
126
|
+
security_buffers.inject(head_size){|cur, a|
|
127
|
+
a[1].offset = cur
|
128
|
+
cur += a[1].data_size
|
129
|
+
}
|
130
|
+
end
|
131
|
+
|
132
|
+
def data_edge
|
133
|
+
security_buffers.map{ |n, f| f.active ? f.offset : size}.min
|
134
|
+
end
|
135
|
+
|
136
|
+
# sub class definitions
|
137
|
+
|
138
|
+
Type0 = Message.define {
|
139
|
+
string :sign, {:size => 8, :value => CONST::SSP_SIGN}
|
140
|
+
int32LE :type, {:value => 0}
|
141
|
+
}
|
142
|
+
|
143
|
+
Type1 = Message.define {
|
144
|
+
string :sign, {:size => 8, :value => CONST::SSP_SIGN}
|
145
|
+
int32LE :type, {:value => 1}
|
146
|
+
int32LE :flag, {:value => CONST::DEFAULT_FLAGS[:TYPE1] }
|
147
|
+
security_buffer :domain, {:value => "", :active => false}
|
148
|
+
security_buffer :workstation, {:value => "", :active => false}
|
149
|
+
string :padding, {:size => 0, :value => "", :active => false }
|
150
|
+
}
|
151
|
+
|
152
|
+
class Type1
|
153
|
+
class << Type1
|
154
|
+
def parse(str)
|
155
|
+
t = new
|
156
|
+
t.parse(str)
|
157
|
+
t
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def parse(str)
|
162
|
+
super(str)
|
163
|
+
enable(:domain) if has_flag?(:DOMAIN_SUPPLIED)
|
164
|
+
enable(:workstation) if has_flag?(:WORKSTATION_SUPPLIED)
|
165
|
+
super(str)
|
166
|
+
if ( (len = data_edge - head_size) > 0)
|
167
|
+
self.padding = "\0" * len
|
168
|
+
super(str)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
Type2 = Message.define{
|
174
|
+
string :sign, {:size => 8, :value => CONST::SSP_SIGN}
|
175
|
+
int32LE :type, {:value => 2}
|
176
|
+
security_buffer :target_name, {:size => 0, :value => ""}
|
177
|
+
int32LE :flag, {:value => CONST::DEFAULT_FLAGS[:TYPE2]}
|
178
|
+
int64LE :challenge, {:value => 0}
|
179
|
+
int64LE :context, {:value => 0, :active => false}
|
180
|
+
security_buffer :target_info, {:value => "", :active => false}
|
181
|
+
string :padding, {:size => 0, :value => "", :active => false }
|
182
|
+
}
|
183
|
+
|
184
|
+
class Type2
|
185
|
+
class << Type2
|
186
|
+
def parse(str)
|
187
|
+
t = new
|
188
|
+
t.parse(str)
|
189
|
+
t
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def parse(str)
|
194
|
+
super(str)
|
195
|
+
if has_flag?(:TARGET_INFO)
|
196
|
+
enable(:context)
|
197
|
+
enable(:target_info)
|
198
|
+
super(str)
|
199
|
+
end
|
200
|
+
if ( (len = data_edge - head_size) > 0)
|
201
|
+
self.padding = "\0" * len
|
202
|
+
super(str)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def response(arg, opt = {})
|
207
|
+
usr = arg[:user]
|
208
|
+
pwd = arg[:password]
|
209
|
+
if usr.nil? or pwd.nil?
|
210
|
+
raise ArgumentError, "user and password have to be supplied"
|
211
|
+
end
|
212
|
+
|
213
|
+
if opt[:workstation]
|
214
|
+
ws = opt[:workstation]
|
215
|
+
else
|
216
|
+
ws = ""
|
217
|
+
end
|
218
|
+
|
219
|
+
if opt[:client_challenge]
|
220
|
+
cc = opt[:client_challenge]
|
221
|
+
else
|
222
|
+
cc = rand(CONST::MAX64)
|
223
|
+
end
|
224
|
+
cc = Rex::Text::pack_int64le(cc) if cc.is_a?(Integer)
|
225
|
+
opt[:client_challenge] = cc
|
226
|
+
|
227
|
+
if has_flag?(:OEM) and opt[:unicode]
|
228
|
+
usr = Rex::Text::to_ascii(usr,'utf-16le')
|
229
|
+
pwd = Rex::Text::to_ascii(pwd,'utf-16le')
|
230
|
+
ws = Rex::Text::to_ascii(ws,'utf-16le')
|
231
|
+
opt[:unicode] = false
|
232
|
+
end
|
233
|
+
|
234
|
+
if has_flag?(:UNICODE) and !opt[:unicode]
|
235
|
+
usr = Rex::Text::to_unicode(usr,'utf-16le')
|
236
|
+
pwd = Rex::Text::to_unicode(pwd,'utf-16le')
|
237
|
+
ws = Rex::Text::to_unicode(ws,'utf-16le')
|
238
|
+
opt[:unicode] = true
|
239
|
+
end
|
240
|
+
|
241
|
+
tgt = self.target_name
|
242
|
+
ti = self.target_info
|
243
|
+
|
244
|
+
chal = self[:challenge].serialize
|
245
|
+
|
246
|
+
if opt[:ntlmv2]
|
247
|
+
ar = { :ntlmv2_hash => NTLM::ntlmv2_hash(usr, pwd, tgt, opt),
|
248
|
+
:challenge => chal, :target_info => ti}
|
249
|
+
lm_res = NTLM::lmv2_response(ar, opt)
|
250
|
+
ntlm_res = NTLM::ntlmv2_response(ar, opt)
|
251
|
+
elsif has_flag?(:NTLM2_KEY)
|
252
|
+
ar = {:ntlm_hash => NTLM::ntlm_hash(pwd, opt), :challenge => chal}
|
253
|
+
lm_res, ntlm_res = NTLM::ntlm2_session(ar, opt)
|
254
|
+
else
|
255
|
+
lm_res = NTLM::lm_response(pwd, chal)
|
256
|
+
ntlm_res = NTLM::ntlm_response(pwd, chal)
|
257
|
+
end
|
258
|
+
|
259
|
+
Type3.create({
|
260
|
+
:lm_response => lm_res,
|
261
|
+
:ntlm_response => ntlm_res,
|
262
|
+
:domain => tgt,
|
263
|
+
:user => usr,
|
264
|
+
:workstation => ws,
|
265
|
+
:flag => self.flag
|
266
|
+
})
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
|
271
|
+
Type3 = Message.define{
|
272
|
+
string :sign, {:size => 8, :value => CONST::SSP_SIGN}
|
273
|
+
int32LE :type, {:value => 3}
|
274
|
+
security_buffer :lm_response, {:value => ""}
|
275
|
+
security_buffer :ntlm_response, {:value => ""}
|
276
|
+
security_buffer :domain, {:value => ""}
|
277
|
+
security_buffer :user, {:value => ""}
|
278
|
+
security_buffer :workstation, {:value => ""}
|
279
|
+
security_buffer :session_key, {:value => "", :active => false }
|
280
|
+
int64LE :flag, {:value => 0, :active => false }
|
281
|
+
}
|
282
|
+
|
283
|
+
class Type3
|
284
|
+
class << Type3
|
285
|
+
def parse(str)
|
286
|
+
t = new
|
287
|
+
t.parse(str)
|
288
|
+
t
|
289
|
+
end
|
290
|
+
|
291
|
+
def create(arg, opt ={})
|
292
|
+
t = new
|
293
|
+
t.lm_response = arg[:lm_response]
|
294
|
+
t.ntlm_response = arg[:ntlm_response]
|
295
|
+
t.domain = arg[:domain]
|
296
|
+
t.user = arg[:user]
|
297
|
+
t.workstation = arg[:workstation]
|
298
|
+
|
299
|
+
if arg[:session_key]
|
300
|
+
t.enable(:session_key)
|
301
|
+
t.session_key = arg[session_key]
|
302
|
+
end
|
303
|
+
if arg[:flag]
|
304
|
+
t.enable(:session_key)
|
305
|
+
t.enable(:flag)
|
306
|
+
t.flag = arg[:flag]
|
307
|
+
end
|
308
|
+
t
|
309
|
+
end
|
310
|
+
end#self
|
311
|
+
end
|
312
|
+
|
313
|
+
public
|
314
|
+
#those class method have been merged from lib/rex/smb/utils
|
315
|
+
|
316
|
+
#
|
317
|
+
# Process Type 3 NTLM Message (in Base64)
|
318
|
+
#
|
319
|
+
# from http://www.innovation.ch/personal/ronald/ntlm.html
|
320
|
+
#
|
321
|
+
# struct {
|
322
|
+
# byte protocol[8]; // 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0'
|
323
|
+
# byte type; // 0x03
|
324
|
+
# byte zero[3];
|
325
|
+
#
|
326
|
+
# short lm_resp_len; // LanManager response length (always 0x18)
|
327
|
+
# short lm_resp_len; // LanManager response length (always 0x18)
|
328
|
+
# short lm_resp_off; // LanManager response offset
|
329
|
+
# byte zero[2];
|
330
|
+
#
|
331
|
+
# short nt_resp_len; // NT response length (always 0x18)
|
332
|
+
# short nt_resp_len; // NT response length (always 0x18)
|
333
|
+
# short nt_resp_off; // NT response offset
|
334
|
+
# byte zero[2];
|
335
|
+
#
|
336
|
+
# short dom_len; // domain string length
|
337
|
+
# short dom_len; // domain string length
|
338
|
+
# short dom_off; // domain string offset (always 0x40)
|
339
|
+
# byte zero[2];
|
340
|
+
#
|
341
|
+
# short user_len; // username string length
|
342
|
+
# short user_len; // username string length
|
343
|
+
# short user_off; // username string offset
|
344
|
+
# byte zero[2];
|
345
|
+
#
|
346
|
+
# short host_len; // host string length
|
347
|
+
# short host_len; // host string length
|
348
|
+
# short host_off; // host string offset
|
349
|
+
# byte zero[6];
|
350
|
+
#
|
351
|
+
# short msg_len; // message length
|
352
|
+
# byte zero[2];
|
353
|
+
#
|
354
|
+
# short flags; // 0x8201
|
355
|
+
# byte zero[2];
|
356
|
+
#
|
357
|
+
# byte dom[*]; // domain string (unicode UTF-16LE)
|
358
|
+
# byte user[*]; // username string (unicode UTF-16LE)
|
359
|
+
# byte host[*]; // host string (unicode UTF-16LE)
|
360
|
+
# byte lm_resp[*]; // LanManager response
|
361
|
+
# byte nt_resp[*]; // NT response
|
362
|
+
# } type_3_message
|
363
|
+
#
|
364
|
+
def self.process_type3_message(message)
|
365
|
+
decode = Rex::Text.decode_base64(message.strip)
|
366
|
+
type = decode[8,1].unpack("C").first
|
367
|
+
if (type == 3)
|
368
|
+
lm_len = decode[12,2].unpack("v").first
|
369
|
+
lm_offset = decode[16,2].unpack("v").first
|
370
|
+
lm = decode[lm_offset, lm_len].unpack("H*").first
|
371
|
+
|
372
|
+
nt_len = decode[20,2].unpack("v").first
|
373
|
+
nt_offset = decode[24,2].unpack("v").first
|
374
|
+
nt = decode[nt_offset, nt_len].unpack("H*").first
|
375
|
+
|
376
|
+
dom_len = decode[28,2].unpack("v").first
|
377
|
+
dom_offset = decode[32,2].unpack("v").first
|
378
|
+
domain = decode[dom_offset, dom_len]
|
379
|
+
|
380
|
+
user_len = decode[36,2].unpack("v").first
|
381
|
+
user_offset = decode[40,2].unpack("v").first
|
382
|
+
user = decode[user_offset, user_len]
|
383
|
+
|
384
|
+
host_len = decode[44,2].unpack("v").first
|
385
|
+
host_offset = decode[48,2].unpack("v").first
|
386
|
+
host = decode[host_offset, host_len]
|
387
|
+
|
388
|
+
return domain, user, host, lm, nt
|
389
|
+
else
|
390
|
+
return "", "", "", "", ""
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
|
395
|
+
|
396
|
+
#
|
397
|
+
# Process Type 1 NTLM Messages, return a Base64 Type 2 Message
|
398
|
+
#
|
399
|
+
def self.process_type1_message(message, nonce = "\x11\x22\x33\x44\x55\x66\x77\x88", win_domain = 'DOMAIN',
|
400
|
+
win_name = 'SERVER', dns_name = 'server', dns_domain = 'example.com', downgrade = true)
|
401
|
+
|
402
|
+
dns_name = Rex::Text.to_unicode(dns_name + "." + dns_domain)
|
403
|
+
win_domain = Rex::Text.to_unicode(win_domain)
|
404
|
+
dns_domain = Rex::Text.to_unicode(dns_domain)
|
405
|
+
win_name = Rex::Text.to_unicode(win_name)
|
406
|
+
decode = Rex::Text.decode_base64(message.strip)
|
407
|
+
|
408
|
+
type = decode[8,1].unpack("C").first
|
409
|
+
|
410
|
+
if (type == 1)
|
411
|
+
# A type 1 message has been received, lets build a type 2 message response
|
412
|
+
|
413
|
+
reqflags = decode[12,4]
|
414
|
+
reqflags = reqflags.unpack("V").first
|
415
|
+
|
416
|
+
if (reqflags & CONST::REQUEST_TARGET) == CONST::REQUEST_TARGET
|
417
|
+
|
418
|
+
if (downgrade)
|
419
|
+
# At this time NTLMv2 and signing requirements are not supported
|
420
|
+
if (reqflags & CONST::NEGOTIATE_NTLM2_KEY) == CONST::NEGOTIATE_NTLM2_KEY
|
421
|
+
reqflags = reqflags - CONST::NEGOTIATE_NTLM2_KEY
|
422
|
+
end
|
423
|
+
if (reqflags & CONST::NEGOTIATE_ALWAYS_SIGN) == CONST::NEGOTIATE_ALWAYS_SIGN
|
424
|
+
reqflags = reqflags - CONST::NEGOTIATE_ALWAYS_SIGN
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
flags = reqflags + CONST::TARGET_TYPE_DOMAIN + CONST::TARGET_TYPE_SERVER
|
429
|
+
tid = true
|
430
|
+
|
431
|
+
tidoffset = 48 + win_domain.length
|
432
|
+
tidbuff =
|
433
|
+
[2].pack('v') + # tid type, win domain
|
434
|
+
[win_domain.length].pack('v') +
|
435
|
+
win_domain +
|
436
|
+
[1].pack('v') + # tid type, server name
|
437
|
+
[win_name.length].pack('v') +
|
438
|
+
win_name +
|
439
|
+
[4].pack('v') + # tid type, domain name
|
440
|
+
[dns_domain.length].pack('v') +
|
441
|
+
dns_domain +
|
442
|
+
[3].pack('v') + # tid type, dns_name
|
443
|
+
[dns_name.length].pack('v') +
|
444
|
+
dns_name
|
445
|
+
else
|
446
|
+
flags = CONST::NEGOTIATE_UNICODE + CONST::NEGOTIATE_NTLM
|
447
|
+
tid = false
|
448
|
+
end
|
449
|
+
|
450
|
+
type2msg = "NTLMSSP\0" + # protocol, 8 bytes
|
451
|
+
"\x02\x00\x00\x00" # type, 4 bytes
|
452
|
+
|
453
|
+
if (tid)
|
454
|
+
type2msg += # Target security info, 8 bytes. Filled if REQUEST_TARGET
|
455
|
+
[win_domain.length].pack('v') + # Length, 2 bytes
|
456
|
+
[win_domain.length].pack('v') # Allocated space, 2 bytes
|
457
|
+
end
|
458
|
+
|
459
|
+
type2msg +="\x30\x00\x00\x00" + # Offset, 4 bytes
|
460
|
+
[flags].pack('V') + # flags, 4 bytes
|
461
|
+
nonce + # the nonce, 8 bytes
|
462
|
+
"\x00" * 8 # Context (all 0s), 8 bytes
|
463
|
+
|
464
|
+
if (tid)
|
465
|
+
type2msg += # Target information security buffer. Filled if REQUEST_TARGET
|
466
|
+
[tidbuff.length].pack('v') + # Length, 2 bytes
|
467
|
+
[tidbuff.length].pack('v') + # Allocated space, 2 bytes
|
468
|
+
[tidoffset].pack('V') + # Offset, 4 bytes (usually \x48 + length of win_domain)
|
469
|
+
win_domain + # Target name data (domain in unicode if REQUEST_UNICODE)
|
470
|
+
# Target information data
|
471
|
+
tidbuff + # Type, 2 bytes
|
472
|
+
# Length, 2 bytes
|
473
|
+
# Data (in unicode if REQUEST_UNICODE)
|
474
|
+
"\x00\x00\x00\x00" # Terminator, 4 bytes, all \x00
|
475
|
+
end
|
476
|
+
|
477
|
+
type2msg = Rex::Text.encode_base64(type2msg).delete("\n") # base64 encode and remove the returns
|
478
|
+
else
|
479
|
+
# This is not a Type2 message
|
480
|
+
type2msg = ""
|
481
|
+
end
|
482
|
+
|
483
|
+
return type2msg
|
484
|
+
end
|
485
|
+
|
486
|
+
#
|
487
|
+
# Downgrading Type messages to LMv1/NTLMv1 and removing signing
|
488
|
+
#
|
489
|
+
def self.downgrade_type_message(message)
|
490
|
+
decode = Rex::Text.decode_base64(message.strip)
|
491
|
+
|
492
|
+
type = decode[8,1].unpack("C").first
|
493
|
+
|
494
|
+
if (type > 0 and type < 4)
|
495
|
+
reqflags = decode[12..15] if (type == 1 or type == 3)
|
496
|
+
reqflags = decode[20..23] if (type == 2)
|
497
|
+
reqflags = reqflags.unpack("V")
|
498
|
+
|
499
|
+
# Remove NEGOTIATE_NTLMV2_KEY and NEGOTIATE_ALWAYS_SIGN, this lowers the negotiation
|
500
|
+
# down to LMv1/NTLMv1.
|
501
|
+
if (reqflags & CONST::NEGOTIATE_NTLM2_KEY) == CONST::NEGOTIATE_NTLM2_KEY
|
502
|
+
reqflags = reqflags - CONST::NEGOTIATE_NTLM2_KEY
|
503
|
+
end
|
504
|
+
if (reqflags & CONST::NEGOTIATE_ALWAYS_SIGN) == CONST::NEGOTIATE_ALWAYS_SIGN
|
505
|
+
reqflags = reqflags - CONST::NEGOTIATE_ALWAYS_SIGN
|
506
|
+
end
|
507
|
+
|
508
|
+
# Return the flags back to the decode so we can base64 it again
|
509
|
+
flags = reqflags.to_s(16)
|
510
|
+
0.upto(8) do |idx|
|
511
|
+
if (idx > flags.length)
|
512
|
+
flags.insert(0, "0")
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
idx = 0
|
517
|
+
0.upto(3) do |cnt|
|
518
|
+
if (type == 2)
|
519
|
+
decode[23-cnt] = [flags[idx,1]].pack("C")
|
520
|
+
else
|
521
|
+
decode[15-cnt] = [flags[idx,1]].pack("C")
|
522
|
+
end
|
523
|
+
idx += 2
|
524
|
+
end
|
525
|
+
|
526
|
+
end
|
527
|
+
return Rex::Text.encode_base64(decode).delete("\n") # base64 encode and remove the returns
|
528
|
+
end
|
529
|
+
|
530
|
+
end
|
531
|
+
end
|
532
|
+
end
|
533
|
+
end
|