Browse Source

Various merge resolutions from master <- staging

* --ask option ported to new location
* --version option now works
* MSF version updated
* All specs passing
Samuel Huckins 5 years ago
parent
commit
149c3ecc63
No account linked to committer's email address
100 changed files with 11637 additions and 2917 deletions
  1. 3
    0
      .gitignore
  2. 1
    1
      .rubocop.yml
  3. 2
    0
      .yardopts
  4. 21
    34
      Gemfile
  5. 0
    2
      Gemfile.local.example
  6. 133
    46
      Gemfile.lock
  7. 8
    78
      Rakefile
  8. 23
    0
      app/concerns/metasploit/credential/core/to_credential.rb
  9. 2
    0
      app/validators/metasploit.rb
  10. 16
    0
      app/validators/metasploit/framework/executable_path_validator.rb
  11. 16
    0
      app/validators/metasploit/framework/file_path_validator.rb
  12. 58
    0
      config/application.rb
  13. 39
    0
      config/boot.rb
  14. 5
    0
      config/environment.rb
  15. 4724
    0
      data/john/wordlists/common_roots.txt
  16. 0
    0
      db/migrate/.git-keep
  17. 118
    1
      db/schema.rb
  18. 4
    0
      lib/fastlib.rb
  19. 27
    25
      lib/metasploit/framework.rb
  20. 323
    0
      lib/metasploit/framework/afp/client.rb
  21. 7
    0
      lib/metasploit/framework/api.rb
  22. 16
    0
      lib/metasploit/framework/api/version.rb
  23. 26
    0
      lib/metasploit/framework/command.rb
  24. 113
    0
      lib/metasploit/framework/command/base.rb
  25. 64
    0
      lib/metasploit/framework/command/console.rb
  26. 74
    0
      lib/metasploit/framework/common_engine.rb
  27. 74
    0
      lib/metasploit/framework/community_string_collection.rb
  28. 7
    0
      lib/metasploit/framework/core.rb
  29. 19
    0
      lib/metasploit/framework/core/version.rb
  30. 105
    0
      lib/metasploit/framework/credential.rb
  31. 148
    0
      lib/metasploit/framework/credential_collection.rb
  32. 1
    1
      lib/metasploit/framework/database.rb
  33. 19
    0
      lib/metasploit/framework/engine.rb
  34. 276
    0
      lib/metasploit/framework/ftp/client.rb
  35. 272
    0
      lib/metasploit/framework/jtr/cracker.rb
  36. 20
    0
      lib/metasploit/framework/jtr/invalid_wordlist.rb
  37. 429
    0
      lib/metasploit/framework/jtr/wordlist.rb
  38. 47
    0
      lib/metasploit/framework/login_scanner.rb
  39. 50
    0
      lib/metasploit/framework/login_scanner/afp.rb
  40. 67
    0
      lib/metasploit/framework/login_scanner/axis2.rb
  41. 222
    0
      lib/metasploit/framework/login_scanner/base.rb
  42. 134
    0
      lib/metasploit/framework/login_scanner/db2.rb
  43. 76
    0
      lib/metasploit/framework/login_scanner/ftp.rb
  44. 123
    0
      lib/metasploit/framework/login_scanner/http.rb
  45. 22
    0
      lib/metasploit/framework/login_scanner/invalid.rb
  46. 74
    0
      lib/metasploit/framework/login_scanner/mssql.rb
  47. 91
    0
      lib/metasploit/framework/login_scanner/mysql.rb
  48. 61
    0
      lib/metasploit/framework/login_scanner/ntlm.rb
  49. 87
    0
      lib/metasploit/framework/login_scanner/pop3.rb
  50. 79
    0
      lib/metasploit/framework/login_scanner/postgres.rb
  51. 54
    0
      lib/metasploit/framework/login_scanner/result.rb
  52. 64
    0
      lib/metasploit/framework/login_scanner/rex_socket.rb
  53. 265
    0
      lib/metasploit/framework/login_scanner/smb.rb
  54. 106
    0
      lib/metasploit/framework/login_scanner/snmp.rb
  55. 134
    0
      lib/metasploit/framework/login_scanner/ssh.rb
  56. 113
    0
      lib/metasploit/framework/login_scanner/telnet.rb
  57. 28
    0
      lib/metasploit/framework/login_scanner/tomcat.rb
  58. 122
    0
      lib/metasploit/framework/login_scanner/vnc.rb
  59. 52
    0
      lib/metasploit/framework/login_scanner/winrm.rb
  60. 728
    0
      lib/metasploit/framework/mssql/client.rb
  61. 27
    0
      lib/metasploit/framework/parsed_options.rb
  62. 185
    0
      lib/metasploit/framework/parsed_options/base.rb
  63. 79
    0
      lib/metasploit/framework/parsed_options/console.rb
  64. 92
    0
      lib/metasploit/framework/require.rb
  65. 186
    0
      lib/metasploit/framework/tcp/client.rb
  66. 219
    0
      lib/metasploit/framework/telnet/client.rb
  67. 13
    0
      lib/metasploit/framework/version.rb
  68. 15
    3
      lib/msf/base/config.rb
  69. 23
    3
      lib/msf/base/simple/framework/module_paths.rb
  70. 52
    404
      lib/msf/core/auxiliary/jtr.rb
  71. 4
    0
      lib/msf/core/auxiliary/login.rb
  72. 0
    1
      lib/msf/core/auxiliary/mixins.rb
  73. 20
    2
      lib/msf/core/auxiliary/report.rb
  74. 134
    145
      lib/msf/core/db.rb
  75. 20
    209
      lib/msf/core/db_export.rb
  76. 105
    67
      lib/msf/core/db_manager.rb
  77. 75
    65
      lib/msf/core/db_manager/import_msf_xml.rb
  78. 1
    0
      lib/msf/core/exploit/cmdstager.rb
  79. 5
    12
      lib/msf/core/framework.rb
  80. 7
    4
      lib/msf/core/modules/namespace.rb
  81. 13
    0
      lib/msf/core/post.rb
  82. 53
    64
      lib/msf/core/rpc/v10/rpc_db.rb
  83. 6
    1
      lib/msf/core/thread_manager.rb
  84. 0
    12
      lib/msf/sanity.rb
  85. 1
    1
      lib/msf/ui/console/command_dispatcher/core.rb
  86. 223
    170
      lib/msf/ui/console/command_dispatcher/db.rb
  87. 49
    39
      lib/msf/ui/console/driver.rb
  88. 12
    25
      lib/msfenv.rb
  89. 4
    4
      lib/net/ssh/key_factory.rb
  90. 11
    3
      lib/rex/proto/smb/exceptions.rb
  91. 4
    4
      lib/rex/ui/text/table.rb
  92. 0
    73
      lib/tasks/database.rake
  93. 7
    0
      lib/tasks/databases.rake
  94. 0
    21
      lib/tasks/rails.rake
  95. 0
    1
      lib/zip.rb
  96. 0
    1146
      lib/zip/ChangeLog
  97. 0
    162
      lib/zip/NEWS
  98. 0
    72
      lib/zip/README
  99. 0
    16
      lib/zip/TODO
  100. 0
    0
      lib/zip/ioextras.rb

+ 3
- 0
.gitignore View File

@@ -48,6 +48,9 @@ tags
48 48
 *.opensdf
49 49
 *.user
50 50
 
51
+# Rails log directory
52
+/log
53
+
51 54
 # ignore release/debug folders for exploits
52 55
 external/source/exploits/**/Debug
53 56
 external/source/exploits/**/Release

+ 1
- 1
.rubocop.yml View File

@@ -53,4 +53,4 @@ Style/StringLiterals:
53 53
 
54 54
 Style/WordArray:
55 55
   Enabled: false
56
-  Description: 'Metasploit prefers consistent use of []'
56
+  Description: 'Metasploit prefers consistent use of []'

+ 2
- 0
.yardopts View File

@@ -3,6 +3,8 @@
3 3
 --exclude \.ut\.rb/
4 4
 --exclude \.ts\.rb/
5 5
 --files CONTRIBUTING.md,COPYING,HACKING,LICENSE
6
+app/**/*.rb
6 7
 lib/msf/**/*.rb
8
+lib/metasploit/**/*.rb
7 9
 lib/rex/**/*.rb
8 10
 plugins/**/*.rb

+ 21
- 34
Gemfile View File

@@ -1,46 +1,26 @@
1 1
 source 'https://rubygems.org'
2
-
3
-# Need 3+ for ActiveSupport::Concern
4
-gem 'activesupport', '>= 3.0.0', '< 4.0.0'
5
-# Needed for some admin modules (cfme_manageiq_evm_pass_reset.rb)
6
-gem 'bcrypt'
7
-# Needed for some admin modules (scrutinizer_add_user.rb)
8
-gem 'json'
9
-# Needed for Meterpreter on Windows, soon others.
10
-gem 'meterpreter_bins', '0.0.6'
11
-# Needed by msfgui and other rpc components
12
-gem 'msgpack'
13
-# Needed by anemone crawler
14
-gem 'nokogiri'
15
-# Needed by db.rb and Msf::Exploit::Capture
16
-gem 'packetfu', '1.1.9'
17
-# Needed by JSObfu
18
-gem 'rkelly-remix', '0.0.6'
19
-# Needed by anemone crawler
20
-gem 'robots'
21
-# Needed for some post modules
22
-gem 'sqlite3'
2
+# Add default group gems to `metasploit-framework.gemspec`:
3
+#   spec.add_runtime_dependency '<name>', [<version requirements>]
4
+gemspec
23 5
 
24 6
 group :db do
25 7
   # Needed for Msf::DbManager
26 8
   gem 'activerecord', '>= 3.0.0', '< 4.0.0'
9
+  # Metasploit::Credential database models
10
+  gem 'metasploit-credential', '>= 0.8.6', '< 0.9'
27 11
   # Database models shared between framework and Pro.
28
-  gem 'metasploit_data_models', '0.17.0'
12
+  gem 'metasploit_data_models', '~> 0.19'
29 13
   # Needed for module caching in Mdm::ModuleDetails
30 14
   gem 'pg', '>= 0.11'
31 15
 end
32 16
 
33
-group :pcap do
34
-  gem 'network_interface', '~> 0.0.1'
35
-  # For sniffer and raw socket modules
36
-  gem 'pcaprub'
37
-end
38
-
39 17
 group :development do
40 18
   # Markdown formatting for yard
41 19
   gem 'redcarpet'
42 20
   # generating documentation
43 21
   gem 'yard'
22
+  # for development and testing purposes
23
+  gem 'pry'
44 24
 end
45 25
 
46 26
 group :development, :test do
@@ -48,19 +28,26 @@ group :development, :test do
48 28
   # Version 4.1.0 or newer is needed to support generate calls without the
49 29
   # 'FactoryGirl.' in factory definitions syntax.
50 30
   gem 'factory_girl', '>= 4.1.0'
31
+  # automatically include factories from spec/factories
32
+  gem 'factory_girl_rails'
51 33
   # Make rspec output shorter and more useful
52 34
   gem 'fivemat', '1.2.1'
53 35
   # running documentation generation tasks and rspec tasks
54 36
   gem 'rake', '>= 10.0.0'
37
+  # testing framework
38
+  gem 'rspec', '>= 2.12', '< 3.0.0'
39
+  # Define `rake spec`.  Must be in development AND test so that its available by default as a rake test when the
40
+  # environment is development
41
+  gem 'rspec-rails' , '>= 2.12', '< 3.0.0'
42
+end
43
+
44
+group :pcap do
45
+  gem 'network_interface', '~> 0.0.1'
46
+  # For sniffer and raw socket modules
47
+  gem 'pcaprub'
55 48
 end
56 49
 
57 50
 group :test do
58
-  # Removes records from database created during tests.  Can't use rspec-rails'
59
-  # transactional fixtures because multiple connections are in use so
60
-  # transactions won't work.
61
-  gem 'database_cleaner'
62
-  # testing framework
63
-  gem 'rspec', '>= 2.12'
64 51
   gem 'shoulda-matchers'
65 52
   # code coverage for tests
66 53
   # any version newer than 0.5.4 gives an Encoding error when trying to read the source files.

+ 0
- 2
Gemfile.local.example View File

@@ -27,8 +27,6 @@ end
27 27
 
28 28
 # Create a custom group
29 29
 group :local do
30
-  # Use pry to help view and interact with objects in the framework
31
-  gem 'pry', '~> 0.9'
32 30
   # Use pry-debugger to step through code during development
33 31
   gem 'pry-debugger', '~> 0.2'
34 32
   # Add the lab gem so that the 'lab' plugin will work again

+ 133
- 46
Gemfile.lock View File

