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
@@ -140,6 +140,8 @@ class Tlv
|
|
140
140
|
else; 'unknown-meta-type'
|
141
141
|
end
|
142
142
|
stype = case type
|
143
|
+
when PACKET_TYPE_REQUEST; "Request"
|
144
|
+
when PACKET_TYPE_RESPONSE; "Response"
|
143
145
|
when TLV_TYPE_REQUEST_ID; "REQUEST-ID"
|
144
146
|
when TLV_TYPE_METHOD; "METHOD"
|
145
147
|
when TLV_TYPE_RESULT; "RESULT"
|
@@ -182,7 +184,7 @@ class Tlv
|
|
182
184
|
if val.length > 50
|
183
185
|
val = val[0,50] + ' ..."'
|
184
186
|
end
|
185
|
-
"#<#{self.class} type=#{stype}
|
187
|
+
"#<#{self.class} type=#{stype} #{self.class.to_s =~ /Packet/ ? "tlvs=#{@tlvs.inspect}" : "meta=#{meta} value=#{val}"} >"
|
186
188
|
end
|
187
189
|
|
188
190
|
##
|
@@ -26,6 +26,21 @@ class Console::CommandDispatcher::Core
|
|
26
26
|
self.extensions = []
|
27
27
|
self.bgjobs = []
|
28
28
|
self.bgjob_id = 0
|
29
|
+
|
30
|
+
@msf_loaded = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def msf_loaded?
|
34
|
+
return @msf_loaded unless @msf_loaded.nil?
|
35
|
+
# if we get here we must not have initialized yet
|
36
|
+
|
37
|
+
if client.framework
|
38
|
+
# We have a framework instance so the msf libraries should be
|
39
|
+
# available. Load up the ones we're going to use
|
40
|
+
require 'msf/base/serializer/readable_text'
|
41
|
+
end
|
42
|
+
@msf_loaded = !!(client.framework)
|
43
|
+
@msf_loaded
|
29
44
|
end
|
30
45
|
|
31
46
|
@@use_opts = Rex::Parser::Arguments.new(
|
@@ -36,7 +51,7 @@ class Console::CommandDispatcher::Core
|
|
36
51
|
# List of supported commands.
|
37
52
|
#
|
38
53
|
def commands
|
39
|
-
{
|
54
|
+
c = {
|
40
55
|
"?" => "Help menu",
|
41
56
|
"background" => "Backgrounds the current session",
|
42
57
|
"close" => "Closes a channel",
|
@@ -49,12 +64,17 @@ class Console::CommandDispatcher::Core
|
|
49
64
|
"use" => "Load a one or more meterpreter extensions",
|
50
65
|
"quit" => "Terminate the meterpreter session",
|
51
66
|
"read" => "Reads data from a channel",
|
52
|
-
"run" => "Executes a meterpreter script",
|
67
|
+
"run" => "Executes a meterpreter script or Post module",
|
53
68
|
"bgrun" => "Executes a meterpreter script as a background thread",
|
54
69
|
"bgkill" => "Kills a background meterpreter script",
|
55
70
|
"bglist" => "Lists running background scripts",
|
56
71
|
"write" => "Writes data to a channel",
|
57
72
|
}
|
73
|
+
if (msf_loaded?)
|
74
|
+
c["info"] = "Displays information about a Post module"
|
75
|
+
end
|
76
|
+
|
77
|
+
c
|
58
78
|
end
|
59
79
|
|
60
80
|
#
|
@@ -159,15 +179,6 @@ class Console::CommandDispatcher::Core
|
|
159
179
|
|
160
180
|
alias cmd_quit cmd_exit
|
161
181
|
|
162
|
-
#
|
163
|
-
# Displays the help menu.
|
164
|
-
#
|
165
|
-
def cmd_help(*args)
|
166
|
-
print(shell.help_to_s)
|
167
|
-
end
|
168
|
-
|
169
|
-
alias cmd_? cmd_help
|
170
|
-
|
171
182
|
#
|
172
183
|
# Interacts with a channel.
|
173
184
|
#
|
@@ -331,21 +342,48 @@ class Console::CommandDispatcher::Core
|
|
331
342
|
return true
|
332
343
|
end
|
333
344
|
|
345
|
+
def cmd_run_help
|
346
|
+
print_line "Usage: run <script> [arguments]"
|
347
|
+
print_line
|
348
|
+
print_line "Executes a ruby script or Metasploit Post module in the context of the"
|
349
|
+
print_line "meterpreter session. Post modules can take arguments in var=val format."
|
350
|
+
print_line "Example: run post/foo/bar BAZ=abcd"
|
351
|
+
print_line
|
352
|
+
end
|
353
|
+
|
334
354
|
#
|
335
355
|
# Executes a script in the context of the meterpreter session.
|
336
356
|
#
|
337
357
|
def cmd_run(*args)
|
338
358
|
if args.length == 0
|
339
|
-
|
340
|
-
"Usage: run <script> [arguments]\n\n" +
|
341
|
-
"Executes a ruby script in the context of the meterpreter session.")
|
359
|
+
cmd_run_help
|
342
360
|
return true
|
343
361
|
end
|
344
362
|
|
345
363
|
# Get the script name
|
346
364
|
begin
|
347
|
-
|
348
|
-
|
365
|
+
script_name = args.shift
|
366
|
+
# First try it as a Post module if we have access to the Metasploit
|
367
|
+
# Framework instance. If we don't, or if no such module exists,
|
368
|
+
# fall back to using the scripting interface.
|
369
|
+
if (msf_loaded? and mod = client.framework.modules.create(script_name))
|
370
|
+
omod = mod
|
371
|
+
mod = client.framework.modules.reload_module(mod)
|
372
|
+
if (not mod)
|
373
|
+
print_error("Failed to reload module: #{client.framework.modules.failed[omod.file_path]}")
|
374
|
+
return
|
375
|
+
end
|
376
|
+
opts = (args + [ "SESSION=#{client.sid}" ]).join(',')
|
377
|
+
mod.run_simple(
|
378
|
+
#'RunAsJob' => true,
|
379
|
+
'LocalInput' => shell.input,
|
380
|
+
'LocalOutput' => shell.output,
|
381
|
+
'OptionStr' => opts
|
382
|
+
)
|
383
|
+
else
|
384
|
+
# the rest of the arguments get passed in through the binding
|
385
|
+
client.execute_script(script_name, args)
|
386
|
+
end
|
349
387
|
rescue
|
350
388
|
print_error("Error in script: #{$!.class} #{$!}")
|
351
389
|
elog("Error in script: #{$!.class} #{$!}")
|
@@ -357,9 +395,12 @@ class Console::CommandDispatcher::Core
|
|
357
395
|
tabs = []
|
358
396
|
if(not words[1] or not words[1].match(/^\//))
|
359
397
|
begin
|
398
|
+
if (msf_loaded?)
|
399
|
+
tabs += tab_complete_postmods
|
400
|
+
end
|
360
401
|
[
|
361
|
-
::Msf::Sessions::Meterpreter
|
362
|
-
::Msf::Sessions::Meterpreter
|
402
|
+
::Msf::Sessions::Meterpreter.script_base,
|
403
|
+
::Msf::Sessions::Meterpreter.user_script_base
|
363
404
|
].each do |dir|
|
364
405
|
next if not ::File.exist? dir
|
365
406
|
tabs += ::Dir.new(dir).find_all { |e|
|
@@ -370,7 +411,7 @@ class Console::CommandDispatcher::Core
|
|
370
411
|
rescue Exception
|
371
412
|
end
|
372
413
|
end
|
373
|
-
return tabs.map { |e| e.sub
|
414
|
+
return tabs.map { |e| e.sub(/\.rb$/, '') }
|
374
415
|
end
|
375
416
|
|
376
417
|
|
@@ -445,6 +486,36 @@ class Console::CommandDispatcher::Core
|
|
445
486
|
end
|
446
487
|
end
|
447
488
|
|
489
|
+
#
|
490
|
+
# Show info for a given Post module.
|
491
|
+
#
|
492
|
+
# See also +cmd_info+ in lib/msf/ui/console/command_dispatcher/core.rb
|
493
|
+
#
|
494
|
+
def cmd_info(*args)
|
495
|
+
return unless msf_loaded?
|
496
|
+
|
497
|
+
if args.length != 1
|
498
|
+
print_error 'Usage: info <module>'
|
499
|
+
return
|
500
|
+
end
|
501
|
+
|
502
|
+
module_name = args.shift
|
503
|
+
mod = client.framework.modules.create(module_name);
|
504
|
+
|
505
|
+
if mod.nil?
|
506
|
+
print_error 'Invalid module: ' << module_name
|
507
|
+
end
|
508
|
+
|
509
|
+
if (mod)
|
510
|
+
print_line ::Msf::Serializer::ReadableText.dump_module(mod)
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
def cmd_info_tabs(*args)
|
515
|
+
return unless msf_loaded?
|
516
|
+
tab_complete_postmods
|
517
|
+
end
|
518
|
+
|
448
519
|
#
|
449
520
|
# Writes data to a channel.
|
450
521
|
#
|
@@ -527,27 +598,13 @@ class Console::CommandDispatcher::Core
|
|
527
598
|
return true
|
528
599
|
end
|
529
600
|
|
530
|
-
|
531
|
-
# Provide command-specific tab completion
|
532
|
-
# Stolen directly from msf/ui/console/command_dispatcher/core.rb
|
533
|
-
# perhaps this should be moved into rex/ui/text/dispatcher_shell.rb ?
|
534
|
-
#
|
535
|
-
def tab_complete_helper(str, words)
|
536
|
-
items = []
|
537
|
-
|
538
|
-
# Is the user trying to tab complete one of our commands?
|
539
|
-
if (commands.include?(words[0]))
|
540
|
-
if (self.respond_to?('cmd_'+words[0]+'_tabs'))
|
541
|
-
res = self.send('cmd_'+words[0]+'_tabs', str, words)
|
542
|
-
return nil if res.nil?
|
543
|
-
items.concat(res)
|
544
|
-
else
|
545
|
-
# Avoid the default completion list for known commands
|
546
|
-
return nil
|
547
|
-
end
|
548
|
-
end
|
601
|
+
@@client_extension_search_paths = [ ::File.join(Rex::Root, "post", "meterpreter", "ui", "console", "command_dispatcher") ]
|
549
602
|
|
550
|
-
|
603
|
+
def self.add_client_extension_search_path(path)
|
604
|
+
@@client_extension_search_paths << path unless @@client_extension_search_paths.include?(path)
|
605
|
+
end
|
606
|
+
def self.client_extension_search_paths
|
607
|
+
@@client_extension_search_paths
|
551
608
|
end
|
552
609
|
|
553
610
|
protected
|
@@ -561,29 +618,40 @@ protected
|
|
561
618
|
# Loads the client extension specified in mod
|
562
619
|
#
|
563
620
|
def add_extension_client(mod)
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
621
|
+
loaded = false
|
622
|
+
klass = nil
|
623
|
+
self.class.client_extension_search_paths.each do |path|
|
624
|
+
path = ::File.join(path, "#{mod}.rb")
|
625
|
+
klass = CommDispatcher.check_hash(path)
|
626
|
+
if (klass == nil)
|
627
|
+
old = CommDispatcher.constants
|
628
|
+
next unless ::File.exist? path
|
629
|
+
|
630
|
+
if (require(path))
|
631
|
+
new = CommDispatcher.constants
|
632
|
+
diff = new - old
|
633
|
+
|
634
|
+
next if (diff.empty?)
|
635
|
+
|
636
|
+
klass = CommDispatcher.const_get(diff[0])
|
637
|
+
|
638
|
+
CommDispatcher.set_hash(path, klass)
|
639
|
+
loaded = true
|
640
|
+
break
|
641
|
+
else
|
642
|
+
print_error("Failed to load client script file: #{path}")
|
576
643
|
return false
|
577
644
|
end
|
578
|
-
|
579
|
-
klass = CommDispatcher.const_get(diff[0])
|
580
|
-
|
581
|
-
CommDispatcher.set_hash(path, klass)
|
582
645
|
else
|
583
|
-
|
584
|
-
|
646
|
+
# the klass is already loaded, from a previous invocation
|
647
|
+
loaded = true
|
648
|
+
break
|
585
649
|
end
|
586
650
|
end
|
651
|
+
unless loaded
|
652
|
+
print_error("Failed to load client portion of #{mod}.")
|
653
|
+
return false
|
654
|
+
end
|
587
655
|
|
588
656
|
# Enstack the dispatcher
|
589
657
|
self.shell.enstack_dispatcher(klass)
|
@@ -591,6 +659,24 @@ protected
|
|
591
659
|
# Insert the module into the list of extensions
|
592
660
|
self.extensions << mod
|
593
661
|
end
|
662
|
+
|
663
|
+
def tab_complete_postmods
|
664
|
+
# XXX This might get slow with a large number of post
|
665
|
+
# modules. The proper solution is probably to implement a
|
666
|
+
# Module::Post#session_compatible?(session_object_or_int) method
|
667
|
+
tabs = client.framework.modules.post.map { |name,klass|
|
668
|
+
mod = klass.new
|
669
|
+
if mod.compatible_sessions.include?(client.sid)
|
670
|
+
mod.fullname.dup
|
671
|
+
else
|
672
|
+
nil
|
673
|
+
end
|
674
|
+
}
|
675
|
+
|
676
|
+
# nils confuse readline
|
677
|
+
tabs.compact
|
678
|
+
end
|
679
|
+
|
594
680
|
end
|
595
681
|
|
596
682
|
end
|
@@ -185,9 +185,7 @@ class Console::CommandDispatcher::Stdapi::Net
|
|
185
185
|
@@portfwd_opts.parse(args) { |opt, idx, val|
|
186
186
|
case opt
|
187
187
|
when "-h"
|
188
|
-
|
189
|
-
"Usage: portfwd [-h] [add / delete / list] [args]\n\n" +
|
190
|
-
@@portfwd_opts.usage)
|
188
|
+
cmd_portfwd_help
|
191
189
|
return true
|
192
190
|
when "-l"
|
193
191
|
lport = val.to_i
|
@@ -265,9 +263,17 @@ class Console::CommandDispatcher::Stdapi::Net
|
|
265
263
|
print_error("Failed to stop TCP relay on #{lhost || '0.0.0.0'}:#{lport}")
|
266
264
|
end
|
267
265
|
|
266
|
+
else
|
267
|
+
cmd_portfwd_help
|
268
268
|
end
|
269
269
|
end
|
270
270
|
|
271
|
+
def cmd_portfwd_help
|
272
|
+
print_line "Usage: portfwd [-h] [add / delete / list] [args]"
|
273
|
+
print_line
|
274
|
+
print @@portfwd_opts.usage
|
275
|
+
end
|
276
|
+
|
271
277
|
protected
|
272
278
|
|
273
279
|
#
|
@@ -457,11 +457,13 @@ class Console::CommandDispatcher::Stdapi::Sys
|
|
457
457
|
#
|
458
458
|
def cmd_sysinfo(*args)
|
459
459
|
info = client.sys.config.sysinfo
|
460
|
+
width = 0
|
461
|
+
info.keys.each { |k| width = k.length if k.length > width }
|
460
462
|
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
print_line("
|
463
|
+
info.each_pair do |key, value|
|
464
|
+
print_line("#{key.ljust(width+1)}: #{value}") if value
|
465
|
+
end
|
466
|
+
print_line("#{"Meterpreter".ljust(width+1)}: #{client.platform}")
|
465
467
|
|
466
468
|
return true
|
467
469
|
end
|
data/lib/rex/proto.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: server.rb
|
1
|
+
# $Id: server.rb 11745 2011-02-12 22:25:02Z jduck $
|
2
2
|
|
3
3
|
require 'rex/socket'
|
4
4
|
require 'rex/proto/dhcp'
|
@@ -212,8 +212,10 @@ protected
|
|
212
212
|
|
213
213
|
# options parsing loop
|
214
214
|
spot = 240
|
215
|
-
while (spot < buf.length - 3
|
215
|
+
while (spot < buf.length - 3)
|
216
216
|
optionType = buf[spot,1].unpack("C").first
|
217
|
+
break if optionType == 0xff
|
218
|
+
|
217
219
|
optionLen = buf[spot + 1,1].unpack("C").first
|
218
220
|
optionValue = buf[(spot + 2)..(spot + optionLen + 1)]
|
219
221
|
spot = spot + optionLen + 2
|
@@ -166,9 +166,8 @@ class Packet
|
|
166
166
|
# Converts the packet to a string.
|
167
167
|
#
|
168
168
|
def to_s
|
169
|
-
|
170
|
-
|
171
|
-
|
169
|
+
content = self.body.dup
|
170
|
+
|
172
171
|
# Update the content length field in the header with the body length.
|
173
172
|
if (content)
|
174
173
|
if !self.compress.nil?
|
@@ -267,7 +266,7 @@ protected
|
|
267
266
|
def parse_header
|
268
267
|
|
269
268
|
head,data = self.bufq.split(/\r?\n\r?\n/, 2)
|
270
|
-
|
269
|
+
|
271
270
|
return if not data
|
272
271
|
|
273
272
|
self.headers.from_s(head)
|
@@ -339,7 +338,7 @@ protected
|
|
339
338
|
|
340
339
|
# If we didn't get a newline, then this might not be the full
|
341
340
|
# length, go back and get more.
|
342
|
-
# e.g.
|
341
|
+
# e.g.
|
343
342
|
# first packet: "200"
|
344
343
|
# second packet: "0\r\n\r\n<html>..."
|
345
344
|
if not bufq.index("\n")
|
@@ -350,7 +349,7 @@ protected
|
|
350
349
|
clen = self.bufq.slice!(/^[a-fA-F0-9]+\r?\n/)
|
351
350
|
|
352
351
|
clen.rstrip! if (clen)
|
353
|
-
|
352
|
+
|
354
353
|
# if we happen to fall upon the end of the buffer for the next chunk len and have no data left, go get some more...
|
355
354
|
if clen.nil? and self.bufq.length == 0
|
356
355
|
return
|
@@ -0,0 +1,177 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'test/unit'
|
3
|
+
require 'rex/proto/ntlm'
|
4
|
+
require 'rex/socket'
|
5
|
+
|
6
|
+
class ConnectionTest < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
@user = "admin"
|
9
|
+
@pass = "1234"
|
10
|
+
@domain = ""
|
11
|
+
@host = "192.168.145.161"
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_socket_connectivity
|
15
|
+
assert_nothing_raised do
|
16
|
+
socket = Rex::Socket.create_tcp(
|
17
|
+
'PeerHost' => @host,
|
18
|
+
'PeerPort' => 80
|
19
|
+
)
|
20
|
+
assert_kind_of Socket, socket
|
21
|
+
assert !socket.closed?
|
22
|
+
socket.close
|
23
|
+
assert socket.closed?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def http_message(msg)
|
28
|
+
get_req = "GET / HTTP/1.1\r\n"
|
29
|
+
get_req += "Host: #{@host}\r\n"
|
30
|
+
get_req += "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)\r\n"
|
31
|
+
get_req += "Authorization: NTLM #{msg.encode64}\r\n"
|
32
|
+
get_req += "Content-type: application/x-www-form-urlencoded\r\n"
|
33
|
+
get_req += "Content-Length: 0\r\n"
|
34
|
+
get_req += "\r\n"
|
35
|
+
end
|
36
|
+
|
37
|
+
def client_auth(pw)
|
38
|
+
msg_1 = Rex::Proto::NTLM::Message::Type1.new
|
39
|
+
get_req = http_message(msg_1)
|
40
|
+
socket = Rex::Socket.create_tcp(
|
41
|
+
'PeerHost' => @host,
|
42
|
+
'PeerPort' => 80
|
43
|
+
)
|
44
|
+
socket.put get_req
|
45
|
+
res = socket.get(3)
|
46
|
+
assert res =~ /WWW-Authenticate: NTLM TlRM/
|
47
|
+
res_ntlm = res.match(/WWW-Authenticate: NTLM ([A-Z0-9\x2b\x2f=]+)/i)[1]
|
48
|
+
assert_operator res_ntlm.size, :>=, 24
|
49
|
+
msg_2 = Rex::Proto::NTLM::Message.decode64(res_ntlm)
|
50
|
+
assert msg_2
|
51
|
+
msg_3 = msg_2.response({:user => @user, :password => pw}, {:ntlmv2 => true})
|
52
|
+
assert msg_3
|
53
|
+
auth_req = http_message(msg_3)
|
54
|
+
socket.put auth_req
|
55
|
+
auth_res = socket.get(3)
|
56
|
+
socket.close
|
57
|
+
return auth_res
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_client_auth_success
|
61
|
+
assert_equal client_auth(@pass)[0,12], "HTTP/1.1 200"
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_client_auth_fail
|
65
|
+
assert_not_equal client_auth("badpass")[0,12], "HTTP/1.1 200"
|
66
|
+
assert_equal client_auth("badpass")[0,12], "HTTP/1.1 401"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# FunctionTest by Minero Aoki
|
71
|
+
|
72
|
+
class FunctionTest < Test::Unit::TestCase #:nodoc:
|
73
|
+
def setup
|
74
|
+
@passwd = "SecREt01"
|
75
|
+
@user = "user"
|
76
|
+
@domain = "domain"
|
77
|
+
@challenge = ["0123456789abcdef"].pack("H*")
|
78
|
+
@client_ch = ["ffffff0011223344"].pack("H*")
|
79
|
+
@timestamp = 1055844000
|
80
|
+
@trgt_info = [
|
81
|
+
"02000c0044004f004d00410049004e00" +
|
82
|
+
"01000c00530045005200560045005200" +
|
83
|
+
"0400140064006f006d00610069006e00" +
|
84
|
+
"2e0063006f006d000300220073006500" +
|
85
|
+
"72007600650072002e0064006f006d00" +
|
86
|
+
"610069006e002e0063006f006d000000" +
|
87
|
+
"0000"
|
88
|
+
].pack("H*")
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_lm_hash
|
92
|
+
ahash = ["ff3750bcc2b22412c2265b23734e0dac"].pack("H*")
|
93
|
+
assert_equal ahash, Rex::Proto::NTLM::Crypt::lm_hash(@passwd)
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_ntlm_hash
|
97
|
+
ahash = ["cd06ca7c7e10c99b1d33b7485a2ed808"].pack("H*")
|
98
|
+
assert_equal ahash, Rex::Proto::NTLM::Crypt::ntlm_hash(@passwd)
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_ntlmv2_hash
|
102
|
+
ahash = ["04b8e0ba74289cc540826bab1dee63ae"].pack("H*")
|
103
|
+
assert_equal ahash, Rex::Proto::NTLM::Crypt::ntlmv2_hash(@user, @passwd, @domain)
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_lm_response
|
107
|
+
ares = ["c337cd5cbd44fc9782a667af6d427c6de67c20c2d3e77c56"].pack("H*")
|
108
|
+
assert_equal ares, Rex::Proto::NTLM::Crypt::lm_response(
|
109
|
+
{
|
110
|
+
:lm_hash => Rex::Proto::NTLM::Crypt::lm_hash(@passwd),
|
111
|
+
:challenge => @challenge
|
112
|
+
}
|
113
|
+
)
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_ntlm_response
|
117
|
+
ares = ["25a98c1c31e81847466b29b2df4680f39958fb8c213a9cc6"].pack("H*")
|
118
|
+
ntlm_hash = Rex::Proto::NTLM::Crypt::ntlm_hash(@passwd)
|
119
|
+
assert_equal ares, Rex::Proto::NTLM::Crypt::ntlm_response(
|
120
|
+
{
|
121
|
+
:ntlm_hash => ntlm_hash,
|
122
|
+
:challenge => @challenge
|
123
|
+
}
|
124
|
+
)
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_lmv2_response
|
128
|
+
ares = ["d6e6152ea25d03b7c6ba6629c2d6aaf0ffffff0011223344"].pack("H*")
|
129
|
+
assert_equal ares, Rex::Proto::NTLM::Crypt::lmv2_response(
|
130
|
+
{
|
131
|
+
:ntlmv2_hash => Rex::Proto::NTLM::Crypt::ntlmv2_hash(@user, @passwd, @domain),
|
132
|
+
:challenge => @challenge
|
133
|
+
},
|
134
|
+
{ :client_challenge => @client_ch }
|
135
|
+
)
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_ntlmv2_response
|
139
|
+
ares = [
|
140
|
+
"cbabbca713eb795d04c97abc01ee4983" +
|
141
|
+
"01010000000000000090d336b734c301" +
|
142
|
+
"ffffff00112233440000000002000c00" +
|
143
|
+
"44004f004d00410049004e0001000c00" +
|
144
|
+
"53004500520056004500520004001400" +
|
145
|
+
"64006f006d00610069006e002e006300" +
|
146
|
+
"6f006d00030022007300650072007600" +
|
147
|
+
"650072002e0064006f006d0061006900" +
|
148
|
+
"6e002e0063006f006d00000000000000" +
|
149
|
+
"0000"
|
150
|
+
].pack("H*")
|
151
|
+
assert_equal ares, Rex::Proto::NTLM::Crypt::ntlmv2_response(
|
152
|
+
{
|
153
|
+
:ntlmv2_hash => Rex::Proto::NTLM::Crypt::ntlmv2_hash(@user, @passwd, @domain),
|
154
|
+
:challenge => @challenge,
|
155
|
+
:target_info => @trgt_info
|
156
|
+
},
|
157
|
+
{
|
158
|
+
:timestamp => @timestamp,
|
159
|
+
:client_challenge => @client_ch
|
160
|
+
}
|
161
|
+
)
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_ntlm2_session
|
165
|
+
acha = ["ffffff001122334400000000000000000000000000000000"].pack("H*")
|
166
|
+
ares = ["10d550832d12b2ccb79d5ad1f4eed3df82aca4c3681dd455"].pack("H*")
|
167
|
+
session = Rex::Proto::NTLM::Crypt::ntlm2_session(
|
168
|
+
{
|
169
|
+
:ntlm_hash => Rex::Proto::NTLM::Crypt::ntlm_hash(@passwd),
|
170
|
+
:challenge => @challenge
|
171
|
+
},
|
172
|
+
{ :client_challenge => @client_ch }
|
173
|
+
)
|
174
|
+
assert_equal acha, session[0]
|
175
|
+
assert_equal ares, session[1]
|
176
|
+
end
|
177
|
+
end
|