librex 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/README.md +3 -5
  2. data/Rakefile +26 -0
  3. data/lib/rex/compat.rb +1 -1
  4. data/lib/rex/exploitation/javascriptosdetect.rb +125 -62
  5. data/lib/rex/file.rb +15 -0
  6. data/lib/rex/io/stream.rb +1 -1
  7. data/lib/rex/parser/nmap_xml.rb +6 -0
  8. data/lib/rex/poly/block.rb +9 -0
  9. data/lib/rex/post/meterpreter/client.rb +0 -8
  10. data/lib/rex/post/meterpreter/extensions/priv/priv.rb +6 -0
  11. data/lib/rex/post/meterpreter/extensions/stdapi/fs/file.rb +1 -1
  12. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_advapi32.rb +49 -35
  13. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/def/def_netapi32.rb +26 -0
  14. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/railgun.rb +9 -2
  15. data/lib/rex/post/meterpreter/extensions/stdapi/railgun/util.rb +630 -0
  16. data/lib/rex/post/meterpreter/packet.rb +3 -1
  17. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/core.rb +143 -57
  18. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/fs.rb +6 -0
  19. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/net.rb +9 -3
  20. data/lib/rex/post/meterpreter/ui/console/command_dispatcher/stdapi/sys.rb +6 -4
  21. data/lib/rex/proto.rb +1 -0
  22. data/lib/rex/proto/dhcp/server.rb +4 -2
  23. data/lib/rex/proto/http/packet.rb +5 -6
  24. data/lib/rex/proto/ntlm.rb +7 -0
  25. data/lib/rex/proto/ntlm.rb.ut.rb +177 -0
  26. data/lib/rex/proto/ntlm/base.rb +326 -0
  27. data/lib/rex/proto/ntlm/constants.rb +74 -0
  28. data/lib/rex/proto/ntlm/crypt.rb +340 -0
  29. data/lib/rex/proto/ntlm/exceptions.rb +9 -0
  30. data/lib/rex/proto/ntlm/message.rb +533 -0
  31. data/lib/rex/proto/ntlm/utils.rb +358 -0
  32. data/lib/rex/proto/smb/client.rb +548 -86
  33. data/lib/rex/proto/smb/client.rb.ut.rb +4 -4
  34. data/lib/rex/proto/smb/constants.rb +7 -24
  35. data/lib/rex/proto/smb/crypt.rb +12 -71
  36. data/lib/rex/proto/smb/exceptions.rb +12 -0
  37. data/lib/rex/proto/smb/simpleclient.rb +17 -5
  38. data/lib/rex/proto/smb/utils.rb +3 -460
  39. data/lib/rex/proto/tftp/server.rb +2 -2
  40. data/lib/rex/script/base.rb +2 -2
  41. data/lib/rex/socket.rb +12 -0
  42. data/lib/rex/socket.rb.ut.rb +31 -10
  43. data/lib/rex/socket/ssl_tcp_server.rb.ut.rb +15 -5
  44. data/lib/rex/text.rb +55 -4
  45. data/lib/rex/ui/output.rb +0 -2
  46. data/lib/rex/ui/text/dispatcher_shell.rb +95 -10
  47. data/lib/rex/ui/text/output/buffer.rb +0 -4
  48. data/lib/rex/ui/text/shell.rb +8 -0
  49. data/lib/rex/ui/text/table.rb +21 -1
  50. metadata +15 -19
  51. 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} meta-type=#{meta} #{self.class.to_s =~ /Packet/ ? "tlvs=#{@tlvs.inspect}" : "value=#{val}"} >"
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
- print_line(
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
- # the rest of the arguments get passed in through the binding
348
- client.execute_script(args.shift, args)
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::ScriptBase,
362
- ::Msf::Sessions::Meterpreter::UserScriptBase
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!(/\.rb$/, '') }
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
- return items
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
- path = "post/meterpreter/ui/console/command_dispatcher/#{mod}.rb"
565
-
566
- if ((klass = CommDispatcher.check_hash(path)) == nil)
567
- clirb = File.join(Rex::Root, path)
568
- old = CommDispatcher.constants
569
-
570
- if (require(clirb))
571
- new = CommDispatcher.constants
572
- diff = new - old
573
-
574
- if (diff.empty? == true)
575
- print_error("Failed to load client portion of #{mod}.")
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
- print_error("Failed to load client script file: #{clirb}")
584
- return false
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
@@ -428,6 +428,12 @@ class Console::CommandDispatcher::Stdapi::Fs
428
428
  return true
429
429
  end
430
430
 
431
+ def cmd_upload_tabs(str, words)
432
+ return [] if words.length > 1
433
+
434
+ tab_complete_filenames(str, words)
435
+ end
436
+
431
437
  end
432
438
 
433
439
  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
- print(
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
- print_line("Computer: " + info['Computer'])
462
- print_line("OS : " + info['OS'])
463
- print_line("Arch : " + info['Architecture']) if info['Architecture']
464
- print_line("Language: " + info['System Language']) if info['System Language']
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
@@ -1,5 +1,6 @@
1
1
  require 'rex/proto/http'
2
2
  require 'rex/proto/smb'
3
+ require 'rex/proto/ntlm'
3
4
  require 'rex/proto/dcerpc'
4
5
  require 'rex/proto/drda'
5
6
 
@@ -1,4 +1,4 @@
1
- # $Id: server.rb 11003 2010-11-12 06:19:49Z hdm $
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 && buf[spot] != 0xff)
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
- # Duplicate and make sure this is 8BIT safe for Ruby 1.9
170
- content = self.body.unpack("C*").pack("C*")
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,7 @@
1
+ require 'rex/proto/ntlm/constants'
2
+ require 'rex/proto/ntlm/exceptions'
3
+ require 'rex/proto/ntlm/crypt'
4
+ require 'rex/proto/ntlm/utils'
5
+ require 'rex/proto/ntlm/base'
6
+ require 'rex/proto/ntlm/message'
7
+
@@ -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