@@ -1,90 +1,177 @@
1
+PATH
2
+  remote: .
3
+  specs:
4
+    metasploit-framework (4.10.1.pre.dev)
5
+      actionpack (< 4.0.0)
6
+      activesupport (>= 3.0.0, < 4.0.0)
7
+      bcrypt
8
+      json
9
+      metasploit-model (~> 0.26.1)
10
+      meterpreter_bins (= 0.0.6)
11
+      msgpack
12
+      nokogiri
13
+      packetfu (= 1.1.9)
14
+      railties
15
+      rkelly-remix (= 0.0.6)
16
+      robots
17
+      rubyzip (~> 1.1)
18
+      sqlite3
19
+      tzinfo
20
+
1 21
 GEM
2 22
   remote: https://rubygems.org/
3 23
   specs:
4
-    activemodel (3.2.14)
5
-      activesupport (= 3.2.14)
24
+    actionpack (3.2.19)
25
+      activemodel (= 3.2.19)
26
+      activesupport (= 3.2.19)
6 27
       builder (~> 3.0.0)
7
-    activerecord (3.2.14)
8
-      activemodel (= 3.2.14)
9
-      activesupport (= 3.2.14)
28
+      erubis (~> 2.7.0)
29
+      journey (~> 1.0.4)
30
+      rack (~> 1.4.5)
31
+      rack-cache (~> 1.2)
32
+      rack-test (~> 0.6.1)
33
+      sprockets (~> 2.2.1)
34
+    activemodel (3.2.19)
35
+      activesupport (= 3.2.19)
36
+      builder (~> 3.0.0)
37
+    activerecord (3.2.19)
38
+      activemodel (= 3.2.19)
39
+      activesupport (= 3.2.19)
10 40
       arel (~> 3.0.2)
11 41
       tzinfo (~> 0.3.29)
12
-    activesupport (3.2.14)
42
+    activesupport (3.2.19)
13 43
       i18n (~> 0.6, >= 0.6.4)
14 44
       multi_json (~> 1.0)
15
-    arel (3.0.2)
45
+    arel (3.0.3)
46
+    arel-helpers (2.0.1)
47
+      activerecord (>= 3.1.0, < 5)
16 48
     bcrypt (3.1.7)
17 49
     builder (3.0.4)
18
-    database_cleaner (1.1.1)
19
-    diff-lcs (1.2.4)
20
-    factory_girl (4.2.0)
50
+    coderay (1.1.0)
51
+    diff-lcs (1.2.5)
52
+    erubis (2.7.0)
53
+    factory_girl (4.4.0)
21 54
       activesupport (>= 3.0.0)
55
+    factory_girl_rails (4.4.1)
56
+      factory_girl (~> 4.4.0)
57
+      railties (>= 3.0.0)
22 58
     fivemat (1.2.1)
23
-    i18n (0.6.5)
24
-    json (1.8.0)
25
-    metasploit_data_models (0.17.0)
26
-      activerecord (>= 3.2.13)
59
+    hike (1.2.3)
60
+    i18n (0.6.11)
61
+    journey (1.0.4)
62
+    json (1.8.1)
63
+    metasploit-concern (0.1.1)
64
+      activesupport (~> 3.0, >= 3.0.0)
65
+    metasploit-credential (0.8.6)
66
+      metasploit-concern (~> 0.1.0)
67
+      metasploit-model (~> 0.26.1)
68
+      metasploit_data_models (~> 0.19.4)
69
+      pg
70
+      rubyntlm
71
+      rubyzip (~> 1.1)
72
+    metasploit-model (0.26.1)
27 73
       activesupport
74
+    metasploit_data_models (0.19.4)
75
+      activerecord (>= 3.2.13, < 4.0.0)
76
+      activesupport
77
+      arel-helpers
78
+      metasploit-concern (~> 0.1.0)
79
+      metasploit-model (~> 0.26.1)
28 80
       pg
29 81
     meterpreter_bins (0.0.6)
30
-    mini_portile (0.5.1)
31
-    msgpack (0.5.5)
82
+    method_source (0.8.2)
83
+    mini_portile (0.6.0)
84
+    msgpack (0.5.8)
32 85
     multi_json (1.0.4)
33 86
     network_interface (0.0.1)
34
-    nokogiri (1.6.0)
35
-      mini_portile (~> 0.5.0)
87
+    nokogiri (1.6.3.1)
88
+      mini_portile (= 0.6.0)
36 89
     packetfu (1.1.9)
37 90
     pcaprub (0.11.3)
38
-    pg (0.16.0)
39
-    rake (10.1.0)
40
-    redcarpet (3.0.0)
91
+    pg (0.17.1)
92
+    pry (0.10.0)
93
+      coderay (~> 1.1.0)
94
+      method_source (~> 0.8.1)
95
+      slop (~> 3.4)
96
+    rack (1.4.5)
97
+    rack-cache (1.2)
98
+      rack (>= 0.4)
99
+    rack-ssl (1.3.4)
100
+      rack
101
+    rack-test (0.6.2)
102
+      rack (>= 1.0)
103
+    railties (3.2.19)
104
+      actionpack (= 3.2.19)
105
+      activesupport (= 3.2.19)
106
+      rack-ssl (~> 1.3.2)
107
+      rake (>= 0.8.7)
108
+      rdoc (~> 3.4)
109
+      thor (>= 0.14.6, < 2.0)
110
+    rake (10.3.2)
111
+    rdoc (3.12.2)
112
+      json (~> 1.4)
113
+    redcarpet (3.1.2)
41 114
     rkelly-remix (0.0.6)
42 115
     robots (0.10.1)
43
-    rspec (2.14.1)
44
-      rspec-core (~> 2.14.0)
45
-      rspec-expectations (~> 2.14.0)
46
-      rspec-mocks (~> 2.14.0)
47
-    rspec-core (2.14.5)
48
-    rspec-expectations (2.14.2)
116
+    rspec (2.99.0)
117
+      rspec-core (~> 2.99.0)
118
+      rspec-expectations (~> 2.99.0)
119
+      rspec-mocks (~> 2.99.0)
120
+    rspec-collection_matchers (1.0.0)
121
+      rspec-expectations (>= 2.99.0.beta1)
122
+    rspec-core (2.99.1)
123
+    rspec-expectations (2.99.2)
49 124
       diff-lcs (>= 1.1.3, < 2.0)
50
-    rspec-mocks (2.14.3)
51
-    shoulda-matchers (2.3.0)
52
-      activesupport (>= 3.0.0)
125
+    rspec-mocks (2.99.2)
126
+    rspec-rails (2.99.0)
127
+      actionpack (>= 3.0)
128
+      activemodel (>= 3.0)
129
+      activesupport (>= 3.0)
130
+      railties (>= 3.0)
131
+      rspec-collection_matchers
132
+      rspec-core (~> 2.99.0)
133
+      rspec-expectations (~> 2.99.0)
134
+      rspec-mocks (~> 2.99.0)
135
+    rubyntlm (0.4.0)
136
+    rubyzip (1.1.6)
137
+    shoulda-matchers (2.6.2)
53 138
     simplecov (0.5.4)
54 139
       multi_json (~> 1.0.3)
55 140
       simplecov-html (~> 0.5.3)
56 141
     simplecov-html (0.5.3)
142
+    slop (3.6.0)
143
+    sprockets (2.2.2)
144
+      hike (~> 1.2)
145
+      multi_json (~> 1.0)
146
+      rack (~> 1.0)
147
+      tilt (~> 1.1, != 1.3.0)
57 148
     sqlite3 (1.3.9)
58
-    timecop (0.6.3)
59
-    tzinfo (0.3.37)
60
-    yard (0.8.7)
149
+    thor (0.19.1)
150
+    tilt (1.4.1)
151
+    timecop (0.7.1)
152
+    tzinfo (0.3.40)
153
+    yard (0.8.7.4)
61 154
 
62 155
 PLATFORMS
63 156
   ruby
64 157
 
65 158
 DEPENDENCIES
66 159
   activerecord (>= 3.0.0, < 4.0.0)
67
-  activesupport (>= 3.0.0, < 4.0.0)
68
-  bcrypt
69
-  database_cleaner
70 160
   factory_girl (>= 4.1.0)
161
+  factory_girl_rails
71 162
   fivemat (= 1.2.1)
72
-  json
73
-  metasploit_data_models (= 0.17.0)
74
-  meterpreter_bins (= 0.0.6)
75
-  msgpack
163
+  metasploit-credential (>= 0.8.6, < 0.9)
164
+  metasploit-framework!
165
+  metasploit_data_models (~> 0.19)
76 166
   network_interface (~> 0.0.1)
77
-  nokogiri
78
-  packetfu (= 1.1.9)
79 167
   pcaprub
80 168
   pg (>= 0.11)
169
+  pry
81 170
   rake (>= 10.0.0)
82 171
   redcarpet
83
-  rkelly-remix (= 0.0.6)
84
-  robots
85
-  rspec (>= 2.12)
172
+  rspec (>= 2.12, < 3.0.0)
173
+  rspec-rails (>= 2.12, < 3.0.0)
86 174
   shoulda-matchers
87 175
   simplecov (= 0.5.4)
88
-  sqlite3
89 176
   timecop
90 177
   yard

+ 8
- 78
Rakefile View File

@@ -1,81 +1,11 @@
1
-require 'bundler/setup'
2
-
3
-pathname = Pathname.new(__FILE__)
4
-root = pathname.parent
5
-
6
-# add metasploit-framework/lib to load paths so rake files can just require
7
-# files normally without having to use __FILE__ and recalculating root and the
8
-# path to lib
9
-lib_pathname = root.join('lib')
10
-$LOAD_PATH.unshift(lib_pathname.to_s)
1
+#!/usr/bin/env rake
2
+require File.expand_path('../config/application', __FILE__)
3
+require 'metasploit/framework/require'
11 4
 
5
+# @note must be before `Metasploit::Framework::Application.load_tasks`
12 6
 #
13
-# load rake files like a rails engine
14
-#
15
-
16
-rakefile_glob = root.join('lib', 'tasks', '**', '*.rake').to_path
17
-
18
-Dir.glob(rakefile_glob) do |rakefile|
19
-  # Skip database tasks, will load them later if MDM is present
20
-  next if rakefile =~ /database\.rake$/
21
-  load rakefile
22
-end
23
-
24
-print_without = false
25
-
26
-begin
27
-	require 'rspec/core/rake_task'
28
-rescue LoadError
29
-	puts "rspec not in bundle, so can't set up spec tasks.  " \
30
-	     "To run specs ensure to install the development and test groups."
31
-
32
-	print_without = true
33
-else
34
-	RSpec::Core::RakeTask.new(:spec => 'db:test:prepare')
35
-
36
-	task :default => :spec
37
-end
38
-
39
-# Require yard before loading metasploit_data_models rake tasks as the yard tasks won't be defined if
40
-# YARD is not defined when yard.rake is loaded.
41
-begin
42
-  require 'yard'
43
-rescue LoadError
44
-	puts "yard not in bundle, so can't set up yard tasks.  " \
45
-	     "To generate documentation ensure to install the development group."
46
-
47
-	print_without = true
48
-end
49
-
50
-begin
51
-	require 'metasploit_data_models'
52
-rescue LoadError
53
-	puts "metasploit_data_models not in bundle, so can't set up db tasks.  " \
54
-	     "To run database tasks, ensure to install the db bundler group."
55
-
56
-	print_without = true
57
-else
58
-	load 'lib/tasks/database.rake'
59
-	metasploit_data_models_task_glob = MetasploitDataModels.root.join(
60
-			'lib',
61
-			'tasks',
62
-			'**',
63
-			'*.rake'
64
-	).to_s
65
-	# include tasks from metasplioit_data_models, such as `rake yard`.
66
-	# metasploit-framework specific yard options are in .yardopts
67
-	Dir.glob(metasploit_data_models_task_glob) do |path|
68
-		load path
69
-	end
70
-end
71
-
72
-
7
+# define db rake tasks from activerecord if activerecord is in the bundle.  activerecord could be not in the bundle if
8
+# the user installs with `bundle install --without db`
9
+Metasploit::Framework::Require.optionally_active_record_railtie
73 10
 
74
-if print_without
75
-	puts "Bundle currently installed " \
76
-	     "'--without #{Bundler.settings.without.join(' ')}'."
77
-	puts "To clear the without option do `bundle install --without ''` " \
78
-	     "(the --without flag with an empty string) or " \
79
-	     "`rm -rf .bundle` to remove the .bundle/config manually and " \
80
-	     "then `bundle install`"
81
-end
11
+Metasploit::Framework::Application.load_tasks

+ 23
- 0
app/concerns/metasploit/credential/core/to_credential.rb View File

