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.
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