librex 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|