@@ -0,0 +1,23 @@
1
+# Adds associations to `Metasploit::Credential::Core` which are inverses of association on models under
2
+# {BruteForce::Reuse}.
3
+require 'metasploit/framework/credential'
4
+
5
+module Metasploit::Credential::Core::ToCredential
6
+  extend ActiveSupport::Concern
7
+  
8
+  included do
9
+    
10
+    def to_credential
11
+      Metasploit::Framework::Credential.new(
12
+        public:       public.try(:username), 
13
+        private:      private.try(:data), 
14
+        private_type: private.try(:type).try(:demodulize).try(:underscore).try(:to_sym), 
15
+        realm:        realm.try(:value), 
16
+        realm_key:    realm.try(:key),
17
+        parent:       self
18
+      )
19
+    end
20
+    
21
+  end
22
+  
23
+end

+ 2
- 0
app/validators/metasploit.rb View File

@@ -0,0 +1,2 @@
1
+require 'metasploit/framework/file_path_validator'
2
+require 'metasploit/framework/executable_path_validator'

+ 16
- 0
app/validators/metasploit/framework/executable_path_validator.rb View File

@@ -0,0 +1,16 @@
1
+module Metasploit
2
+  module Framework
3
+    # This is a ActiveModel custom validator that assumes the attribute
4
+    # is supposed to be the path to a regular file. It checks whether the
5
+    # file exists and whether or not it is an executable file.
6
+    class ExecutablePathValidator < ActiveModel::EachValidator
7
+
8
+      def validate_each(record, attribute, value)
9
+        unless ::File.executable? value
10
+          record.errors[attribute] << (options[:message] || "is not a valid path to an executable file")
11
+        end
12
+      end
13
+    end
14
+  end
15
+end
16
+

+ 16
- 0
app/validators/metasploit/framework/file_path_validator.rb View File

@@ -0,0 +1,16 @@
1
+module Metasploit
2
+  module Framework
3
+    # This is a ActiveModel custom validator that assumes the attribute
4
+    # is supposed to be the path to a regular file. It checks whether the
5
+    # file exists and whether or not it is a regular file.
6
+    class FilePathValidator < ActiveModel::EachValidator
7
+
8
+      def validate_each(record, attribute, value)
9
+        unless ::File.file? value
10
+          record.errors[attribute] << (options[:message] || "is not a valid path to a regular file")
11
+        end
12
+      end
13
+    end
14
+  end
15
+end
16
+

+ 58
- 0
config/application.rb View File

@@ -0,0 +1,58 @@
1
+require 'rails'
2
+require File.expand_path('../boot', __FILE__)
3
+
4
+all_environments = [
5
+    :development,
6
+    :production,
7
+    :test
8
+]
9
+
10
+Bundler.require(
11
+    *Rails.groups(
12
+        db: all_environments,
13
+        pcap: all_environments
14
+    )
15
+)
16
+
17
+#
18
+# Railties
19
+#
20
+
21
+# For compatibility with jquery-rails (and other engines that need action_view) in pro
22
+require 'action_view/railtie'
23
+
24
+#
25
+# Project
26
+#
27
+
28
+require 'metasploit/framework/common_engine'
29
+require 'msf/base/config'
30
+
31
+module Metasploit
32
+  module Framework
33
+    class Application < Rails::Application
34
+      include Metasploit::Framework::CommonEngine
35
+
36
+      environment_database_yaml = ENV['MSF_DATABASE_CONFIG']
37
+
38
+      if environment_database_yaml
39
+        # DO NOT check if the path exists: if the environment variable is set, then the user meant to use this path
40
+        # and if it doesn't exist then an error should occur so the user knows the environment variable points to a
41
+        # non-existent file.
42
+        config.paths['config/database'] = environment_database_yaml
43
+      else
44
+        user_config_root = Pathname.new(Msf::Config.get_config_root)
45
+        user_database_yaml = user_config_root.join('database.yml')
46
+
47
+        # DO check if the path exists as in test environments there may be no config root, in which case the normal
48
+        # rails location, `config/database.yml`, should contain the database config.
49
+        if user_database_yaml.exist?
50
+          config.paths['config/database'] = [user_database_yaml.to_path]
51
+        end
52
+      end
53
+    end
54
+  end
55
+end
56
+
57
+# Silence warnings about this defaulting to true
58
+I18n.enforce_available_locales = true

+ 39
- 0
config/boot.rb View File

@@ -0,0 +1,39 @@
1
+require 'pathname'
2
+require 'rubygems'
3
+
4
+GEMFILE_EXTENSIONS = [
5
+    '.local',
6
+    ''
7
+]
8
+
9
+msfenv_real_pathname = Pathname.new(__FILE__).realpath
10
+root = msfenv_real_pathname.parent.parent
11
+
12
+unless ENV['BUNDLE_GEMFILE']
13
+  require 'pathname'
14
+
15
+  GEMFILE_EXTENSIONS.each do |extension|
16
+    extension_pathname = root.join("Gemfile#{extension}")
17
+
18
+    if extension_pathname.readable?
19
+      ENV['BUNDLE_GEMFILE'] = extension_pathname.to_path
20
+      break
21
+    end
22
+  end
23
+end
24
+
25
+begin
26
+  require 'bundler'
27
+rescue LoadError
28
+  $stderr.puts "[*] Metasploit requires the Bundler gem to be installed"
29
+  $stderr.puts "    $ gem install bundler"
30
+  exit(0)
31
+end
32
+
33
+Bundler.setup
34
+
35
+lib_path = root.join('lib').to_path
36
+
37
+unless $LOAD_PATH.include? lib_path
38
+  $LOAD_PATH.unshift lib_path
39
+end

+ 5
- 0
config/environment.rb View File

@@ -0,0 +1,5 @@
1
+# Load the rails application
2
+require File.expand_path('../application', __FILE__)
3
+
4
+# Initialize the rails application
5
+Metasploit::Framework::Application.initialize!

+ 4724
- 0
data/john/wordlists/common_roots.txt
File diff suppressed because it is too large
View File


lib/zip/test/data/generated/empty.txt → db/migrate/.git-keep View File


+ 118
- 1
db/schema.rb View File

@@ -11,7 +11,7 @@
11 11
 #
12 12
 # It's strongly recommended to check this file into your version control system.
13 13
 
14
-ActiveRecord::Schema.define(:version => 20130717150737) do
14
+ActiveRecord::Schema.define(:version => 20140801150537) do
15 15
 
16 16
   create_table "api_keys", :force => true do |t|
17 17
     t.text     "token"
@@ -28,6 +28,16 @@ ActiveRecord::Schema.define(:version => 20130717150737) do
28 28
     t.datetime "updated_at"
29 29
   end
30 30
 
31
+  create_table "credential_cores_tasks", :id => false, :force => true do |t|
32
+    t.integer "core_id"
33
+    t.integer "task_id"
34
+  end
35
+
36
+  create_table "credential_logins_tasks", :id => false, :force => true do |t|
37
+    t.integer "login_id"
38
+    t.integer "task_id"
39
+  end
40
+
31 41
   create_table "creds", :force => true do |t|
32 42
     t.integer  "service_id",                                    :null => false
33 43
     t.datetime "created_at",                                    :null => false
@@ -167,6 +177,113 @@ ActiveRecord::Schema.define(:version => 20130717150737) do
167 177
     t.binary   "prefs"
168 178
   end
169 179
 
180
+  create_table "metasploit_credential_cores", :force => true do |t|
181
+    t.integer  "origin_id",                   :null => false
182
+    t.string   "origin_type",                 :null => false
183
+    t.integer  "private_id"
184
+    t.integer  "public_id"
185
+    t.integer  "realm_id"
186
+    t.integer  "workspace_id",                :null => false
187
+    t.datetime "created_at",                  :null => false
188
+    t.datetime "updated_at",                  :null => false
189
+    t.integer  "logins_count", :default => 0
190
+  end
191
+
192
+  add_index "metasploit_credential_cores", ["origin_type", "origin_id"], :name => "index_metasploit_credential_cores_on_origin_type_and_origin_id"
193
+  add_index "metasploit_credential_cores", ["private_id"], :name => "index_metasploit_credential_cores_on_private_id"
194
+  add_index "metasploit_credential_cores", ["public_id"], :name => "index_metasploit_credential_cores_on_public_id"
195
+  add_index "metasploit_credential_cores", ["realm_id"], :name => "index_metasploit_credential_cores_on_realm_id"
196
+  add_index "metasploit_credential_cores", ["workspace_id", "private_id"], :name => "unique_private_metasploit_credential_cores", :unique => true
197
+  add_index "metasploit_credential_cores", ["workspace_id", "public_id", "private_id"], :name => "unique_realmless_metasploit_credential_cores", :unique => true
198
+  add_index "metasploit_credential_cores", ["workspace_id", "public_id"], :name => "unique_public_metasploit_credential_cores", :unique => true
199
+  add_index "metasploit_credential_cores", ["workspace_id", "realm_id", "private_id"], :name => "unique_publicless_metasploit_credential_cores", :unique => true
200
+  add_index "metasploit_credential_cores", ["workspace_id", "realm_id", "public_id", "private_id"], :name => "unique_complete_metasploit_credential_cores", :unique => true
201
+  add_index "metasploit_credential_cores", ["workspace_id", "realm_id", "public_id"], :name => "unique_privateless_metasploit_credential_cores", :unique => true
202
+  add_index "metasploit_credential_cores", ["workspace_id"], :name => "index_metasploit_credential_cores_on_workspace_id"
203
+
204
+  create_table "metasploit_credential_logins", :force => true do |t|
205
+    t.integer  "core_id",           :null => false
206
+    t.integer  "service_id",        :null => false
207
+    t.string   "access_level"
208
+    t.string   "status",            :null => false
209
+    t.datetime "last_attempted_at"
210
+    t.datetime "created_at",        :null => false
211
+    t.datetime "updated_at",        :null => false
212
+  end
213
+
214
+  add_index "metasploit_credential_logins", ["core_id", "service_id"], :name => "index_metasploit_credential_logins_on_core_id_and_service_id", :unique => true
215
+  add_index "metasploit_credential_logins", ["service_id", "core_id"], :name => "index_metasploit_credential_logins_on_service_id_and_core_id", :unique => true
216
+
217
+  create_table "metasploit_credential_origin_cracked_passwords", :force => true do |t|
218
+    t.integer  "metasploit_credential_core_id", :null => false
219
+    t.datetime "created_at",                    :null => false
220
+    t.datetime "updated_at",                    :null => false
221
+  end
222
+
223
+  add_index "metasploit_credential_origin_cracked_passwords", ["metasploit_credential_core_id"], :name => "originating_credential_cores"
224
+
225
+  create_table "metasploit_credential_origin_imports", :force => true do |t|
226
+    t.text     "filename",   :null => false
227
+    t.integer  "task_id"
228
+    t.datetime "created_at", :null => false
229
+    t.datetime "updated_at", :null => false
230
+  end
231
+
232
+  add_index "metasploit_credential_origin_imports", ["task_id"], :name => "index_metasploit_credential_origin_imports_on_task_id"
233
+
234
+  create_table "metasploit_credential_origin_manuals", :force => true do |t|
235
+    t.integer  "user_id",    :null => false
236
+    t.datetime "created_at", :null => false
237
+    t.datetime "updated_at", :null => false
238
+  end
239
+
240
+  add_index "metasploit_credential_origin_manuals", ["user_id"], :name => "index_metasploit_credential_origin_manuals_on_user_id"
241
+
242
+  create_table "metasploit_credential_origin_services", :force => true do |t|
243
+    t.integer  "service_id",       :null => false
244
+    t.text     "module_full_name", :null => false
245
+    t.datetime "created_at",       :null => false
246
+    t.datetime "updated_at",       :null => false
247
+  end
248
+
249
+  add_index "metasploit_credential_origin_services", ["service_id", "module_full_name"], :name => "unique_metasploit_credential_origin_services", :unique => true
250
+
251
+  create_table "metasploit_credential_origin_sessions", :force => true do |t|
252
+    t.text     "post_reference_name", :null => false
253
+    t.integer  "session_id",          :null => false
254
+    t.datetime "created_at",          :null => false
255
+    t.datetime "updated_at",          :null => false
256
+  end
257
+
258
+  add_index "metasploit_credential_origin_sessions", ["session_id", "post_reference_name"], :name => "unique_metasploit_credential_origin_sessions", :unique => true
259
+
260
+  create_table "metasploit_credential_privates", :force => true do |t|
261
+    t.string   "type",       :null => false
262
+    t.text     "data",       :null => false
263
+    t.datetime "created_at", :null => false
264
+    t.datetime "updated_at", :null => false
265
+    t.string   "jtr_format"
266
+  end
267
+
268
+  add_index "metasploit_credential_privates", ["type", "data"], :name => "index_metasploit_credential_privates_on_type_and_data", :unique => true
269
+
270
+  create_table "metasploit_credential_publics", :force => true do |t|
271
+    t.string   "username",   :null => false
272
+    t.datetime "created_at", :null => false
273
+    t.datetime "updated_at", :null => false
274
+  end
275
+
276
+  add_index "metasploit_credential_publics", ["username"], :name => "index_metasploit_credential_publics_on_username", :unique => true
277
+
278
+  create_table "metasploit_credential_realms", :force => true do |t|
279
+    t.string   "key",        :null => false
280
+    t.string   "value",      :null => false
281
+    t.datetime "created_at", :null => false
282
+    t.datetime "updated_at", :null => false
283
+  end
284
+
285
+  add_index "metasploit_credential_realms", ["key", "value"], :name => "index_metasploit_credential_realms_on_key_and_value", :unique => true
286
+
170 287
   create_table "mod_refs", :force => true do |t|
