librex 0.0.12 → 0.0.13
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.markdown +1 -1
- data/Rakefile +1 -1
- data/lib/rex/io/stream.rb +1 -1
- data/lib/rex/parser/nmap_xml.rb +4 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun.rb.ts.rb +6 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/api_constants.rb.ut.rb +31 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/buffer_item.rb +47 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/buffer_item.rb.ut.rb +36 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/{model.rb → dll.rb} +4 -226
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb +100 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_function.rb.ut.rb +42 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb +148 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/dll_helper.rb.ut.rb +127 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/multicall.rb +2 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb +3 -2
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb +1 -1
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb +75 -0
- data/lib/rex/post/meterpreter/extensions/stdapi/railgun/win_const_manager.rb.ut.rb +103 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +44 -0
- data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +2 -2
- data/lib/rex/proto/dhcp/server.rb +7 -6
- data/lib/rex/proto/ntlm/utils.rb +505 -100
- data/lib/rex/proto/rfb/cipher.rb +6 -0
- data/lib/rex/proto/smb/client.rb +40 -332
- data/lib/rex/proto/smb/simpleclient.rb +3 -1
- data/lib/rex/proto/smb/utils.rb +0 -4
- metadata +14 -4
@@ -63,6 +63,7 @@ class Console::CommandDispatcher::Core
|
|
63
63
|
"migrate" => "Migrate the server to another process",
|
64
64
|
"use" => "Load a one or more meterpreter extensions",
|
65
65
|
"quit" => "Terminate the meterpreter session",
|
66
|
+
"resource" => "Run the commands stored in a file",
|
66
67
|
"read" => "Reads data from a channel",
|
67
68
|
"run" => "Executes a meterpreter script or Post module",
|
68
69
|
"bgrun" => "Executes a meterpreter script as a background thread",
|
@@ -598,6 +599,49 @@ class Console::CommandDispatcher::Core
|
|
598
599
|
return true
|
599
600
|
end
|
600
601
|
|
602
|
+
def cmd_resource_tabs(str, words)
|
603
|
+
return [] if words.length > 1
|
604
|
+
|
605
|
+
tab_complete_filenames(str, words)
|
606
|
+
end
|
607
|
+
|
608
|
+
def cmd_resource(*args)
|
609
|
+
if args.empty?
|
610
|
+
print(
|
611
|
+
"Usage: resource path1 path2" +
|
612
|
+
"Run the commands stored in the supplied files.\n")
|
613
|
+
return false
|
614
|
+
end
|
615
|
+
args.each do |glob|
|
616
|
+
files = ::Dir.glob(::File.expand_path(glob))
|
617
|
+
if files.empty?
|
618
|
+
print_error("No such file #{glob}")
|
619
|
+
next
|
620
|
+
end
|
621
|
+
files.each do |filename|
|
622
|
+
print_status("Reading #{filename}")
|
623
|
+
if (not ::File.readable?(filename))
|
624
|
+
print_error("Could not read file #{filename}")
|
625
|
+
next
|
626
|
+
else
|
627
|
+
::File.open(filename, "r").each_line do |line|
|
628
|
+
next if line.strip.length < 1
|
629
|
+
next if line[0,1] == "#"
|
630
|
+
begin
|
631
|
+
print_status("Running #{line}")
|
632
|
+
client.console.run_single(line)
|
633
|
+
rescue ::Exception => e
|
634
|
+
print_error("Error Running Command #{line}: #{e.class} #{e}")
|
635
|
+
end
|
636
|
+
|
637
|
+
end
|
638
|
+
end
|
639
|
+
end
|
640
|
+
end
|
641
|
+
end
|
642
|
+
|
643
|
+
|
644
|
+
|
601
645
|
@@client_extension_search_paths = [ ::File.join(Rex::Root, "post", "meterpreter", "ui", "console", "command_dispatcher") ]
|
602
646
|
|
603
647
|
def self.add_client_extension_search_path(path)
|
@@ -457,8 +457,8 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|
457
457
|
#
|
458
458
|
def cmd_sysinfo(*args)
|
459
459
|
info = client.sys.config.sysinfo
|
460
|
-
width =
|
461
|
-
info.keys.each { |k| width = k.length if k.length > width }
|
460
|
+
width = "Meterpreter".length
|
461
|
+
info.keys.each { |k| width = k.length if k.length > width and info[k] }
|
462
462
|
|
463
463
|
info.each_pair do |key, value|
|
464
464
|
print_line("#{key.ljust(width+1)}: #{value}") if value
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: server.rb
|
1
|
+
# $Id: server.rb 12030 2011-03-20 00:33:02Z scriptjunkie $
|
2
2
|
|
3
3
|
require 'rex/socket'
|
4
4
|
require 'rex/proto/dhcp'
|
@@ -236,11 +236,12 @@ protected
|
|
236
236
|
pkt << buf[1..7] #hwtype, hwlen, hops, txid
|
237
237
|
pkt << "\x00\x00\x00\x00" #elapsed, flags
|
238
238
|
pkt << clientip
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
239
|
+
if messageType == DHCPDiscover
|
240
|
+
# give next ip address (not super reliable high volume but it should work for a basic server)
|
241
|
+
self.current_ip += 1
|
242
|
+
if self.current_ip > self.end_ip
|
243
|
+
self.current_ip = self.start_ip
|
244
|
+
end
|
244
245
|
end
|
245
246
|
pkt << Rex::Socket.addr_iton(self.current_ip)
|
246
247
|
pkt << self.ipstring #next server ip
|
data/lib/rex/proto/ntlm/utils.rb
CHANGED
@@ -1,8 +1,14 @@
|
|
1
|
+
require 'rex/proto/ntlm/constants'
|
2
|
+
require 'rex/proto/ntlm/crypt'
|
3
|
+
|
1
4
|
module Rex
|
2
5
|
module Proto
|
3
6
|
module NTLM
|
4
7
|
class Utils
|
5
8
|
|
9
|
+
CONST = Rex::Proto::NTLM::Constants
|
10
|
+
CRYPT = Rex::Proto::NTLM::Crypt
|
11
|
+
|
6
12
|
#duplicate from lib/rex/proto/smb/utils cause we only need this fonction from Rex::Proto::SMB::Utils
|
7
13
|
# Convert a unix timestamp to a 64-bit signed server time
|
8
14
|
def self.time_unix_to_smb(unix_time)
|
@@ -12,6 +18,11 @@ class Utils
|
|
12
18
|
return [thi, tlo]
|
13
19
|
end
|
14
20
|
|
21
|
+
# Determine whether the password is a known hash format
|
22
|
+
def self.is_pass_ntlm_hash?(str)
|
23
|
+
str.downcase =~ /^[0-9a-f]{32}:[0-9a-f]{32}$/
|
24
|
+
end
|
25
|
+
|
15
26
|
#
|
16
27
|
# Prepends an ASN1 formatted length field to a piece of data
|
17
28
|
#
|
@@ -116,6 +127,26 @@ class Utils
|
|
116
127
|
return blob
|
117
128
|
end
|
118
129
|
|
130
|
+
# BLOB without GSS usefull for ntlmssp type 1 message
|
131
|
+
def self.make_ntlmssp_blob_init(domain = 'WORKGROUP', name = 'WORKSTATION', flags=0x80201)
|
132
|
+
blob = "NTLMSSP\x00" +
|
133
|
+
[1, flags].pack('VV') +
|
134
|
+
|
135
|
+
[
|
136
|
+
domain.length, #length
|
137
|
+
domain.length, #max length
|
138
|
+
32
|
139
|
+
].pack('vvV') +
|
140
|
+
|
141
|
+
[
|
142
|
+
name.length, #length
|
143
|
+
name.length, #max length
|
144
|
+
domain.length + 32
|
145
|
+
].pack('vvV') +
|
146
|
+
|
147
|
+
domain + name
|
148
|
+
return blob
|
149
|
+
end
|
119
150
|
|
120
151
|
# GSS BLOB usefull for ntlmssp type 1 message
|
121
152
|
def self.make_ntlmssp_secblob_init(domain = 'WORKGROUP', name = 'WORKSTATION', flags=0x80201)
|
@@ -135,22 +166,7 @@ class Utils
|
|
135
166
|
) +
|
136
167
|
"\xa2" + self.asn1encode(
|
137
168
|
"\x04" + self.asn1encode(
|
138
|
-
|
139
|
-
[1, flags].pack('VV') +
|
140
|
-
|
141
|
-
[
|
142
|
-
domain.length, #length
|
143
|
-
domain.length, #max length
|
144
|
-
32
|
145
|
-
].pack('vvV') +
|
146
|
-
|
147
|
-
[
|
148
|
-
name.length, #length
|
149
|
-
name.length, #max length
|
150
|
-
domain.length + 32
|
151
|
-
].pack('vvV') +
|
152
|
-
|
153
|
-
domain + name
|
169
|
+
make_ntlmssp_blob_init(domain, name, flags)
|
154
170
|
)
|
155
171
|
)
|
156
172
|
)
|
@@ -161,33 +177,6 @@ class Utils
|
|
161
177
|
end
|
162
178
|
|
163
179
|
|
164
|
-
# GSS BLOB usefull for ntlmssp type 2 message
|
165
|
-
def self.make_ntlmssp_secblob_chall(win_domain, win_name, dns_domain, dns_name, chall, flags)
|
166
|
-
|
167
|
-
blob =
|
168
|
-
"\xa1" + self.asn1encode(
|
169
|
-
"\x30" + self.asn1encode(
|
170
|
-
"\xa0" + self.asn1encode(
|
171
|
-
"\x0a" + self.asn1encode(
|
172
|
-
"\x01"
|
173
|
-
)
|
174
|
-
) +
|
175
|
-
"\xa1" + self.asn1encode(
|
176
|
-
"\x06" + self.asn1encode(
|
177
|
-
"\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"
|
178
|
-
)
|
179
|
-
) +
|
180
|
-
"\xa2" + self.asn1encode(
|
181
|
-
"\x04" + self.asn1encode(
|
182
|
-
make_ntlmssp_blob_chall(win_domain, win_name, dns_domain, dns_name, chall, flags)
|
183
|
-
)
|
184
|
-
)
|
185
|
-
)
|
186
|
-
)
|
187
|
-
|
188
|
-
return blob
|
189
|
-
end
|
190
|
-
|
191
180
|
# BLOB without GSS usefull for ntlm type 2 message
|
192
181
|
def self.make_ntlmssp_blob_chall(win_domain, win_name, dns_domain, dns_name, chall, flags)
|
193
182
|
|
@@ -219,10 +208,35 @@ class Utils
|
|
219
208
|
return blob
|
220
209
|
end
|
221
210
|
|
211
|
+
# GSS BLOB usefull for ntlmssp type 2 message
|
212
|
+
def self.make_ntlmssp_secblob_chall(win_domain, win_name, dns_domain, dns_name, chall, flags)
|
213
|
+
|
214
|
+
blob =
|
215
|
+
"\xa1" + self.asn1encode(
|
216
|
+
"\x30" + self.asn1encode(
|
217
|
+
"\xa0" + self.asn1encode(
|
218
|
+
"\x0a" + self.asn1encode(
|
219
|
+
"\x01"
|
220
|
+
)
|
221
|
+
) +
|
222
|
+
"\xa1" + self.asn1encode(
|
223
|
+
"\x06" + self.asn1encode(
|
224
|
+
"\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"
|
225
|
+
)
|
226
|
+
) +
|
227
|
+
"\xa2" + self.asn1encode(
|
228
|
+
"\x04" + self.asn1encode(
|
229
|
+
make_ntlmssp_blob_chall(win_domain, win_name, dns_domain, dns_name, chall, flags)
|
230
|
+
)
|
231
|
+
)
|
232
|
+
)
|
233
|
+
)
|
222
234
|
|
223
|
-
|
224
|
-
|
235
|
+
return blob
|
236
|
+
end
|
225
237
|
|
238
|
+
# BLOB without GSS Usefull for ntlmssp type 3 message
|
239
|
+
def self.make_ntlmssp_blob_auth(domain, name, user, lm, ntlm, enc_session_key, flags = 0x080201)
|
226
240
|
lm ||= "\x00" * 24
|
227
241
|
ntlm ||= "\x00" * 24
|
228
242
|
|
@@ -232,59 +246,67 @@ class Utils
|
|
232
246
|
session = enc_session_key
|
233
247
|
|
234
248
|
ptr = 64
|
249
|
+
|
250
|
+
blob = "NTLMSSP\x00" +
|
251
|
+
[ 3 ].pack('V') +
|
252
|
+
|
253
|
+
[ # Lan Manager Response
|
254
|
+
lm.length,
|
255
|
+
lm.length,
|
256
|
+
(ptr)
|
257
|
+
].pack('vvV') +
|
258
|
+
|
259
|
+
[ # NTLM Manager Response
|
260
|
+
ntlm.length,
|
261
|
+
ntlm.length,
|
262
|
+
(ptr += lm.length)
|
263
|
+
].pack('vvV') +
|
264
|
+
|
265
|
+
[ # Domain Name
|
266
|
+
domain_uni.length,
|
267
|
+
domain_uni.length,
|
268
|
+
(ptr += ntlm.length)
|
269
|
+
].pack('vvV') +
|
270
|
+
|
271
|
+
[ # Username
|
272
|
+
user_uni.length,
|
273
|
+
user_uni.length,
|
274
|
+
(ptr += domain_uni.length)
|
275
|
+
].pack('vvV') +
|
276
|
+
|
277
|
+
[ # Hostname
|
278
|
+
name_uni.length,
|
279
|
+
name_uni.length,
|
280
|
+
(ptr += user_uni.length)
|
281
|
+
].pack('vvV') +
|
282
|
+
|
283
|
+
[ # Session Key (none)
|
284
|
+
session.length,
|
285
|
+
session.length,
|
286
|
+
(ptr += name_uni.length)
|
287
|
+
].pack('vvV') +
|
288
|
+
|
289
|
+
[ flags ].pack('V') +
|
290
|
+
|
291
|
+
lm +
|
292
|
+
ntlm +
|
293
|
+
domain_uni +
|
294
|
+
user_uni +
|
295
|
+
name_uni +
|
296
|
+
session + "\x00"
|
297
|
+
return blob
|
298
|
+
|
299
|
+
end
|
300
|
+
|
301
|
+
# GSS BLOB Usefull for ntlmssp type 3 message
|
302
|
+
def self.make_ntlmssp_secblob_auth(domain, name, user, lm, ntlm, enc_session_key, flags = 0x080201)
|
303
|
+
|
235
304
|
blob =
|
236
305
|
"\xa1" + self.asn1encode(
|
237
306
|
"\x30" + self.asn1encode(
|
238
307
|
"\xa2" + self.asn1encode(
|
239
308
|
"\x04" + self.asn1encode(
|
240
|
-
|
241
|
-
"NTLMSSP\x00" +
|
242
|
-
[ 3 ].pack('V') +
|
243
|
-
|
244
|
-
[ # Lan Manager Response
|
245
|
-
lm.length,
|
246
|
-
lm.length,
|
247
|
-
(ptr)
|
248
|
-
].pack('vvV') +
|
249
|
-
|
250
|
-
[ # NTLM Manager Response
|
251
|
-
ntlm.length,
|
252
|
-
ntlm.length,
|
253
|
-
(ptr += lm.length)
|
254
|
-
].pack('vvV') +
|
255
|
-
|
256
|
-
[ # Domain Name
|
257
|
-
domain_uni.length,
|
258
|
-
domain_uni.length,
|
259
|
-
(ptr += ntlm.length)
|
260
|
-
].pack('vvV') +
|
261
|
-
|
262
|
-
[ # Username
|
263
|
-
user_uni.length,
|
264
|
-
user_uni.length,
|
265
|
-
(ptr += domain_uni.length)
|
266
|
-
].pack('vvV') +
|
267
|
-
|
268
|
-
[ # Hostname
|
269
|
-
name_uni.length,
|
270
|
-
name_uni.length,
|
271
|
-
(ptr += user_uni.length)
|
272
|
-
].pack('vvV') +
|
273
|
-
|
274
|
-
[ # Session Key (none)
|
275
|
-
session.length,
|
276
|
-
session.length,
|
277
|
-
(ptr += name_uni.length)
|
278
|
-
].pack('vvV') +
|
279
|
-
|
280
|
-
[ flags ].pack('V') +
|
281
|
-
|
282
|
-
lm +
|
283
|
-
ntlm +
|
284
|
-
domain_uni +
|
285
|
-
user_uni +
|
286
|
-
name_uni +
|
287
|
-
session + "\x00"
|
309
|
+
make_ntlmssp_blob_auth(domain, name, user, lm, ntlm, enc_session_key, flags )
|
288
310
|
)
|
289
311
|
)
|
290
312
|
)
|
@@ -308,13 +330,107 @@ class Utils
|
|
308
330
|
return blob
|
309
331
|
end
|
310
332
|
|
333
|
+
# Return the correct ntlmflags upon the configuration
|
334
|
+
def self.make_ntlm_flags(opt = {})
|
335
|
+
|
336
|
+
signing = opt[:signing] != nil ? opt[:signing] : false
|
337
|
+
usentlm2_session = opt[:usentlm2_session] != nil ? opt[:usentlm2_session] : true
|
338
|
+
use_ntlmv2 = opt[:use_ntlmv2] != nil ? opt[:use_ntlmv2] : false
|
339
|
+
send_lm = opt[:send_lm] != nil ? opt[:send_lm] : true
|
340
|
+
send_ntlm = opt[:send_ntlm] != nil ? opt[:send_ntlm] : true
|
341
|
+
use_lanman_key = opt[:use_lanman_key] != nil ? opt[:use_lanman_key] : false
|
342
|
+
|
343
|
+
if signing
|
344
|
+
ntlmssp_flags = 0xe2088215
|
345
|
+
else
|
346
|
+
|
347
|
+
ntlmssp_flags = 0xa2080205
|
348
|
+
end
|
349
|
+
|
350
|
+
if usentlm2_session
|
351
|
+
if use_ntlmv2
|
352
|
+
#set Negotiate Target Info
|
353
|
+
ntlmssp_flags |= CONST::NEGOTIATE_TARGET_INFO
|
354
|
+
end
|
355
|
+
|
356
|
+
else
|
357
|
+
#remove the ntlm2_session flag
|
358
|
+
ntlmssp_flags &= 0xfff7ffff
|
359
|
+
#set lanmanflag only when lm and ntlm are sent
|
360
|
+
if send_lm
|
361
|
+
ntlmssp_flags |= CONST::NEGOTIATE_LMKEY if use_lanman_key
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
#we can also downgrade ntlm2_session when we send only lmv1
|
366
|
+
ntlmssp_flags &= 0xfff7ffff if usentlm2_session && (not use_ntlmv2) && (not send_ntlm)
|
367
|
+
|
368
|
+
return ntlmssp_flags
|
369
|
+
end
|
370
|
+
|
371
|
+
|
372
|
+
# Parse an ntlm type 2 challenge blob and return usefull data
|
373
|
+
def self.parse_ntlm_type_2_blob(blob)
|
374
|
+
data = {}
|
375
|
+
# Extract the NTLM challenge key the lazy way
|
376
|
+
cidx = blob.index("NTLMSSP\x00\x02\x00\x00\x00")
|
377
|
+
|
378
|
+
if not cidx
|
379
|
+
raise XCEPT::NTLM2MissingChallenge
|
380
|
+
end
|
381
|
+
|
382
|
+
data[:challenge_key] = blob[cidx + 24, 8]
|
383
|
+
|
384
|
+
data[:server_ntlmssp_flags] = blob[cidx + 20, 4].unpack("V")[0]
|
385
|
+
|
386
|
+
# Extract the address list from the blob
|
387
|
+
alist_len,alist_mlen,alist_off = blob[cidx + 40, 8].unpack("vvV")
|
388
|
+
alist_buf = blob[cidx + alist_off, alist_len]
|
389
|
+
|
390
|
+
while(alist_buf.length > 0)
|
391
|
+
atype, alen = alist_buf.slice!(0,4).unpack('vv')
|
392
|
+
break if atype == 0x00
|
393
|
+
addr = alist_buf.slice!(0, alen)
|
394
|
+
case atype
|
395
|
+
when 1
|
396
|
+
#netbios name
|
397
|
+
data[:default_name] = addr.gsub("\x00", '')
|
398
|
+
when 2
|
399
|
+
#netbios domain
|
400
|
+
data[:default_domain] = addr.gsub("\x00", '')
|
401
|
+
when 3
|
402
|
+
#dns name
|
403
|
+
data[:dns_host_name] = addr.gsub("\x00", '')
|
404
|
+
when 4
|
405
|
+
#dns domain
|
406
|
+
data[:dns_domain_name] = addr.gsub("\x00", '')
|
407
|
+
when 5
|
408
|
+
#The FQDN of the forest.
|
409
|
+
when 6
|
410
|
+
#A 32-bit value indicating server or client configuration
|
411
|
+
when 7
|
412
|
+
#Client time
|
413
|
+
data[:chall_MsvAvTimestamp] = addr
|
414
|
+
when 8
|
415
|
+
#A Restriction_Encoding structure
|
416
|
+
when 9
|
417
|
+
#The SPN of the target server.
|
418
|
+
when 10
|
419
|
+
#A channel bindings hash.
|
420
|
+
end
|
421
|
+
end
|
422
|
+
return data
|
423
|
+
end
|
424
|
+
|
311
425
|
# This function return an ntlmv2 client challenge
|
312
|
-
|
426
|
+
# This is a partial implementation, full description is in [MS-NLMP].pdf around 3.1.5.2.1 :-/
|
427
|
+
def self.make_ntlmv2_clientchallenge(win_domain, win_name, dns_domain, dns_name,
|
428
|
+
client_challenge = nil, chall_MsvAvTimestamp = nil, spnopt = {})
|
313
429
|
|
314
430
|
client_challenge ||= Rex::Text.rand_text(8)
|
315
431
|
# We have to set the timestamps here to the one in the challenge message from server if present
|
316
|
-
# If we don't do that, recent server like
|
317
|
-
timestamp = chall_MsvAvTimestamp !=
|
432
|
+
# If we don't do that, recent server like Seven/2008 will send a STATUS_INVALID_PARAMETER error packet
|
433
|
+
timestamp = chall_MsvAvTimestamp != '' ? chall_MsvAvTimestamp : self.time_unix_to_smb(Time.now.to_i).reverse.pack("VV")
|
318
434
|
# Make those values unicode as requested
|
319
435
|
win_domain = Rex::Text.to_unicode(win_domain)
|
320
436
|
win_name = Rex::Text.to_unicode(win_name)
|
@@ -328,6 +444,14 @@ class Utils
|
|
328
444
|
addr_list << [3, dns_name.length].pack('vv') + dns_name
|
329
445
|
addr_list << [7, 8].pack('vv') + timestamp
|
330
446
|
|
447
|
+
# Windows Seven / 2008r2 Request this type if in local security policies,
|
448
|
+
# Microsoft network server : Server SPN target name validation level is set to <Required from client>
|
449
|
+
# otherwise it send an STATUS_ACCESS_DENIED packet
|
450
|
+
if spnopt[:use_spn]
|
451
|
+
spn= Rex::Text.to_unicode("cifs/#{spnopt[:name] || 'unknow'}")
|
452
|
+
addr_list << [9, spn.length].pack('vv') + spn
|
453
|
+
end
|
454
|
+
|
331
455
|
# MAY BE USEFUL FOR FUTURE
|
332
456
|
# Seven (client) add at least one more av that is of type MsAvRestrictions (8)
|
333
457
|
# maybe this will be usefull with future windows OSs but has no use at all for the moment afaik
|
@@ -338,10 +462,6 @@ class Utils
|
|
338
462
|
# Seven (client) and maybe others versions also add an av of type MsvChannelBindings (10) but the hash is "\x00" * 16
|
339
463
|
# addr_list << [10, 16].pack('vv') + "\x00" * 16
|
340
464
|
|
341
|
-
# Seven and maybe other versions also add an av of type MsvAvTargetName(9) with value cifs/target(_ip)
|
342
|
-
# implementing it will necessary require knowing the target here, todo... :-/
|
343
|
-
# spn= Rex::Text.to_unicode("cifs/RHOST")
|
344
|
-
# addr_list << [9, spn.length].pack('vv') + spn
|
345
465
|
|
346
466
|
addr_list << [0, 0].pack('vv')
|
347
467
|
ntlm_clientchallenge = [1,1,0,0].pack("CCvV") + #RespType, HiRespType, Reserved1, Reserved2
|
@@ -352,6 +472,291 @@ class Utils
|
|
352
472
|
|
353
473
|
end
|
354
474
|
|
475
|
+
# create lm/ntlm responses
|
476
|
+
def self.create_lm_ntlm_responses(user, pass, challenge_key, domain = '', default_name = '', default_domain = '',
|
477
|
+
dns_host_name = '', dns_domain_name = '', chall_MsvAvTimestamp = nil, spnopt = {}, opt = {} )
|
478
|
+
|
479
|
+
usentlm2_session = opt[:usentlm2_session] != nil ? opt[:usentlm2_session] : true
|
480
|
+
use_ntlmv2 = opt[:use_ntlmv2] != nil ? opt[:use_ntlmv2] : false
|
481
|
+
send_lm = opt[:send_lm] != nil ? opt[:send_lm] : true
|
482
|
+
send_ntlm = opt[:send_ntlm] != nil ? opt[:send_ntlm] : true
|
483
|
+
|
484
|
+
#calculate the lm/ntlm response
|
485
|
+
resp_lm = "\x00" * 24
|
486
|
+
resp_ntlm = "\x00" * 24
|
487
|
+
|
488
|
+
client_challenge = Rex::Text.rand_text(8)
|
489
|
+
ntlm_cli_challenge = ''
|
490
|
+
if send_ntlm #should be default
|
491
|
+
if usentlm2_session
|
492
|
+
if use_ntlmv2
|
493
|
+
ntlm_cli_challenge = self.make_ntlmv2_clientchallenge(default_domain, default_name, dns_domain_name,
|
494
|
+
dns_host_name,client_challenge ,
|
495
|
+
chall_MsvAvTimestamp, spnopt)
|
496
|
+
if self.is_pass_ntlm_hash?(pass)
|
497
|
+
argntlm = {
|
498
|
+
:ntlmv2_hash => CRYPT::ntlmv2_hash(
|
499
|
+
user,
|
500
|
+
[ pass.upcase()[33,65] ].pack('H32'),
|
501
|
+
domain,{:pass_is_hash => true}
|
502
|
+
),
|
503
|
+
:challenge => challenge_key
|
504
|
+
}
|
505
|
+
else
|
506
|
+
argntlm = {
|
507
|
+
:ntlmv2_hash => CRYPT::ntlmv2_hash(user, pass, domain),
|
508
|
+
:challenge => challenge_key
|
509
|
+
}
|
510
|
+
end
|
511
|
+
|
512
|
+
optntlm = { :nt_client_challenge => ntlm_cli_challenge}
|
513
|
+
ntlmv2_response = CRYPT::ntlmv2_response(argntlm,optntlm)
|
514
|
+
resp_ntlm = ntlmv2_response
|
515
|
+
|
516
|
+
if send_lm
|
517
|
+
if self.is_pass_ntlm_hash?(pass)
|
518
|
+
arglm = {
|
519
|
+
:ntlmv2_hash => CRYPT::ntlmv2_hash(
|
520
|
+
user,
|
521
|
+
[ pass.upcase()[33,65] ].pack('H32'),
|
522
|
+
domain,{:pass_is_hash => true}
|
523
|
+
),
|
524
|
+
:challenge => challenge_key
|
525
|
+
}
|
526
|
+
else
|
527
|
+
arglm = {
|
528
|
+
:ntlmv2_hash => CRYPT::ntlmv2_hash(user,pass, domain),
|
529
|
+
:challenge => challenge_key
|
530
|
+
}
|
531
|
+
end
|
532
|
+
|
533
|
+
optlm = { :client_challenge => client_challenge }
|
534
|
+
resp_lm = CRYPT::lmv2_response(arglm, optlm)
|
535
|
+
else
|
536
|
+
resp_lm = "\x00" * 24
|
537
|
+
end
|
538
|
+
|
539
|
+
else # ntlm2_session
|
540
|
+
if self.is_pass_ntlm_hash?(pass)
|
541
|
+
argntlm = {
|
542
|
+
:ntlm_hash => [ pass.upcase()[33,65] ].pack('H32'),
|
543
|
+
:challenge => challenge_key
|
544
|
+
}
|
545
|
+
else
|
546
|
+
argntlm = {
|
547
|
+
:ntlm_hash => CRYPT::ntlm_hash(pass),
|
548
|
+
:challenge => challenge_key
|
549
|
+
}
|
550
|
+
end
|
551
|
+
|
552
|
+
optntlm = { :client_challenge => client_challenge}
|
553
|
+
resp_ntlm = CRYPT::ntlm2_session(argntlm,optntlm).join[24,24]
|
554
|
+
|
555
|
+
# Generate the fake LANMAN hash
|
556
|
+
resp_lm = client_challenge + ("\x00" * 16)
|
557
|
+
end
|
558
|
+
|
559
|
+
else # we use lmv1/ntlmv1
|
560
|
+
if self.is_pass_ntlm_hash?(pass)
|
561
|
+
argntlm = {
|
562
|
+
:ntlm_hash => [ pass.upcase()[33,65] ].pack('H32'),
|
563
|
+
:challenge => challenge_key
|
564
|
+
}
|
565
|
+
else
|
566
|
+
argntlm = {
|
567
|
+
:ntlm_hash => CRYPT::ntlm_hash(pass),
|
568
|
+
:challenge => challenge_key
|
569
|
+
}
|
570
|
+
end
|
571
|
+
|
572
|
+
resp_ntlm = CRYPT::ntlm_response(argntlm)
|
573
|
+
if send_lm
|
574
|
+
if self.is_pass_ntlm_hash?(pass)
|
575
|
+
arglm = {
|
576
|
+
:lm_hash => [ pass.upcase()[0,32] ].pack('H32'),
|
577
|
+
:challenge => challenge_key
|
578
|
+
}
|
579
|
+
else
|
580
|
+
arglm = {
|
581
|
+
:lm_hash => CRYPT::lm_hash(pass),
|
582
|
+
:challenge => challenge_key
|
583
|
+
}
|
584
|
+
end
|
585
|
+
resp_lm = CRYPT::lm_response(arglm)
|
586
|
+
else
|
587
|
+
#when windows does not send lm in ntlmv1 type response,
|
588
|
+
# it gives lm response the same value as ntlm response
|
589
|
+
resp_lm = resp_ntlm
|
590
|
+
end
|
591
|
+
end
|
592
|
+
else #send_ntlm = false
|
593
|
+
#lmv2
|
594
|
+
if usentlm2_session && use_ntlmv2
|
595
|
+
if self.is_pass_ntlm_hash?(pass)
|
596
|
+
arglm = {
|
597
|
+
:ntlmv2_hash => CRYPT::ntlmv2_hash(
|
598
|
+
user,
|
599
|
+
[ pass.upcase()[33,65] ].pack('H32'),
|
600
|
+
domain,{:pass_is_hash => true}
|
601
|
+
),
|
602
|
+
:challenge => challenge_key
|
603
|
+
}
|
604
|
+
else
|
605
|
+
arglm = {
|
606
|
+
:ntlmv2_hash => CRYPT::ntlmv2_hash(user,pass, domain),
|
607
|
+
:challenge => challenge_key
|
608
|
+
}
|
609
|
+
end
|
610
|
+
optlm = { :client_challenge => client_challenge }
|
611
|
+
resp_lm = CRYPT::lmv2_response(arglm, optlm)
|
612
|
+
else
|
613
|
+
if self.is_pass_ntlm_hash?(pass)
|
614
|
+
arglm = {
|
615
|
+
:lm_hash => [ pass.upcase()[0,32] ].pack('H32'),
|
616
|
+
:challenge => challenge_key
|
617
|
+
}
|
618
|
+
else
|
619
|
+
arglm = {
|
620
|
+
:lm_hash => CRYPT::lm_hash(pass),
|
621
|
+
:challenge => challenge_key
|
622
|
+
}
|
623
|
+
end
|
624
|
+
resp_lm = CRYPT::lm_response(arglm)
|
625
|
+
end
|
626
|
+
resp_ntlm = ""
|
627
|
+
end
|
628
|
+
return resp_lm, resp_ntlm, client_challenge, ntlm_cli_challenge
|
629
|
+
end
|
630
|
+
|
631
|
+
# create the session key
|
632
|
+
def self.create_session_key(server_ntlmssp_flags, user, pass, domain, challenge_key,
|
633
|
+
client_challenge = '', ntlm_cli_challenge = '' , opt = {} )
|
634
|
+
|
635
|
+
usentlm2_session = opt[:usentlm2_session] != nil ? opt[:usentlm2_session] : true
|
636
|
+
use_ntlmv2 = opt[:use_ntlmv2] != nil ? opt[:use_ntlmv2] : false
|
637
|
+
send_lm = opt[:send_lm] != nil ? opt[:send_lm] : true
|
638
|
+
send_ntlm = opt[:send_ntlm] != nil ? opt[:send_ntlm] : true
|
639
|
+
use_lanman_key = opt[:use_lanman_key] != nil ? opt[:use_lanman_key] : false
|
640
|
+
|
641
|
+
# Create the sessionkey (aka signing key, aka mackey) and encrypted session key
|
642
|
+
# Server will decide for key_size and key_exchange
|
643
|
+
enc_session_key = ''
|
644
|
+
signing_key = ''
|
645
|
+
|
646
|
+
# Set default key size and key exchange values
|
647
|
+
key_size = 40
|
648
|
+
key_exchange = false
|
649
|
+
# Remove ntlmssp.negotiate56
|
650
|
+
ntlmssp_flags &= 0x7fffffff
|
651
|
+
# Remove ntlmssp.negotiatekeyexch
|
652
|
+
ntlmssp_flags &= 0xbfffffff
|
653
|
+
# Remove ntlmssp.negotiate128
|
654
|
+
ntlmssp_flags &= 0xdfffffff
|
655
|
+
# Check the keyexchange
|
656
|
+
if server_ntlmssp_flags & CONST::NEGOTIATE_KEY_EXCH != 0 then
|
657
|
+
key_exchange = true
|
658
|
+
ntlmssp_flags |= CONST::NEGOTIATE_KEY_EXCH
|
659
|
+
end
|
660
|
+
# Check 128bits
|
661
|
+
if server_ntlmssp_flags & CONST::NEGOTIATE_128 != 0 then
|
662
|
+
key_size = 128
|
663
|
+
ntlmssp_flags |= CONST::NEGOTIATE_128
|
664
|
+
ntlmssp_flags |= CONST::NEGOTIATE_56
|
665
|
+
# Check 56bits
|
666
|
+
else
|
667
|
+
if server_ntlmssp_flags & CONST::NEGOTIATE_56 != 0 then
|
668
|
+
key_size = 56
|
669
|
+
ntlmssp_flags |= CONST::NEGOTIATE_56
|
670
|
+
end
|
671
|
+
end
|
672
|
+
|
673
|
+
# Generate the user session key
|
674
|
+
lanman_weak = false
|
675
|
+
if send_ntlm # Should be default
|
676
|
+
if usentlm2_session
|
677
|
+
if use_ntlmv2
|
678
|
+
if self.is_pass_ntlm_hash?(pass)
|
679
|
+
user_session_key = CRYPT::ntlmv2_user_session_key(user,
|
680
|
+
[ pass.upcase()[33,65] ].pack('H32'),
|
681
|
+
domain,
|
682
|
+
challenge_key, ntlm_cli_challenge,
|
683
|
+
{:pass_is_hash => true})
|
684
|
+
else
|
685
|
+
user_session_key = CRYPT::ntlmv2_user_session_key(user, pass, domain,
|
686
|
+
challenge_key, ntlm_cli_challenge)
|
687
|
+
end
|
688
|
+
else
|
689
|
+
if self.is_pass_ntlm_hash?(pass)
|
690
|
+
user_session_key = CRYPT::ntlm2_session_user_session_key([ pass.upcase()[33,65] ].pack('H32'),
|
691
|
+
challenge_key,
|
692
|
+
client_challenge,
|
693
|
+
{:pass_is_hash => true})
|
694
|
+
else
|
695
|
+
user_session_key = CRYPT::ntlm2_session_user_session_key(pass, challenge_key,
|
696
|
+
client_challenge)
|
697
|
+
end
|
698
|
+
end
|
699
|
+
else # lmv1/ntlmv1
|
700
|
+
# lanman_key may also be used without ntlm response but it is not so much used
|
701
|
+
# so we don't care about this feature
|
702
|
+
if send_lm && use_lanman_key
|
703
|
+
if self.is_pass_ntlm_hash?(pass)
|
704
|
+
user_session_key = CRYPT::lanman_session_key([ pass.upcase()[0,32] ].pack('H32'),
|
705
|
+
challenge_key,
|
706
|
+
{:pass_is_hash => true})
|
707
|
+
else
|
708
|
+
user_session_key = CRYPT::lanman_session_key(pass, challenge_key)
|
709
|
+
end
|
710
|
+
lanman_weak = true
|
711
|
+
|
712
|
+
|
713
|
+
else
|
714
|
+
if self.is_pass_ntlm_hash?(pass)
|
715
|
+
user_session_key = CRYPT::ntlmv1_user_session_key([ pass.upcase()[33,65] ].pack('H32'),
|
716
|
+
{:pass_is_hash => true})
|
717
|
+
else
|
718
|
+
user_session_key = CRYPT::ntlmv1_user_session_key(pass)
|
719
|
+
end
|
720
|
+
end
|
721
|
+
end
|
722
|
+
else
|
723
|
+
if usentlm2_session && use_ntlmv2
|
724
|
+
if self.is_pass_ntlm_hash?(pass)
|
725
|
+
user_session_key = CRYPT::lmv2_user_session_key(user, [ pass.upcase()[33,65] ].pack('H32'),
|
726
|
+
domain,
|
727
|
+
challenge_key, client_challenge,
|
728
|
+
{:pass_is_hash => true})
|
729
|
+
else
|
730
|
+
user_session_key = CRYPT::lmv2_user_session_key(user, pass, domain,
|
731
|
+
challenge_key, client_challenge)
|
732
|
+
end
|
733
|
+
else
|
734
|
+
if self.is_pass_ntlm_hash?(pass)
|
735
|
+
user_session_key = CRYPT::lmv1_user_session_key([ pass.upcase()[0,32] ].pack('H32'),
|
736
|
+
{:pass_is_hash => true})
|
737
|
+
else
|
738
|
+
user_session_key = CRYPT::lmv1_user_session_key(pass)
|
739
|
+
end
|
740
|
+
end
|
741
|
+
end
|
742
|
+
|
743
|
+
user_session_key = CRYPT::make_weak_sessionkey(user_session_key,key_size, lanman_weak)
|
744
|
+
|
745
|
+
# Sessionkey and encrypted session key
|
746
|
+
if key_exchange
|
747
|
+
signing_key = Rex::Text.rand_text(16)
|
748
|
+
enc_session_key = CRYPT::encrypt_sessionkey(signing_key, user_session_key)
|
749
|
+
else
|
750
|
+
signing_key = user_session_key
|
751
|
+
end
|
752
|
+
|
753
|
+
return signing_key, enc_session_key
|
754
|
+
|
755
|
+
|
756
|
+
end
|
757
|
+
|
758
|
+
|
759
|
+
|
355
760
|
end
|
356
761
|
end
|
357
762
|
end
|