171 288
     t.string "module", :limit => 1024
172 289
     t.string "mtype",  :limit => 128

+ 4
- 0
lib/fastlib.rb View File

@@ -378,6 +378,10 @@ module Kernel #:nodoc:all
378 378
   # This method handles the loading of FASTLIB archives
379 379
   #
380 380
   def fastlib_require(name)
381
+    if name.respond_to? :to_path
382
+      name = name.to_path
383
+    end
384
+
381 385
     name = name + ".rb" if not name =~ /\.rb$/
382 386
     return false if fastlib_already_loaded?(name)
383 387
     return false if fastlib_already_tried?(name)

+ 27
- 25
lib/metasploit/framework.rb View File

@@ -1,3 +1,29 @@
1
+#
2
+# Gems
3
+#
4
+# gems must load explicitly any gem declared in gemspec
5
+# @see https://github.com/bundler/bundler/issues/2018#issuecomment-6819359
6
+#
7
+
8
+require 'active_support'
9
+require 'bcrypt'
10
+require 'json'
11
+require 'msgpack'
12
+require 'metasploit/model'
13
+require 'nokogiri'
14
+require 'packetfu'
15
+# railties has not autorequire defined
16
+# rkelly-remix is a fork of rkelly, so it's autorequire is 'rkelly' and not 'rkelly-remix'
17
+require 'rkelly'
18
+require 'robots'
19
+require 'zip'
20
+
21
+#
22
+# Project
23
+#
24
+
25
+require 'msf/core'
26
+
1 27
 # Top-level namespace that is shared between {Metasploit::Framework
2 28
 # metasploit-framework} and pro, which uses Metasploit::Pro.
3 29
 module Metasploit
@@ -5,30 +31,6 @@ module Metasploit
5 31
   # works in compatible manner with activerecord's rake tasks and other
6 32
   # railties.
7 33
   module Framework
8
-    # Returns the environment for {Metasploit::Framework}.  Checks
9
-    # `METASPLOIT_FRAMEWORK_ENV` environment variable for value.  Defaults to
10
-    # `'development'` if `METASPLOIT_FRAMEWORK_ENV` is not set in the
11
-    # environment variables.
12
-    #
13
-    # {env} is a ActiveSupport::StringInquirer like `Rails.env` so it can be
14
-    # queried for its value.
15
-    #
16
-    # @example check if environment is development
17
-    #   if Metasploit::Framework.env.development?
18
-    #     # runs only when in development
19
-    #   end
20
-    #
21
-    # @return [ActiveSupport::StringInquirer] the environment name
22
-    def self.env
23
-      unless instance_variable_defined? :@env
24
-        name = ENV['METASPLOIT_FRAMEWORK_ENV']
25
-        name ||= 'development'
26
-        @env = ActiveSupport::StringInquirer.new(name)
27
-      end
28
-
29
-      @env
30
-    end
31
-
32 34
     # Returns the root of the metasploit-framework project.  Use in place of
33 35
     # `Rails.root`.
34 36
     #
@@ -42,4 +44,4 @@ module Metasploit
42 44
       @root
43 45
     end
44 46
   end
45
-end
47
+end

+ 323
- 0
lib/metasploit/framework/afp/client.rb View File

@@ -0,0 +1,323 @@
1
+# -*- coding: binary -*-
2
+require 'msf/core'
3
+require 'msf/core/exploit/tcp'
4
+
5
+module Metasploit
6
+  module Framework
7
+    module AFP
8
+      module Client
9
+
10
+        def next_id
11
+          @request_id ||= -1
12
+          @request_id += 1
13
+
14
+          @request_id
15
+        end
16
+
17
+        def get_info
18
+          packet =  "\00"    # Flag: Request
19
+          packet << "\x03"   # Command: FPGetSrvrInfo
20
+          packet << [next_id].pack('n') # requestID
21
+          packet << "\x00\x00\x00\x00" # Data offset
22
+          packet << "\x00\x00\x00\x00" # Length
23
+          packet << "\x00\x00\x00\x00" # Reserved
24
+
25
+          sock.put(packet)
26
+
27
+          response = sock.timed_read(1024)
28
+          return parse_info_response(response)
29
+        end
30
+
31
+        def open_session
32
+          packet =  "\00"              # Flag: Request
33
+          packet << "\x04"             # Command: DSIOpenSession
34
+          packet << [next_id].pack('n') # requestID
35
+          packet << "\x00\x00\x00\x00" # Data offset
36
+          packet << "\x00\x00\x00\x06" # Length
37
+          packet << "\x00\x00\x00\x00" # Reserved
38
+          packet << "\x01"             # Attention Quantum
39
+          packet << "\x04"             # Length
40
+          packet << "\x00\x00\x04\x00" # 1024
41
+
42
+          sock.put(packet)
43
+
44
+          response = sock.timed_read(1024)
45
+          return parse_open_session_response(response)
46
+        end
47
+
48
+        def login(user, pass)
49
+          if user == ''
50
+            return no_user_authent_login
51
+          end
52
+
53
+          p = OpenSSL::BN.new("BA2873DFB06057D43F2024744CEEE75B", 16)
54
+          g = OpenSSL::BN.new("7", 10)
55
+          ra = OpenSSL::BN.new('86F6D3C0B0D63E4B11F113A2F9F19E3BBBF803F28D30087A1450536BE979FD42', 16)
56
+          ma = g.mod_exp(ra, p)
57
+
58
+          padded_user = (user.length + 1) % 2 != 0 ? user + "\x00" : user
59
+          bin_user = [padded_user.length, padded_user].pack("Ca*")
60
+
61
+          length = 18 + bin_user.length + ma.to_s(2).length
62
+
63
+          packet =  "\00"              # Flag: Request
64
+          packet << "\x02"             # Command: DSICommand
65
+          packet << [next_id].pack('n') # requestID
66
+          packet << "\x00\x00\x00\x00" # Data offset
67
+          packet << [length].pack('N') # Length (42)
68
+          packet << "\x00\x00\x00\x00" # Reserved
69
+          packet << "\x12"             # AFPCommand: FPLogin (18)
70
+          packet << "\x06\x41\x46\x50\x33\x2e\x31" # AFPVersion: AFP3.1
71
+          packet << "\x09\x44\x48\x43\x41\x53\x54\x31\x32\x38" #UAM: DHCAST128
72
+          packet << bin_user           # username
73
+          packet << ma.to_s(2)         # random number
74
+
75
+          sock.put(packet)
76
+
77
+          begin
78
+            response = sock.timed_read(1024, self.login_timeout)
79
+          rescue Timeout::Error
80
+            #vprint_error("AFP #{rhost}:#{rport} Login timeout (AFP server delay response for 20 - 22 seconds after 7 incorrect logins)")
81
+            return :connection_error
82
+          end
83
+
84
+          flags, command, request_id, error_code, length, reserved = parse_header(response)
85
+
86
+          case error_code
87
+          when -5001 #kFPAuthContinue
88
+            return parse_login_response_add_send_login_count(response, {:p => p, :g => g, :ra => ra, :ma => ma,
89
+                                                                        :password => pass, :user => user})
90
+          when -5023 #kFPUserNotAuth (User dosen't exists)
91
+            #print_status("AFP #{rhost}:#{rport} User #{user} dosen't exists")
92
+            return :skip_user
93
+          else
94
+            return :connection_error
95
+          end
96
+
97
+        end
98
+
99
+        def close_session
100
+          packet =  "\00"              # Flag: Request
101
+          packet << "\x01"             # Command: DSICloseSession
102
+          packet << [next_id].pack('n')    # requestID
103
+          packet << "\x00\x00\x00\x00" #Data offset
104
+          packet << "\x00\x00\x00\x00" #Length
105
+          packet << "\x00\x00\x00\x00" #Reserved
106
+
107
+          sock.put(packet)
108
+        end
109
+
110
+        def no_user_authent_login
111
+          packet =  "\00"              # Flag: Request
112
+          packet << "\x02"             # Command: DSICommand
113
+          packet << [next_id].pack('n')    # requestID
114
+          packet << "\x00\x00\x00\x00" # Data offset
115
+          packet << "\x00\x00\x00\x18" # Length (24)
116
+          packet << "\x00\x00\x00\x00" # Reserved
117
+          packet << "\x12"             # AFPCommand: FPLogin (18)
118
+          packet << "\x06\x41\x46\x50\x33\x2e\x31" #AFP3.1
119
+          packet << "\x0f\x4e\x6f\x20\x55\x73\x65\x72\x20\x41\x75\x74\x68\x65\x6e\x74" #UAM: No User Authent
120
+
121
+          sock.put(packet)
122
+
123
+          begin
124
+            response = sock.timed_read(1024, self.login_timeout)
125
+          rescue Timeout::Error
126
+            vprint_error("AFP #{rhost}:#{rport} Login timeout (AFP server delay response for 20 - 22 seconds after 7 incorrect logins)")
127
+            return :connection_error
128
+          end
129
+
130
+          flags, command, request_id, error_code, length, reserved = parse_header(response)
131
+
132
+          if error_code == 0
133
+            return :true
134
+          else
135
+            return false
136
+          end
137
+        end
138
+
139
+        def parse_login_response_add_send_login_count(response, data)
140
+          dhx_s2civ = 'CJalbert'
141
+          dhx_c2civ = 'LWallace'
142
+
143
+          flags, command, request_id, error_code, length, reserved = parse_header(response)
144
+          body = get_body(response, length)
145
+          id, mb, enc_data = body.unpack("nH32a*")
146
+
147
+          mb = OpenSSL::BN.new(mb, 16)
148
+          k = mb.mod_exp(data[:ra], data[:p] )
149
+
150
+          cipher = OpenSSL::Cipher.new('cast5-cbc').decrypt
151
+          cipher.key = k.to_s(2)
152
+          cipher.iv = dhx_s2civ
153
+          cipher.padding = 0
154
+
155
+          nonce = cipher.update(enc_data)
156
+          nonce << cipher.final
157
+          nonce = nonce[0..15]
158
+          nonce = OpenSSL::BN.new(nonce, 2) + 1
159
+
160
+          plain_text = nonce.to_s(2) + data[:password].ljust(64, "\x00")
161
+          cipher = OpenSSL::Cipher.new('cast5-cbc').encrypt
162
+          cipher.key = k.to_s(2)
163
+          cipher.iv = dhx_c2civ
164
+          auth_response = cipher.update(plain_text)
165
+          auth_response << cipher.final
166
+
167
+          packet =  "\00"              # Flag: Request
168
+          packet << "\x02"             # Command: DSICommand
169
+          packet << [next_id].pack('n')    # requestID
170
+          packet << "\x00\x00\x00\x00" # Data offset
171
+          packet << [auth_response.length + 2].pack("N")  # Length
172
+          packet << "\x00\x00\x00\x00" # Reserved
173
+          packet << "\x13"             # AFPCommand: FPLoginCont (19)
174
+          packet << "\x00"
175
+          packet << [id].pack('n')
176
+          packet << auth_response
177
+
178
+          sock.put(packet)
179
+
180
+          begin
181
+            response = sock.timed_read(1024, self.login_timeout)
182
+          rescue Timeout::Error
183
+            vprint_error("AFP #{rhost}:#{rport} Login timeout (AFP server delay response for 20 - 22 seconds after 7 incorrect logins)")
184
+            return :connection_error
185
+          end
186
+
187
+          flags, command, request_id, error_code, length, reserved = parse_header(response)
188
+          if error_code == 0
189
+            return true
190
+          else
191
+            return false
192
+          end
193
+        end
194
+
195
+        def parse_open_session_response(response)
196
+          _, _, _, error_code, _, _ = parse_header(response)
197
+          return error_code == 0 ? true : false
198
+        end
199
+
200
+        def parse_info_response(response)
201
+          parsed_data = {}
202
+
203
+          flags, command, request_id, error_code, length, reserved = parse_header(response)
204
+          raise "AFP #{rhost}:#{rport} Server response with error" if error_code != 0
205
+          body = get_body(response, length)
206
+          machine_type_offset, afp_versions_offset, uam_count_offset, icon_offset, server_flags =
207
+            body.unpack('nnnnn')
208
+
209
+          server_name_length = body.unpack('@10C').first
210
+          parsed_data[:server_name] = body.unpack("@11A#{server_name_length}").first
211
+
212
+          pos = 11 + server_name_length
213
+          pos += 1 if pos % 2 != 0 #padding
214
+
215
+          server_signature_offset, network_addresses_offset, directory_names_offset,
216
+            utf8_servername_offset = body.unpack("@#{pos}nnnn")
217
+
218
+          parsed_data[:machine_type] = read_pascal_string(body, machine_type_offset)
219
+          parsed_data[:versions] = read_array(body, afp_versions_offset)
220
+          parsed_data[:uams] = read_array(body, uam_count_offset)
221
+          # skiped icon
222
+          parsed_data[:server_flags] = parse_flags(server_flags)
223
+          parsed_data[:signature] = body.unpack("@#{server_signature_offset}H32").first
224
+
225
+          network_addresses = read_array(body, network_addresses_offset, true)
226
+          parsed_data[:network_addresses] = parse_network_addresses(network_addresses)
227
+          # skiped directory names
228
+          #Error catching for offset issues on this field. Need better error ahndling all through here
229
+          begin
230
+            parsed_data[:utf8_server_name] = read_utf8_pascal_string(body, utf8_servername_offset)
231
+          rescue
232
+            parsed_data[:utf8_server_name] = "N/A"
233
+          end
234
+
235
+          return parsed_data
236
+        end
237
+
238
+        def parse_header(packet)
239
+          header = packet.unpack('CCnNNN') #ruby 1.8.7 don't support unpacking signed integers in big-endian order
240
+          header[3] = packet[4..7].reverse.unpack("l").first
241
+          return header
242
+        end
243
+
244
+        def get_body(packet, body_length)
245
+          body = packet[16..body_length + 15]
246
+          raise "AFP #{rhost}:#{rport} Invalid body length" if body.length != body_length
247
+          return body
248
+        end
249
+
250
+        def read_pascal_string(str, offset)
251
+          length = str.unpack("@#{offset}C").first
252
+          return str.unpack("@#{offset + 1}A#{length}").first
253
+        end
254
+
255
+        def read_utf8_pascal_string(str, offset)
256
+          length = str.unpack("@#{offset}n").first
257
+          return str[offset + 2..offset + length + 1]
258
+        end
259
+
260
+        def read_array(str, offset, afp_network_address=false)
261
+          size = str.unpack("@#{offset}C").first
262
+          pos = offset + 1
263
+
264
+          result = []
265
+          size.times do
266
+            result << read_pascal_string(str, pos)
267
+            pos += str.unpack("@#{pos}C").first
268
+            pos += 1 unless afp_network_address
269
+          end
270
+          return result
271
+        end
272
+
273
+        def parse_network_addresses(network_addresses)
274
+          parsed_addreses = []
275
+          network_addresses.each do |address|
276
+            case address.unpack('C').first
277
+            when 0 #Reserved
278
+              next
279
+            when 1 # Four-byte IP address
280
+              parsed_addreses << IPAddr.ntop(address[1..4]).to_s
281
+            when 2 # Four-byte IP address followed by a two-byte port number
282
+              parsed_addreses <<  "#{IPAddr.ntop(address[1..4])}:#{address[5..6].unpack("n").first}"
283
+            when 3 # DDP address (depricated)
284
+              next
285
+            when 4 # DNS name (maximum of 254 bytes)
286
+              parsed_addreses << address[1..address.length - 1]
287
+            when 5 # This functionality is deprecated.
288
+              next
289
+            when 6 # IPv6 address (16 bytes)
290
+              parsed_addreses << "[#{IPAddr.ntop(address[1..16])}]"
291
+            when 7 # IPv6 address (16 bytes) followed by a two-byte port number
292
+              parsed_addreses << "[#{IPAddr.ntop(address[1..16])}]:#{address[17..18].unpack("n").first}"
293
+            else   # Something wrong?
294
+              raise "Error parsing network addresses"
295
+            end
296
+          end
297
+          return parsed_addreses
298
+        end
299
+
300
+        def parse_flags(flags)
301
+          flags = flags.to_s(2)
302
+          result = {}
303
+          result['Super Client'] = flags[0,1] == '1' ? true : false
304
+          result['UUIDs'] = flags[5,1] == '1' ? true : false
305
+          result['UTF8 Server Name'] = flags[6,1] == '1' ? true : false
306
+          result['Open Directory'] = flags[7,1] == '1' ? true : false
307
+          result['Reconnect'] = flags[8,1] == '1' ? true : false
308
+          result['Server Notifications'] = flags[9,1] == '1' ? true : false
309
+          result['TCP/IP'] = flags[10,1] == '1' ? true : false
310
+          result['Server Signature'] = flags[11,1] == '1' ? true : false
311
+          result['Server Messages'] = flags[12,1] == '1' ? true : false
312
+          result['Password Saving Prohibited'] = flags[13,1] == '1' ? true : false
313
+          result['Password Changing'] = flags[14,1] == '1' ? true : false
314
+          result['Copy File'] = flags[5,1] == '1' ? true : false
315
+          return result
316
+        end
317
+
318
+      end
319
+    end
320
+
321
+  end
322
+end
323
+

+ 7
- 0
lib/metasploit/framework/api.rb View File

@@ -0,0 +1,7 @@
1
+module Metasploit
2
+  module Framework
3
+    module API
4
+
5
+    end
6
+  end
7
+end

+ 16
- 0
lib/metasploit/framework/api/version.rb View File

@@ -0,0 +1,16 @@
1
+module Metasploit
2
+  module Framework
3
+    module API
4
+      # @note This is a like.  The API version is not semantically version and it's version has actually never changed
5
+      #    even though API changes have occured.  DO NOT base compatibility on this version.
6
+      module Version
7
+        MAJOR = 1
8
+        MINOR = 0
9
+        PATCH = 0
10
+      end
11
+
12
+      VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::PATCH}"
13
+      GEM_VERSION = Gem::Version.new(VERSION)
14
+    end
15
+  end
16
+end

+ 26
- 0
lib/metasploit/framework/command.rb View File

@@ -0,0 +1,26 @@
1
+#
2
+# Gems
3
+#
4
+
5
+# have to be exact so minimum is loaded prior to parsing arguments which could
6
+# influence loading.
7
+require 'active_support/dependencies/autoload'
8
+
9
+# @note Must use the nested declaration of the
10
+# {Metasploit::Framework::Command} namespace because commands need to be able
11
+# to be required directly without any other part of metasploit-framework
12
+# besides config/boot so that the commands can parse arguments, setup
13
+# RAILS_ENV, and load config/application.rb correctly.
14
+module Metasploit
15
+  module Framework
16
+    module Command
17
+      # Namespace for commands for metasploit-framework.  There are
18
+      # corresponding classes in the {Metasploit::Framework::ParsedOptions}
19
+      # namespace, which handle for parsing the options for each command.
20
+      extend ActiveSupport::Autoload
21
+
22
+      autoload :Base
23
+      autoload :Console
24
+    end
25
+  end
26
+end

+ 113
- 0
lib/metasploit/framework/command/base.rb View File

@@ -0,0 +1,113 @@
1
+#
2
+# Gems
3
+#
4
+
5
+require 'active_support/core_ext/module/introspection'
6
+
7
+#
8
+# Project
9
+#
10
+
11
+require 'metasploit/framework/command'
12
+require 'metasploit/framework/parsed_options'
13
+require 'metasploit/framework/require'
14
+
15
+# Based on pattern used for lib/rails/commands in the railties gem.
16
+class Metasploit::Framework::Command::Base
17
+  #
18
+  # Attributes
19
+  #
20
+
21
+  # @!attribute [r] application
22
+  #   The Rails application for metasploit-framework.
23
+  #
24
+  #   @return [Metasploit::Framework::Application]
25
+  attr_reader :application
26
+
27
+  # @!attribute [r] parsed_options
28
+  #   The parsed options from the command line.
29
+  #
30
+  #   @return (see parsed_options)
31
+  attr_reader :parsed_options
32
+
33
+  #
34
+  # Class Methods
35
+  #
36
+
37
+  # @note {require_environment!} should be called to load
38
+  #   `config/application.rb` to so that the RAILS_ENV can be set from the
39
+  #   command line options in `ARGV` prior to `Rails.env` being set.
40
+  # @note After returning, `Rails.application` will be defined and configured.
41
+  #
42
+  # Parses `ARGV` for command line arguments to configure the
43
+  # `Rails.application`.
44
+  #
45
+  # @return (see parsed_options)
46
+  def self.require_environment!
47
+    parsed_options = self.parsed_options
48
+    # RAILS_ENV must be set before requiring 'config/application.rb'
49
+    parsed_options.environment!
50
+    ARGV.replace(parsed_options.positional)
51
+
52
+    # allow other Rails::Applications to use this command
53
+    if !defined?(Rails) || Rails.application.nil?
54
+      # @see https://github.com/rails/rails/blob/v3.2.17/railties/lib/rails/commands.rb#L39-L40
55
+      require Pathname.new(__FILE__).parent.parent.parent.parent.parent.join('config', 'application')
56
+    end
57
+
58
+    # have to configure before requiring environment because
59
+    # config/environment.rb calls initialize! and the initializers will use
60
+    # the configuration from the parsed options.
61
+    parsed_options.configure(Rails.application)
62
+
63
+    # support disabling the database
64
+    unless parsed_options.options.database.disable
65
+      Metasploit::Framework::Require.optionally_active_record_railtie
66
+    end
67
+
68
+    Rails.application.require_environment!
69
+
70
+    parsed_options
71
+  end
72
+
73
+  def self.parsed_options
74
+    parsed_options_class.new
75
+  end
76
+
77
+  def self.parsed_options_class
78
+    @parsed_options_class ||= parsed_options_class_name.constantize
79
+  end
80
+
81
+  def self.parsed_options_class_name
82
+    @parsed_options_class_name ||= "#{parent.parent}::ParsedOptions::#{name.demodulize}"
83
+  end
84
+
85
+  def self.start
86
+    parsed_options = require_environment!
87
+    new(application: Rails.application, parsed_options: parsed_options).start
88
+  end
89
+
90
+  #
91
+  # Instance Methods
92
+  #
93
+
94
+  # @param attributes [Hash{Symbol => ActiveSupport::OrderedOptions,Rails::Application}]
95
+  # @option attributes [Rails::Application] :application
96
+  # @option attributes [ActiveSupport::OrderedOptions] :parsed_options
97
+  # @raise [KeyError] if :application is not given
98
+  # @raise [KeyError] if :parsed_options is not given
99
+  def initialize(attributes={})
100
+    @application = attributes.fetch(:application)
101
+    @parsed_options = attributes.fetch(:parsed_options)
102
+  end
103
+
104
+  # @abstract Use {#application} to start this command.
105
+  #
106
+  # Starts this command.
107
+  #
108
+  # @return [void]
109
+  # @raise [NotImplementedError]
110
+  def start
111
+    raise NotImplementedError
112
+  end
113
+end

+ 64
- 0
lib/metasploit/framework/command/console.rb View File

@@ -0,0 +1,64 @@
1
+#
2
+# Project
3
+#
4
+
5
+require 'metasploit/framework/command'
6
+require 'metasploit/framework/command/base'
7
+
8
+# Based on pattern used for lib/rails/commands in the railties gem.
9
+class Metasploit::Framework::Command::Console < Metasploit::Framework::Command::Base
10
+  def start
11
+    case parsed_options.options.subcommand
12
+    when :version
13
+      $stderr.puts "Framework Version: #{Metasploit::Framework::VERSION}"
14
+    else
15
+      driver.run
16
+    end
17
+  end
18
+
19
+  private
20
+
21
+  # The console UI driver.
22
+  #
23
+  # @return [Msf::Ui::Console::Driver]
24
+  def driver
25
+    unless @driver
26
+      # require here so minimum loading is done before {start} is called.
27
+      require 'msf/ui'
28
+
29
+      @driver = Msf::Ui::Console::Driver.new(
30
+          Msf::Ui::Console::Driver::DefaultPrompt,
31
+          Msf::Ui::Console::Driver::DefaultPromptChar,
32
+          driver_options
33
+      )
34
+    end
35
+
36
+    @driver
37
+  end
38
+
39
+  def driver_options
40
+    unless @driver_options
41
+      options = parsed_options.options
42
+
43
+      driver_options = {}
44
+      driver_options['Config'] = options.framework.config
45
+      driver_options['ConfirmExit'] = options.console.confirm_exit
46
+      driver_options['DatabaseEnv'] = options.environment
47
+      driver_options['DatabaseMigrationPaths'] = options.database.migrations_paths
48
+      driver_options['DatabaseYAML'] = options.database.config
49
+      driver_options['Defanged'] = options.console.defanged
50
+      driver_options['DisableBanner'] = options.console.quiet
51
+      driver_options['DisableDatabase'] = options.database.disable
52
+      driver_options['LocalOutput'] = options.console.local_output
53
+      driver_options['ModulePath'] = options.modules.path
54
+      driver_options['Plugins'] = options.console.plugins
55
+      driver_options['RealReadline'] = options.console.real_readline
56
+      driver_options['Resource'] = options.console.resources
57
+      driver_options['XCommands'] = options.console.commands
58
+
59
+      @driver_options = driver_options
60
+    end
61
+
62
+    @driver_options
63
+  end
64
+end

+ 74
- 0
lib/metasploit/framework/common_engine.rb View File

@@ -0,0 +1,74 @@
1
+#
2
+# Standard Library
3
+#
4
+
5
+require 'fileutils'
6
+
7
+# `Rails::Engine` behavior common to both {Metasploit::Framework::Application} and {Metasploit::Framework::Engine}.
8
+module Metasploit::Framework::CommonEngine
9
+  extend ActiveSupport::Concern
10
+
11
+  included do
12
+    #
13
+    # config
14
+    #
15
+
16
+    # Force binary encoding to remove necessity to set external and internal encoding when construct Strings from
17
+    # from files.  Socket#read always returns a String in ASCII-8bit encoding
18
+    #
19
+    # @see http://rubydoc.info/stdlib/core/IO:read
20
+    config.before_initialize do
21
+      encoding = 'binary'
22
+      Encoding.default_external = encoding
23
+      Encoding.default_internal = encoding
24
+    end
25
+
26
+    config.root = Msf::Config::install_root
27
+    config.paths.add 'data/meterpreter', glob: '**/ext_*'
28
+    config.paths.add 'modules'
29
+
30
+    #
31
+    # `initializer`s
32
+    #
33
+
34
+    initializer 'metasploit_framework.merge_meterpreter_extensions' do
35
+      Rails.application.railties.engines.each do |engine|
36
+        merge_meterpreter_extensions(engine)
37
+      end
38
+
39
+      # The Rails.application itself could have paths['data/meterpreter'], but will not be part of
40
+      # Rails.application.railties.engines because only direct subclasses of `Rails::Engine` are returned.
41
+      merge_meterpreter_extensions(Rails.application)
42
+    end
43
+  end
44
+
45
+  #
46
+  # Instance Methods
47
+  #
48
+
49
+  private
50
+
51
+  # Merges the meterpreter extensions from `engine`'s `paths['data/meterpreter]`.
52
+  #
53
+  # @param engine [Rails::Engine] a Rails engine or application that has meterpreter extensions
54
+  # @return [void]
55
+  # @todo Make metasploit-framework look for meterpreter extension in paths['data/meterpreter'] from the engine instead of copying them.
56
+  def merge_meterpreter_extensions(engine)
57
+    data_meterpreter_paths = engine.paths['data/meterpreter']
58
+
59
+    # may be `nil` since 'data/meterpreter' is not part of the core Rails::Engine paths set.
60
+    if data_meterpreter_paths
61
+      source_paths = data_meterpreter_paths.existent
62
+      destination_directory = root.join('data', 'meterpreter').to_path
63
+
64
+      source_paths.each do |source_path|
65
+        basename = File.basename(source_path)
66
+        destination_path = File.join(destination_directory, basename)
67
+
68
+        unless destination_path == source_path
69
+          FileUtils.copy(source_path, destination_directory)
70
+        end
71
+      end
72
+    end
73
+  end
74
+end

+ 74
- 0
lib/metasploit/framework/community_string_collection.rb View File

@@ -0,0 +1,74 @@
1
+require 'metasploit/framework/credential'
2
+
3
+module Metasploit
4
+  module Framework
5
+
6
+    # This class is responsible for taking datastore options from the snmp_login module
7
+    # and yielding appropriate {Metasploit::Framework::Credential}s to the {Metasploit::Framework::LoginScanner::SNMP}.
8
+    # This one has to be different from {credentialCollection} as it will only have a {Metasploit::Framework::Credential#public}
9
+    # It may be slightly confusing that the attribues are called password and pass_file, because this is what the legacy
10
+    # module used. However, community Strings are now considered more to be public credentials than private ones.
11
+    class CommunityStringCollection
12
+      # @!attribute pass_file
13
+      #   Path to a file containing passwords, one per line
14
+      #   @return [String]
15
+      attr_accessor :pass_file
16
+
17
+      # @!attribute password
18
+      #   @return [String]
19
+      attr_accessor :password
20
+
21
+      # @!attribute prepended_creds
22
+      #   List of credentials to be tried before any others
23
+      #
24
+      #   @see #prepend_cred
25
+      #   @return [Array<Credential>]
26
+      attr_accessor :prepended_creds
27
+
28
+      # @option opts [String] :pass_file See {#pass_file}
29
+      # @option opts [String] :password See {#password}
30
+      # @option opts [Array<Credential>] :prepended_creds ([]) See {#prepended_creds}
31
+      def initialize(opts = {})
32
+        opts.each do |attribute, value|
33
+          public_send("#{attribute}=", value)
34
+        end
35
+        self.prepended_creds ||= []
36
+      end
37
+
38
+      # Combines all the provided credential sources into a stream of {Credential}
39
+      # objects, yielding them one at a time
40
+      #
41
+      # @yieldparam credential [Metasploit::Framework::Credential]
42
+      # @return [void]
43
+      def each
44
+        begin
45
+          if pass_file.present?
46
+            pass_fd = File.open(pass_file, 'r:binary')
47
+            pass_fd.each_line do |line|
48
+              line.chomp!
49
+              yield Metasploit::Framework::Credential.new(public: line, paired: false)
50
+            end
51
+          end
52
+
53
+          if password.present?
54
+            yield Metasploit::Framework::Credential.new(public: password, paired: false)
55
+          end
56
+
57
+        ensure
58
+          pass_fd.close if pass_fd && !pass_fd.closed?
59
+        end
60
+      end
61
+
62
+      # Add {Credential credentials} that will be yielded by {#each}
63
+      #
64
+      # @see prepended_creds
65
+      # @param cred [Credential]
66
+      # @return [self]
67
+      def prepend_cred(cred)
68
+        prepended_creds.unshift cred
69
+        self
70
+      end
71
+
72
+    end
73
+  end
74
+end

+ 7
- 0
lib/metasploit/framework/core.rb View File

@@ -0,0 +1,7 @@
1
+module Metasploit
2
+  module Framework
3
+    module Core
4
+
5
+    end
6
+  end
7
+end

+ 19
- 0
lib/metasploit/framework/core/version.rb View File

@@ -0,0 +1,19 @@
1
+require 'metasploit/framework/version'
2
+
3
+module Metasploit
4
+  module Framework
5
+    # @note This is a lie.  The core libraries are not semantically versioned.  This is currently just linked to the
6
+    #   Metasploit::Framework::Version, which is also not semantically versioned.
7
+    module Core
8
+      module Version
9
+        MAJOR = Metasploit::Framework::Version::MAJOR
10
+        MINOR = Metasploit::Framework::Version::MINOR
11
+        PATCH = Metasploit::Framework::Version::PATCH
12
+        PRERELEASE = Metasploit::Framework::Version::PRERELEASE
13
+      end
14
+
15
+      VERSION = Metasploit::Framework::VERSION
16
+      GEM_VERSION = Gem::Version.new(Metasploit::Framework::GEM_VERSION)
17
+    end
18
+  end
19
+end

+ 105
- 0
lib/metasploit/framework/credential.rb View File

@@ -0,0 +1,105 @@
1
+require 'active_model'
2
+
3
+module Metasploit
4
+  module Framework
5
+    # This class provides an in-memory representation of a conceptual Credential
6
+    #
7
+    # It contains the public, private, and realm if any.
8
+    class Credential
9
+      include ActiveModel::Validations
10
+
11
+      # @!attribute paired
12
+      #   @return [Boolean] Whether BOTH a public and private are required
13
+      #     (defaults to `true`)
14
+      attr_accessor :paired
15
+      # @!attribute parent
16
+      #   @return [Object] the parent object that had .to_credential called on it to create this object
17
+      attr_accessor :parent
18
+      # @!attribute private
19
+      #   The private credential component (e.g. username)
20
+      #
21
+      #   @return [String] if {#paired} is `true` or {#private} is `nil`
22
+      #   @return [String, nil] if {#paired} is `false` or {#private} is not `nil`.
23
+      attr_accessor :private
24
+      # @!attribute private_type
25
+      #   The type of private credential this object represents, e.g. a
26
+      #   password or an NTLM hash.
27
+      #
28
+      #   @return [String]
29
+      attr_accessor :private_type
30
+      # @!attribute public
31
+      #   The public credential component (e.g. password)
32
+      #
33
+      #   @return [String] if {#paired} is `true` or {#public} is `nil`
34
+      #   @return [String, nil] if {#paired} is `false` or {#public} is not `nil`.
35
+      attr_accessor :public
36
+      # @!attribute realm
37
+      #   @return [String,nil] The realm credential component (e.g domain name)
38
+      attr_accessor :realm
39
+      # @!attribute realm
40
+      #   @return [String,nil] The type of {#realm}
41
+      attr_accessor :realm_key
42
+
43
+      validates :paired,
44
+        inclusion: { in: [true, false] }
45
+
46
+      # If we have no public we MUST have a private (e.g. SNMP Community String)
47
+      validates :private,
48
+        exclusion: { in: [nil] },
49
+        if: "public.nil? or paired"
50
+
51
+      # These values should be #demodularized from subclasses of
52
+      # `Metasploit::Credential::Private`
53
+      validates :private_type,
54
+        inclusion: { in: [ :password, :ntlm_hash, :ssh_key ] },
55
+        if: "private_type.present?"
56
+
57
+      # If we have no private we MUST have a public
58
+      validates :public,
59
+        presence: true,
60
+        if: "private.nil? or paired"
61
+
62
+      # @param attributes [Hash{Symbol => String,nil}]
63
+      def initialize(attributes={})
64
+        attributes.each do |attribute, value|
65
+          public_send("#{attribute}=", value)
66
+        end
67
+
68
+        self.paired = true if self.paired.nil?
69
+      end
70
+
71
+      def inspect
72
+        "#<#{self.class} \"#{self}\" >"
73
+      end
74
+
75
+      def to_s
76
+        if realm && realm_key == Metasploit::Model::Realm::Key::ACTIVE_DIRECTORY_DOMAIN
77
+          "#{self.realm}\\#{self.public}:#{self.private}"
78
+        else
79
+          "#{self.public}:#{self.private}#{at_realm}"
80
+        end
81
+      end
82
+
83
+      def ==(other)
84
+        other.respond_to?(:public) && other.public == self.public &&
85
+        other.respond_to?(:private) && other.private == self.private &&
86
+        other.respond_to?(:realm) && other.realm == self.realm
87
+      end
88
+
89
+      def to_credential
90
+        self.parent = self
91
+        self        
92
+      end
93
+
94
+      private
95
+
96
+      def at_realm
97
+        if self.realm.present?
98
+          "@#{self.realm}"
99
+        else
100
+          ""
101
+        end
102
+      end
103
+    end
104
+  end
105
+end

+ 148
- 0
lib/metasploit/framework/credential_collection.rb View File

@@ -0,0 +1,148 @@
1
+require 'metasploit/framework/credential'
2
+
3
+class Metasploit::Framework::CredentialCollection
4
+
5
+  # @!attribute blank_passwords
6
+  #   Whether each username should be tried with a blank password
7
+  #   @return [Boolean]
8
+  attr_accessor :blank_passwords
9
+
10
+  # @!attribute pass_file
11
+  #   Path to a file containing passwords, one per line
12
+  #   @return [String]
13
+  attr_accessor :pass_file
14
+
15
+  # @!attribute password
16
+  #   @return [String]
17
+  attr_accessor :password
18
+
19
+  # @!attribute prepended_creds
20
+  #   List of credentials to be tried before any others
21
+  #
22
+  #   @see #prepend_cred
23
+  #   @return [Array<Credential>]
24
+  attr_accessor :prepended_creds
25
+
26
+  # @!attribute realm
27
+  #   @return [String]
28
+  attr_accessor :realm
29
+
30
+  # @!attribute user_as_pass
31
+  #   Whether each username should be tried as a password for that user
32
+  #   @return [Boolean]
33
+  attr_accessor :user_as_pass
34
+
35
+  # @!attribute user_file
36
+  #   Path to a file containing usernames, one per line
37
+  #   @return [String]
38
+  attr_accessor :user_file
39
+
40
+  # @!attribute username
41
+  #   @return [String]
42
+  attr_accessor :username
43
+
44
+  # @!attribute userpass_file
45
+  #   Path to a file containing usernames and passwords separated by a space,
46
+  #   one pair per line
47
+  #   @return [String]
48
+  attr_accessor :userpass_file
49
+
50
+  # @option opts [Boolean] :blank_passwords See {#blank_passwords}
51
+  # @option opts [String] :pass_file See {#pass_file}
52
+  # @option opts [String] :password See {#password}
53
+  # @option opts [Array<Credential>] :prepended_creds ([]) See {#prepended_creds}
54
+  # @option opts [Boolean] :user_as_pass See {#user_as_pass}
55
+  # @option opts [String] :user_file See {#user_file}
56
+  # @option opts [String] :username See {#username}
57
+  # @option opts [String] :userpass_file See {#userpass_file}
58
+  def initialize(opts = {})
59
+    opts.each do |attribute, value|
60
+      public_send("#{attribute}=", value)
61
+    end
62
+    self.prepended_creds ||= []
63
+  end
64
+
65
+  # Add {Credential credentials} that will be yielded by {#each}
66
+  #
67
+  # @see prepended_creds
68
+  # @param cred [Credential]
69
+  # @return [self]
70
+  def prepend_cred(cred)
71
+    prepended_creds.unshift cred
72
+    self
73
+  end
74
+
75
+  # Combines all the provided credential sources into a stream of {Credential}
76
+  # objects, yielding them one at a time
77
+  #
78
+  # @yieldparam credential [Metasploit::Framework::Credential]
79
+  # @return [void]
80
+  def each
81
+    if pass_file.present?
82
+      pass_fd = File.open(pass_file, 'r:binary')
83
+    end
84
+
85
+    prepended_creds.each { |c| yield c }
86
+
87
+    if username.present?
88
+      if password.present?
89
+        yield Metasploit::Framework::Credential.new(public: username, private: password, realm: realm)
90
+      end
91
+      if user_as_pass
92
+        yield Metasploit::Framework::Credential.new(public: username, private: username, realm: realm)
93
+      end
94
+      if blank_passwords
95
+        yield Metasploit::Framework::Credential.new(public: username, private: "", realm: realm)
96
+      end
97
+      if pass_fd
98
+        pass_fd.each_line do |pass_from_file|
99
+          pass_from_file.chomp!
100
+          yield Metasploit::Framework::Credential.new(public: username, private: pass_from_file, realm: realm)
101
+        end
102
+        pass_fd.seek(0)
103
+      end
104
+    end
105
+
106
+    if user_file.present?
107
+      File.open(user_file, 'r:binary') do |user_fd|
108
+        user_fd.each_line do |user_from_file|
109
+          user_from_file.chomp!
110
+          if password
111
+            yield Metasploit::Framework::Credential.new(public: user_from_file, private: password, realm: realm)
112
+          end
113
+          if user_as_pass
114
+            yield Metasploit::Framework::Credential.new(public: user_from_file, private: user_from_file, realm: realm)
115
+          end
116
+          if blank_passwords
117
+            yield Metasploit::Framework::Credential.new(public: user_from_file, private: "", realm: realm)
118
+          end
119
+          if pass_fd
120
+            pass_fd.each_line do |pass_from_file|
121
+              pass_from_file.chomp!
122
+              yield Metasploit::Framework::Credential.new(public: user_from_file, private: pass_from_file, realm: realm)
123
+            end
124
+            pass_fd.seek(0)
125
+          end
126
+        end
127
+      end
128
+    end
129
+
130
+    if userpass_file.present?
131
+      File.open(userpass_file, 'r:binary') do |userpass_fd|
132
+        userpass_fd.each_line do |line|
133
+          user, pass = line.split(" ", 2)
134
+          if pass.blank?
135
+            pass = ''
136
+          else
137
+            pass.chomp!
138
+          end
139
+          yield Metasploit::Framework::Credential.new(public: user, private: pass, realm: realm)
140
+        end
141
+      end
142
+    end
143
+
144
+  ensure
145
+    pass_fd.close if pass_fd && !pass_fd.closed?
146
+  end
147
+
148
+end

+ 1
- 1
lib/metasploit/framework/database.rb View File

@@ -8,7 +8,7 @@ module Metasploit
8 8
       end
9 9
 
10 10
       def self.configurations_pathname
11
-        Metasploit::Framework.root.join('config', 'database.yml')
11
+        Metasploit::Framework::Application.paths['config/database'].first
12 12
       end
13 13
     end
14 14
   end

+ 19
- 0
lib/metasploit/framework/engine.rb View File

@@ -0,0 +1,19 @@
1
+#
2
+# Gems
3
+#
4
+
5
+require 'rails/engine'
6
+
7
+#
8
+# Project
9
+#
10
+
11
+require 'metasploit/framework/common_engine'
12
+
13
+module Metasploit
14
+  module Framework
15
+    class Engine < Rails::Engine
16
+      include Metasploit::Framework::CommonEngine
17
+    end
18
+  end
19
+end

+ 276
- 0
lib/metasploit/framework/ftp/client.rb View File

@@ -0,0 +1,276 @@
1
+require 'metasploit/framework/tcp/client'
2
+
3
+module Metasploit
4
+  module Framework
5
+    module Ftp
6
+      module Client
7
+        include Metasploit::Framework::Tcp::Client
8
+
9
+        #
10
+        # This method establishes an FTP connection to host and port specified by
11
+        # the 'rhost' and 'rport' methods. After connecting, the banner
12
+        # message is read in and stored in the 'banner' attribute.
13
+        #
14
+        def connect(global = true)
15
+          fd = super(global)
16
+
17
+          @ftpbuff = '' unless @ftpbuff
18
+
19
+          # Wait for a banner to arrive...
20
+          self.banner = recv_ftp_resp(fd)
21
+
22
+          # Return the file descriptor to the caller
23
+          fd
24
+        end
25
+
26
+        #
27
+        # This method handles establishing datasocket for data channel
28
+        #
29
+        def data_connect(mode = nil, nsock = self.sock)
30
+          if mode
31
+            res = send_cmd([ 'TYPE' , mode ], true, nsock)
32
+            return nil if not res =~ /^200/
33
+          end
34
+
35
+          # force datasocket to renegotiate
36
+          self.datasocket.shutdown if self.datasocket != nil
37
+
38
+          res = send_cmd(['PASV'], true, nsock)
39
+          return nil if not res =~ /^227/
40
+
41
+          # 227 Entering Passive Mode (127,0,0,1,196,5)
42
+          if res =~ /\((\d+)\,(\d+),(\d+),(\d+),(\d+),(\d+)/
43
+            # convert port to FTP syntax
44
+            datahost = "#{$1}.#{$2}.#{$3}.#{$4}"
45
+            dataport = ($5.to_i * 256) + $6.to_i
46
+            self.datasocket = Rex::Socket::Tcp.create('PeerHost' => datahost, 'PeerPort' => dataport)
47
+          end
48
+          self.datasocket
49
+        end
50
+
51
+        #
52
+        # This method handles disconnecting our data channel
53
+        #
54
+        def data_disconnect
55
+          self.datasocket.shutdown
56
+          self.datasocket = nil
57
+        end
58
+
59
+        #
60
+        # Connect and login to the remote FTP server using the credentials
61
+        # that have been supplied in the exploit options.
62
+        #
63
+        def connect_login(user,pass,global = true)
64
+          ftpsock = connect(global)
65
+
66
+          if !(user and pass)
67
+            return false
68
+          end
69
+
70
+          res = send_user(user, ftpsock)
71
+
72
+          if (res !~ /^(331|2)/)
73
+            return false
74
+          end
75
+
76
+          if (pass)
77
+            res = send_pass(pass, ftpsock)
78
+            if (res !~ /^2/)
79
+              return false
80
+            end
81
+          end
82
+
83
+          return true
84
+        end
85
+
86
+        #
87
+        # This method logs in as the supplied user by transmitting the FTP
88
+        # 'USER <user>' command.
89
+        #
90
+        def send_user(user, nsock = self.sock)
91
+          raw_send("USER #{user}\r\n", nsock)
92
+          recv_ftp_resp(nsock)
93
+        end
94
+
95
+        #
96
+        # This method completes user authentication by sending the supplied
97
+        # password using the FTP 'PASS <pass>' command.
98
+        #
99
+        def send_pass(pass, nsock = self.sock)
100
+          raw_send("PASS #{pass}\r\n", nsock)
101
+          recv_ftp_resp(nsock)
102
+        end
103
+
104
+        #
105
+        # This method sends a QUIT command.
106
+        #
107
+        def send_quit(nsock = self.sock)
108
+          raw_send("QUIT\r\n", nsock)
109
+          recv_ftp_resp(nsock)
110
+        end
111
+
112
+        #
113
+        # This method sends one command with zero or more parameters
114
+        #
115
+        def send_cmd(args, recv = true, nsock = self.sock)
116
+          cmd = args.join(" ") + "\r\n"
117
+          ret = raw_send(cmd, nsock)
118
+          if (recv)
119
+            return recv_ftp_resp(nsock)
120
+          end
121
+          return ret
122
+        end
123
+
124
+        #
125
+        # This method transmits the command in args and receives / uploads DATA via data channel
126
+        # For commands not needing data, it will fall through to the original send_cmd
127
+        #
128
+        # For commands that send data only, the return will be the server response.
129
+        # For commands returning both data and a server response, an array will be returned.
130
+        #
131
+        # NOTE: This function always waits for a response from the server.
132
+        #
133
+        def send_cmd_data(args, data, mode = 'a', nsock = self.sock)
134
+          type = nil
135
+          # implement some aliases for various commands
136
+          if (args[0] =~ /^DIR$/i || args[0] =~ /^LS$/i)
137
+            # TODO || args[0] =~ /^MDIR$/i || args[0] =~ /^MLS$/i
138
+            args[0] = "LIST"
139
+            type = "get"
140
+          elsif (args[0] =~ /^GET$/i)
141
+            args[0] = "RETR"
142
+            type = "get"
143
+          elsif (args[0] =~ /^PUT$/i)
144
+            args[0] = "STOR"
145
+            type = "put"
146
+          end
147
+
148
+          # fall back if it's not a supported data command
149
+          if not type
150
+            return send_cmd(args, true, nsock)
151
+          end
152
+
153
+          # Set the transfer mode and connect to the remove server
154
+          return nil if not data_connect(mode)
155
+
156
+          # Our pending command should have got a connection now.
157
+          res = send_cmd(args, true, nsock)
158
+          # make sure could open port
159
+          return nil unless res =~ /^(150|125) /
160
+
161
+          # dispatch to the proper method
162
+          if (type == "get")
163
+            # failed listings jsut disconnect..
164
+            begin
165
+              data = self.datasocket.get_once(-1, ftp_timeout)
166
+            rescue ::EOFError
167
+              data = nil
168
+            end
169
+          else
170
+            sent = self.datasocket.put(data)
171
+          end
172
+
173
+          # close data channel so command channel updates
174
+          data_disconnect
175
+
176
+          # get status of transfer
177
+          ret = nil
178
+          if (type == "get")
179
+            ret = recv_ftp_resp(nsock)
180
+            ret = [ ret, data ]
181
+          else
182
+            ret = recv_ftp_resp(nsock)
183
+          end
184
+
185
+          ret
186
+        end
187
+
188
+        #
189
+        # This method transmits a FTP command and waits for a response.  If one is
190
+        # received, it is returned to the caller.
191
+        #
192
+        def raw_send_recv(cmd, nsock = self.sock)
193
+          nsock.put(cmd)
194
+          nsock.get_once(-1, ftp_timeout)
195
+        end
196
+
197
+        #
198
+        # This method reads an FTP response based on FTP continuation stuff
199
+        #
200
+        def recv_ftp_resp(nsock = self.sock)
201
+          found_end = false
202
+          resp = ""
203
+          left = ""
204
+          if !@ftpbuff.empty?
205
+            left << @ftpbuff
206
+            @ftpbuff = ""
207
+          end
208
+          while true
209
+            data = nsock.get_once(-1, ftp_timeout)
210
+            if not data
211
+              @ftpbuff << resp
212
+              @ftpbuff << left
213
+              return data
214
+            end
215
+
216
+            got = left + data
217
+            left = ""
218
+
219
+            # handle the end w/o newline case
220
+            enlidx = got.rindex(0x0a.chr)
221
+            if enlidx != (got.length-1)
222
+              if not enlidx
223
+                left << got
224
+                next
225
+              else
226
+                left << got.slice!((enlidx+1)..got.length)
227
+              end
228
+            end
229
+
230
+            # split into lines
231
+            rarr = got.split(/\r?\n/)
232
+            rarr.each do |ln|
233
+              if not found_end
234
+                resp << ln
235
+                resp << "\r\n"
236
+                if ln.length > 3 and ln[3,1] == ' '
237
+                  found_end = true
238
+                end
239
+              else
240
+                left << ln
241
+                left << "\r\n"
242
+              end
243
+            end
244
+            if found_end
245
+              @ftpbuff << left
246
+              return resp
247
+            end
248
+          end
249
+        end
250
+
251
+        #
252
+        # This method transmits a FTP command and does not wait for a response
253
+        #
254
+        def raw_send(cmd, nsock = self.sock)
255
+          nsock.put(cmd)
256
+        end
257
+
258
+        def ftp_timeout
259
+          raise NotImplementedError
260
+        end
261
+
262
+
263
+
264
+        protected
265
+
266
+        #
267
+        # This attribute holds the banner that was read in after a successful call
268
+        # to connect or connect_login.
269
+        #
270
+        attr_accessor :banner, :datasocket
271
+
272
+
273
+      end
274
+    end
275
+  end
276
+end

+ 272
- 0
lib/metasploit/framework/jtr/cracker.rb View File

@@ -0,0 +1,272 @@
1
+module Metasploit
2
+  module Framework
3
+    module JtR
4
+
5
+      class JohnNotFoundError < StandardError
6
+      end
7
+
8
+      class Cracker
9
+        include ActiveModel::Validations
10
+
11
+        # @!attribute config
12
+        #   @return [String] The path to an optional config file for John to use
13
+        attr_accessor :config
14
+
15
+        # @!attribute format
16
+        #   @return [String] The hash format to try
17
+        attr_accessor :format
18
+
19
+        # @!attribute hash_path
20
+        #   @return [String] The path to the file containing the hashes
21
+        attr_accessor :hash_path
22
+
23
+        # @!attribute incremental
24
+        #   @return [String] The incremental mode to use
25
+        attr_accessor :incremental
26
+
27
+        # @!attribute john_path
28
+        #   This attribute allows the user to specify a john binary to use.
29
+        #   If not supplied, the Cracker will search the PATH for a suitable john binary
30
+        #   and finally fall back to the pre-compiled versions shipped with Metasploit.
31
+        #
32
+        #   @return [String] The file path to an alternative John binary to use
33
+        attr_accessor :john_path
34
+
35
+        # @!attribute max_runtime
36
+        #   @return [Fixnum] An optional maximum duration of the cracking attempt in seconds
37
+        attr_accessor :max_runtime
38
+
39
+        # @!attribute pot
40
+        #   @return [String] The file path to an alternative John pot file to use
41
+        attr_accessor :pot
42
+
43
+        # @!attribute rules
44
+        #   @return [String] The wordlist mangling rules to use inside John
45
+        attr_accessor :rules
46
+
47
+        # @!attribute wordlist
48
+        #   @return [String] The file path to the wordlist to use
49
+        attr_accessor :wordlist
50
+
51
+        validates :config, :'Metasploit::Framework::File_path' => true, if: 'config.present?'
52
+
53
+        validates :hash_path, :'Metasploit::Framework::File_path' => true, if: 'hash_path.present?'
54
+
55
+        validates :john_path, :'Metasploit::Framework::Executable_path' => true, if: 'john_path.present?'
56
+
57
+        validates :pot, :'Metasploit::Framework::File_path' => true, if: 'pot.present?'
58
+
59
+        validates :max_runtime,
60
+                  numericality: {
61
+                      only_integer:             true,
62
+                      greater_than_or_equal_to: 0
63
+                  }, if: 'max_runtime.present?'
64
+
65
+        validates :wordlist, :'Metasploit::Framework::File_path' => true, if: 'wordlist.present?'
66
+
67
+        # @param attributes [Hash{Symbol => String,nil}]
68
+        def initialize(attributes={})
69
+          attributes.each do |attribute, value|
70
+            public_send("#{attribute}=", value)
71
+          end
72
+        end
73
+
74
+        # This method follows a decision tree to determine the path
75
+        # to the John the Ripper binary we should use.
76
+        #
77
+        # @return [NilClass] if a binary path could not be found
78
+        # @return [String] the path to the selected JtR binary
79
+        def binary_path
80
+          # Always prefer a manually entered path
81
+          if john_path && ::File.file?(john_path)
82
+            bin_path = john_path
83
+          else
84
+            # Look in the Environment PATH for the john binary
85
+            path = Rex::FileUtils.find_full_path("john") ||
86
+                Rex::FileUtils.find_full_path("john.exe")
87
+
88
+            if path && ::File.file?(path)
89
+              bin_path = path
90
+            else
91
+              # If we can't find john anywhere else, look at our precompiled binaries
92
+              bin_path = select_shipped_binary
93
+            end
94
+          end
95
+          raise JohnNotFoundError, 'No suitable John binary was found on the system' if bin_path.blank?
96
+          bin_path
97
+        end
98
+
99
+        # This method runs the command from {#crack_command} and yields each line of output.
100
+        #
101
+        # @yield [String] a line of output from the john command
102
+        # @return [void]
103
+        def crack
104
+          ::IO.popen(crack_command, "rb") do |fd|
105
+            fd.each_line do |line|
106
+              yield line
107
+            end
108
+          end
109
+        end
110
+
111
+        # This method builds an array for the command to actually run the cracker.
112
+        # It builds the command from all of the attributes on the class.
113
+        #
114
+        # @raise [JohnNotFoundError] if a suitable John binary was never found
115
+        # @return [Array] An array set up for {::IO.popen} to use
116
+        def crack_command
117
+          cmd_string = binary_path
118
+          cmd = [ cmd_string,  '--session=' + john_session_id, '--nolog' ]
119
+
120
+          if config.present?
121
+            cmd << ( "--config=" + config )
122
+          else
123
+            cmd << ( "--config=" + john_config_file )
124
+          end
125
+
126
+          if pot.present?
127
+            cmd << ( "--pot=" + pot )
128
+          else
129
+            cmd << ( "--pot=" + john_pot_file)
130
+          end
131
+
132
+          if format.present?
133
+            cmd << ( "--format=" + format )
134
+          end
135
+
136
+          if wordlist.present?
137
+            cmd << ( "--wordlist=" + wordlist )
138
+          end
139
+
140
+          if incremental.present?
141
+            cmd << ( "--incremental=" + incremental )
142
+          end
143
+
144
+          if rules.present?
145
+            cmd << ( "--rules=" + rules )
146
+          end
147
+
148
+          if max_runtime.present?
149
+            cmd << ( "--max-run-time=" + max_runtime.to_s)
150
+          end
151
+
152
+          cmd << hash_path
153
+        end
154
+
155
+        # This runs the show command in john and yields cracked passwords.
156
+        #
157
+        # @yield [String] the output lines from the command
158
+        # @return [void]
159
+        def each_cracked_password
160
+          ::IO.popen(show_command, "rb") do |fd|
161
+            fd.each_line do |line|
162
+              yield line
163
+            end
164
+          end
165
+        end
166
+
167
+        # This method returns the path to a default john.conf file.
168
+        #
169
+        # @return [String] the path to the default john.conf file
170
+        def john_config_file
171
+          ::File.join( ::Msf::Config.data_directory, "john", "confs", "john.conf" )
172
+        end
173
+
174
+        # This method returns the path to a default john.pot file.
175
+        #
176
+        # @return [String] the path to the default john.pot file
177
+        def john_pot_file
178
+          ::File.join( ::Msf::Config.config_directory, "john.pot" )
179
+        end
180
+
181
+        # This method is a getter for a random Session ID for John.
182
+        # It allows us to dinstiguish between cracking sessions.
183
+        #
184
+        # @ return [String] the Session ID to use
185
+        def john_session_id
186
+          @session_id ||= ::Rex::Text.rand_text_alphanumeric(8)
187
+        end
188
+
189
+        # This method builds the command to show the cracked passwords.
190
+        #
191
+        # @raise [JohnNotFoundError] if a suitable John binary was never found
192
+        # @return [Array] An array set up for {::IO.popen} to use
193
+        def show_command
194
+          cmd_string = binary_path
195
+
196
+          pot_file = pot || john_pot_file
197
+          cmd = [cmd_string, "--show", "--pot=#{pot_file}", "--format=#{format}" ]
198
+
199
+          if config
200
+            cmd << "--config=#{config}"
201
+          else
202
+            cmd << ( "--config=" + john_config_file )
203
+          end
204
+
205
+          cmd << hash_path
206
+        end
207
+
208
+        private
209
+
210
+        # This method tries to identify the correct version of the pre-shipped
211
+        # JtR binaries to use based on the platform.
212
+        #
213
+        # @return [NilClass] if the correct binary could not be determined
214
+        # @return [String] the path to the selected binary
215
+        def select_shipped_binary
216
+          cpuinfo_base = ::File.join(Msf::Config.data_directory, "cpuinfo")
217
+          run_path = nil
218
+          if File.directory?(cpuinfo_base)
219
+            data = nil
220
+
221
+            case ::RUBY_PLATFORM
222
+              when /mingw|cygwin|mswin/
223
+                fname = "#{cpuinfo_base}/cpuinfo.exe"
224
+                if File.exists?(fname) and File.executable?(fname)
225
+                  data = %x{"#{fname}"} rescue nil
226
+                end
227
+                case data
228
+                  when /sse2/
229
+                    run_path ||= ::File.join(Msf::Config.data_directory, "john", "run.win32.sse2", "john.exe")
230
+                  when /mmx/
231
+                    run_path ||= ::File.join(Msf::Config.data_directory, "john", "run.win32.mmx", "john.exe")
232
+                  else
233
+                    run_path ||= ::File.join(Msf::Config.data_directory, "john", "run.win32.any", "john.exe")
234
+                end
235
+              when /x86_64-linux/
236
+                fname = "#{cpuinfo_base}/cpuinfo.ia64.bin"
237
+                if File.exists? fname
238
+                  ::FileUtils.chmod(0755, fname) rescue nil
239
+                  data = %x{"#{fname}"} rescue nil
240
+                end
241
+                case data
242
+                  when /mmx/
243
+                    run_path ||= ::File.join(Msf::Config.data_directory, "john", "run.linux.x64.mmx", "john")
244
+                  else
245
+                    run_path ||= ::File.join(Msf::Config.data_directory, "john", "run.linux.x86.any", "john")
246
+                end
247
+              when /i[\d]86-linux/
248
+                fname = "#{cpuinfo_base}/cpuinfo.ia32.bin"
249
+                if File.exists? fname
250
+                  ::FileUtils.chmod(0755, fname) rescue nil
251
+                  data = %x{"#{fname}"} rescue nil
252
+                end
253
+                case data
254
+                  when /sse2/
255
+                    run_path ||= ::File.join(Msf::Config.data_directory, "john", "run.linux.x86.sse2", "john")
256
+                  when /mmx/
257
+                    run_path ||= ::File.join(Msf::Config.data_directory, "john", "run.linux.x86.mmx", "john")
258
+                  else
259
+                    run_path ||= ::File.join(Msf::Config.data_directory, "john", "run.linux.x86.any", "john")
260
+                end
261
+            end
262
+          end
263
+          run_path
264
+        end
265
+
266
+
267
+
268
+      end
269
+
270
+    end
271
+  end
272
+end

+ 20
- 0
lib/metasploit/framework/jtr/invalid_wordlist.rb View File

@@ -0,0 +1,20 @@
1
+module Metasploit
2
+  module Framework
3
+    module JtR
4
+
5
+      # This class is the generic Exception raised by a {Wordlist} when
6
+      # it fails validation. It rolls up all validation errors into a
7
+      # single exception so that all errors can be dealt with at once.
8
+      class InvalidWordlist < StandardError
9
+        attr_reader :model
10
+
11
+        def initialize(model)
12
+          @model = model
13
+
14
+          errors = @model.errors.full_messages.join(', ')
15
+          super(errors)
16
+        end
17
+      end
18
+    end
19
+  end
20
+end

+ 429
- 0
lib/metasploit/framework/jtr/wordlist.rb View File

@@ -0,0 +1,429 @@
1
+require 'metasploit/framework/jtr/invalid_wordlist'
2
+
3
+module Metasploit
4
+  module Framework
5
+    module JtR
6
+
7
+      class Wordlist
8
+        include ActiveModel::Validations
9
+
10
+        # A mapping of the mutation substitution rules
11
+        MUTATIONS = {
12
+            '@' => 'a',
13
+            '0' => 'o',
14
+            '3' => 'e',
15
+            '$' => 's',
16
+            '7' => 't',
17
+            '1' => 'l',
18
+            '5' => 's'
19
+        }
20
+
21
+        # @!attribute appenders
22
+        #   @return [Array] an array of strings to append to each word
23
+        attr_accessor :appenders
24
+
25
+        # @!attribute custom_wordlist
26
+        #   @return [String] the path to a custom wordlist file to include
27
+        attr_accessor :custom_wordlist
28
+
29
+        # @!attribute mutate
30
+        #   @return [TrueClass] if you want each word mutated as it is added
31
+        #   @return [FalseClass] if you do not want each word mutated
32
+        attr