metasploit_data_models 0.23.1 → 0.23.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/models/mdm/host.rb +42 -33
- data/app/models/mdm/loot.rb +9 -0
- data/app/models/mdm/module/detail.rb +28 -7
- data/app/models/mdm/module/ref.rb +4 -4
- data/app/models/mdm/ref.rb +5 -5
- data/app/models/mdm/session.rb +18 -1
- data/app/models/mdm/user.rb +13 -0
- data/app/models/mdm/vuln.rb +16 -7
- data/app/models/mdm/workspace.rb +16 -8
- data/app/models/metasploit_data_models/automatic_exploitation.rb +5 -0
- data/app/models/metasploit_data_models/automatic_exploitation/match.rb +42 -0
- data/app/models/metasploit_data_models/automatic_exploitation/match_result.rb +40 -0
- data/app/models/metasploit_data_models/automatic_exploitation/match_set.rb +30 -0
- data/app/models/metasploit_data_models/automatic_exploitation/run.rb +27 -0
- data/app/models/metasploit_data_models/module_run.rb +213 -0
- data/app/validators/password_is_strong_validator.rb +5 -5
- data/db/migrate/20131002004641_create_automatic_exploitation_matches.rb +13 -0
- data/db/migrate/20131002164449_create_automatic_exploitation_match_sets.rb +12 -0
- data/db/migrate/20131008213344_create_automatic_exploitation_runs.rb +11 -0
- data/db/migrate/20131011184338_module_detail_on_automatic_exploitation_match.rb +10 -0
- data/db/migrate/20131017150735_create_automatic_exploitation_match_results.rb +11 -0
- data/db/migrate/20131021185657_make_match_polymorphic.rb +11 -0
- data/db/migrate/20150219173821_create_module_runs.rb +23 -0
- data/db/migrate/20150219215039_add_module_run_to_session.rb +8 -0
- data/db/migrate/20150226151459_add_module_run_fk_to_loot.rb +8 -0
- data/db/migrate/20150312155312_add_module_full_name_to_match.rb +6 -0
- data/db/migrate/20150326183742_add_missing_ae_indices.rb +13 -0
- data/lib/metasploit_data_models/version.rb +1 -1
- data/spec/app/models/mdm/host_spec.rb +28 -27
- data/spec/app/models/mdm/loot_spec.rb +1 -0
- data/spec/app/models/mdm/module/detail_spec.rb +2 -2
- data/spec/app/models/mdm/session_spec.rb +21 -18
- data/spec/app/models/mdm/vuln_spec.rb +9 -10
- data/spec/app/models/metasploit_data_models/automatic_exploitation/match_result_spec.rb +88 -0
- data/spec/app/models/metasploit_data_models/automatic_exploitation/match_set_spec.rb +48 -0
- data/spec/app/models/metasploit_data_models/automatic_exploitation/match_spec.rb +25 -0
- data/spec/app/models/metasploit_data_models/automatic_exploitation/run_spec.rb +40 -0
- data/spec/app/models/metasploit_data_models/module_run_spec.rb +136 -0
- data/spec/dummy/db/structure.sql +369 -2
- data/spec/factories/mdm/module/details.rb +21 -21
- data/spec/factories/metasploit_data_models/automatic_exploitation/match_results.rb +7 -0
- data/spec/factories/metasploit_data_models/automatic_exploitation/match_sets.rb +8 -0
- data/spec/factories/metasploit_data_models/automatic_exploitation/matches.rb +6 -0
- data/spec/factories/metasploit_data_models/automatic_exploitation/runs.rb +6 -0
- data/spec/factories/module_runs.rb +40 -0
- metadata +30 -172
data/app/models/mdm/workspace.rb
CHANGED
@@ -15,6 +15,14 @@ class Mdm::Workspace < ActiveRecord::Base
|
|
15
15
|
# Relations
|
16
16
|
#
|
17
17
|
|
18
|
+
has_many :automatic_exploitation_runs,
|
19
|
+
class_name: 'MetasploitDataModels::AutomaticExploitation::Run',
|
20
|
+
inverse_of: :workspace
|
21
|
+
|
22
|
+
has_many :automatic_exploitation_match_sets,
|
23
|
+
class_name: 'MetasploitDataModels::AutomaticExploitation:MatchSet',
|
24
|
+
inverse_of: :workspace
|
25
|
+
|
18
26
|
has_many :creds, :through => :services, :class_name => 'Mdm::Cred'
|
19
27
|
has_many :events, :class_name => 'Mdm::Event'
|
20
28
|
has_many :hosts, :dependent => :destroy, :class_name => 'Mdm::Host'
|
@@ -58,7 +66,7 @@ class Mdm::Workspace < ActiveRecord::Base
|
|
58
66
|
allowed = false
|
59
67
|
boundaries.each do |boundary_range|
|
60
68
|
ok_range = Rex::Socket::RangeWalker.new(boundary)
|
61
|
-
allowed
|
69
|
+
allowed = true if ok_range.include_range? given_range
|
62
70
|
end
|
63
71
|
return allowed
|
64
72
|
end
|
@@ -69,9 +77,9 @@ class Mdm::Workspace < ActiveRecord::Base
|
|
69
77
|
|
70
78
|
def creds
|
71
79
|
Mdm::Cred.find(
|
72
|
-
|
73
|
-
|
74
|
-
|
80
|
+
:all,
|
81
|
+
:include => {:service => :host},
|
82
|
+
:conditions => ["hosts.workspace_id = ?", self.id]
|
75
83
|
)
|
76
84
|
end
|
77
85
|
|
@@ -101,9 +109,9 @@ class Mdm::Workspace < ActiveRecord::Base
|
|
101
109
|
|
102
110
|
def host_tags
|
103
111
|
Mdm::Tag.find(
|
104
|
-
|
105
|
-
|
106
|
-
|
112
|
+
:all,
|
113
|
+
:include => :hosts,
|
114
|
+
:conditions => ["hosts.workspace_id = ?", self.id]
|
107
115
|
)
|
108
116
|
end
|
109
117
|
|
@@ -169,7 +177,7 @@ class Mdm::Workspace < ActiveRecord::Base
|
|
169
177
|
def web_unique_forms(addrs=nil)
|
170
178
|
forms = unique_web_forms
|
171
179
|
if addrs
|
172
|
-
forms.reject!{|f| not addrs.include?(
|
180
|
+
forms.reject! { |f| not addrs.include?(f.web_site.service.host.address) }
|
173
181
|
end
|
174
182
|
forms
|
175
183
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class MetasploitDataModels::AutomaticExploitation::Match < ActiveRecord::Base
|
2
|
+
attr_accessible :match_set_id, :module_fullname
|
3
|
+
|
4
|
+
|
5
|
+
#
|
6
|
+
# Associations
|
7
|
+
#
|
8
|
+
|
9
|
+
# @!attribute matchable
|
10
|
+
# A (polymorphic) "matchable" entity like a {Mdm::Vuln} or {Mdm::Service}
|
11
|
+
#
|
12
|
+
# @return [Mdm::Vuln, Mdm::Service]
|
13
|
+
belongs_to :matchable, polymorphic: true
|
14
|
+
attr_accessible :matchable
|
15
|
+
|
16
|
+
# @!attribute module_detail
|
17
|
+
# The MSF module that this match connects to
|
18
|
+
#
|
19
|
+
# @return [Mdm::Module::Detail]
|
20
|
+
belongs_to :module_detail,
|
21
|
+
class_name: 'Mdm::Module::Detail',
|
22
|
+
foreign_key: :module_fullname,
|
23
|
+
primary_key: :fullname
|
24
|
+
|
25
|
+
# @!attribute match_set
|
26
|
+
# The {MatchSet} this match is part of
|
27
|
+
#
|
28
|
+
# @return [MetasploitDataModels::AutomaticExploitation::MatchResult]
|
29
|
+
has_many :match_results,
|
30
|
+
class_name: 'MetasploitDataModels::AutomaticExploitation::MatchResult',
|
31
|
+
inverse_of: :match
|
32
|
+
|
33
|
+
# @!attribute match_set
|
34
|
+
# The {MatchSet} this match is part of
|
35
|
+
#
|
36
|
+
# @return [MetasploitDataModels::AutomaticExploitation::MatchSet]
|
37
|
+
belongs_to :match_set,
|
38
|
+
class_name: 'MetasploitDataModels::AutomaticExploitation::MatchSet',
|
39
|
+
inverse_of: :matches
|
40
|
+
|
41
|
+
Metasploit::Concern.run(self)
|
42
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class MetasploitDataModels::AutomaticExploitation::MatchResult < ActiveRecord::Base
|
2
|
+
attr_accessible :match_id, :run_id, :state
|
3
|
+
|
4
|
+
# Running associated exploit did NOT create a session
|
5
|
+
FAILED = "failed"
|
6
|
+
# Running associated exploit created a session
|
7
|
+
SUCCEEDED = "succeeded"
|
8
|
+
|
9
|
+
VALID_STATES = [FAILED, SUCCEEDED]
|
10
|
+
|
11
|
+
#
|
12
|
+
# ASSOCIATIONS
|
13
|
+
#
|
14
|
+
|
15
|
+
belongs_to :match,
|
16
|
+
class_name: 'MetasploitDataModels::AutomaticExploitation::Match',
|
17
|
+
inverse_of: :match_results,
|
18
|
+
dependent: :destroy
|
19
|
+
|
20
|
+
belongs_to :run,
|
21
|
+
inverse_of: :match_results,
|
22
|
+
class_name: 'MetasploitDataModels::AutomaticExploitation::Run'
|
23
|
+
|
24
|
+
#
|
25
|
+
# VALIDATIONS
|
26
|
+
#
|
27
|
+
|
28
|
+
# must be present and one of allowable values
|
29
|
+
validates :state,
|
30
|
+
presence: true,
|
31
|
+
inclusion: VALID_STATES
|
32
|
+
|
33
|
+
#
|
34
|
+
# SCOPES
|
35
|
+
#
|
36
|
+
scope :succeeded, lambda { where(state:"succeeded") }
|
37
|
+
scope :failed, lambda { where(state:"failed") }
|
38
|
+
|
39
|
+
Metasploit::Concern.run(self)
|
40
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class MetasploitDataModels::AutomaticExploitation::MatchSet < ActiveRecord::Base
|
2
|
+
attr_accessible :user_id, :workspace_id, :minimum_rank
|
3
|
+
|
4
|
+
has_many :runs,
|
5
|
+
class_name: "MetasploitDataModels::AutomaticExploitation::Run",
|
6
|
+
inverse_of: :match_set
|
7
|
+
|
8
|
+
has_many :matches,
|
9
|
+
class_name: "MetasploitDataModels::AutomaticExploitation::Match",
|
10
|
+
inverse_of: :match_set,
|
11
|
+
dependent: :destroy
|
12
|
+
|
13
|
+
belongs_to :workspace,
|
14
|
+
inverse_of: :automatic_exploitation_match_sets,
|
15
|
+
class_name: "Mdm::Workspace"
|
16
|
+
|
17
|
+
belongs_to :user,
|
18
|
+
inverse_of: :automatic_exploitation_match_sets,
|
19
|
+
class_name: "Mdm::User"
|
20
|
+
|
21
|
+
|
22
|
+
validates :user,
|
23
|
+
presence: true
|
24
|
+
|
25
|
+
validates :workspace,
|
26
|
+
presence: true
|
27
|
+
|
28
|
+
|
29
|
+
Metasploit::Concern.run(self)
|
30
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class MetasploitDataModels::AutomaticExploitation::Run < ActiveRecord::Base
|
2
|
+
attr_accessible :user_id, :workspace_id, :match_set_id
|
3
|
+
|
4
|
+
#
|
5
|
+
# ASSOCIATIONS
|
6
|
+
#
|
7
|
+
has_many :match_results,
|
8
|
+
class_name:'MetasploitDataModels::AutomaticExploitation::MatchResult',
|
9
|
+
inverse_of: :run,
|
10
|
+
dependent: :destroy
|
11
|
+
|
12
|
+
belongs_to :match_set,
|
13
|
+
class_name: 'MetasploitDataModels::AutomaticExploitation::MatchSet',
|
14
|
+
inverse_of: :runs
|
15
|
+
|
16
|
+
belongs_to :user,
|
17
|
+
class_name: "Mdm::User",
|
18
|
+
inverse_of: :automatic_exploitation_runs
|
19
|
+
|
20
|
+
belongs_to :workspace,
|
21
|
+
class_name: "Mdm::Workspace",
|
22
|
+
inverse_of: :automatic_exploitation_runs
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
Metasploit::Concern.run(self)
|
27
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
# {MetasploitDataModels::ModuleRun} holds the record of having launched a piece of Metasploit content.
|
2
|
+
# It has associations to {Mdm::User} for audit purposes, and makes polymorphic associations to things like
|
3
|
+
# {Mdm::Vuln} and {Mdm::Host} for flexible record keeping about activity attacking either specific vulns or just
|
4
|
+
# making mischief on specific remote targets w/out the context of a vuln or even a remote IP service.
|
5
|
+
#
|
6
|
+
# There are also associations to {Mdm::Session} for two use cases: a `spawned_session` is a
|
7
|
+
# session created by the ModuleRun. A `target_session` is a session that the ModuleRun
|
8
|
+
# is acting upon (e.g.) for running a post module.
|
9
|
+
class MetasploitDataModels::ModuleRun < ActiveRecord::Base
|
10
|
+
#
|
11
|
+
# Constants
|
12
|
+
#
|
13
|
+
|
14
|
+
# Marks the module as having successfully run
|
15
|
+
SUCCEED = 'succeeded'
|
16
|
+
# Marks the run as having not run successfully
|
17
|
+
FAIL = 'failed'
|
18
|
+
# Marks the module as having had a runtime error
|
19
|
+
ERROR = 'error'
|
20
|
+
# {ModuleRun} objects will be validated against these statuses
|
21
|
+
VALID_STATUSES = [SUCCEED, FAIL, ERROR]
|
22
|
+
|
23
|
+
|
24
|
+
#
|
25
|
+
# Attributes
|
26
|
+
#
|
27
|
+
|
28
|
+
# @!attribute [rw] attempted_at
|
29
|
+
# The date/time when this module was run
|
30
|
+
# @return [Datetime]
|
31
|
+
|
32
|
+
# @!attribute [rw] fail_detail
|
33
|
+
# Arbitrary information captured by the module to give in-depth reason for failure
|
34
|
+
# @return [String]
|
35
|
+
|
36
|
+
# @!attribute [rw] fail_reason
|
37
|
+
# One of the values of the constants in {Msf::Module::Failure}
|
38
|
+
# @return [String]
|
39
|
+
|
40
|
+
# @!attribute [rw] module_name
|
41
|
+
# The Msf::Module#fullname of the module being run
|
42
|
+
# @return [String]
|
43
|
+
|
44
|
+
# @!attribute [rw] port
|
45
|
+
# The port that the remote host was attacked on, if any
|
46
|
+
# @return [Fixnum]
|
47
|
+
|
48
|
+
# @!attribute [rw] proto
|
49
|
+
# The name of the protocol that the host was attacked on, if any
|
50
|
+
# @return [String]
|
51
|
+
|
52
|
+
# @!attribute [rw] session_id
|
53
|
+
# The {Mdm::Session} that this was run with, in the case of a post module. In exploit modules, this field will
|
54
|
+
# remain null.
|
55
|
+
# @return [Datetime]
|
56
|
+
|
57
|
+
# @!attribute [rw] status
|
58
|
+
# The result of running the module
|
59
|
+
# @return [String]
|
60
|
+
|
61
|
+
# @!attribute [rw] username
|
62
|
+
# The name of the user running this module
|
63
|
+
# @return [String]
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
#
|
68
|
+
# Associations
|
69
|
+
#
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
# @!attribute [rw] loots
|
74
|
+
# The sweet, sweet loot taken by this module_run
|
75
|
+
#
|
76
|
+
# @return [ActiveRecord::Relation<Mdm::Loot>]
|
77
|
+
has_many :loots,
|
78
|
+
class_name: 'Mdm::Loot',
|
79
|
+
inverse_of: :module_run
|
80
|
+
|
81
|
+
# @!attribute [rw] module_detail
|
82
|
+
# The cached module information
|
83
|
+
#
|
84
|
+
# @return [ActiveRecord::Relation<Mdm::Module::Detail>]
|
85
|
+
belongs_to :module_detail,
|
86
|
+
class_name: 'Mdm::Module::Detail',
|
87
|
+
inverse_of: :module_runs,
|
88
|
+
foreign_key: :module_fullname,
|
89
|
+
primary_key: :fullname
|
90
|
+
|
91
|
+
# @!attribute [rw] spawned_session
|
92
|
+
#
|
93
|
+
# The session created by running this module.
|
94
|
+
# Note that this is NOT the session that modules are run on.
|
95
|
+
#
|
96
|
+
# @return [Mdm::Session]
|
97
|
+
has_one :spawned_session,
|
98
|
+
class_name: 'Mdm::Session',
|
99
|
+
inverse_of: :originating_module_run
|
100
|
+
|
101
|
+
|
102
|
+
# @!attribute [rw] target_session
|
103
|
+
#
|
104
|
+
# The session this module was run on, if any.
|
105
|
+
# Note that this is NOT a session created by this module run
|
106
|
+
# of exploit modules.
|
107
|
+
#
|
108
|
+
# @return [Mdm::Session]
|
109
|
+
belongs_to :target_session,
|
110
|
+
class_name: 'Mdm::Session',
|
111
|
+
foreign_key: :session_id,
|
112
|
+
inverse_of: :target_module_runs
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
# @!attribute [rw] trackable
|
117
|
+
#
|
118
|
+
# A polymorphic association that is tracked as being related to this module run.
|
119
|
+
# {Mdm::Host} and {Mdm::Vuln} can each have {ModuleRun} objects.
|
120
|
+
#
|
121
|
+
# @return [Mdm::Host, Mdm::Vuln]
|
122
|
+
belongs_to :trackable, polymorphic: true
|
123
|
+
|
124
|
+
|
125
|
+
# @!attribute [rw] user
|
126
|
+
#
|
127
|
+
# The user that launched this module
|
128
|
+
#
|
129
|
+
# @return [Mdm::User]
|
130
|
+
belongs_to :user,
|
131
|
+
class_name: 'Mdm::User',
|
132
|
+
foreign_key: 'user_id',
|
133
|
+
inverse_of: :module_runs
|
134
|
+
|
135
|
+
|
136
|
+
|
137
|
+
#
|
138
|
+
#
|
139
|
+
# Validations
|
140
|
+
#
|
141
|
+
#
|
142
|
+
|
143
|
+
#
|
144
|
+
# Method Validations
|
145
|
+
#
|
146
|
+
|
147
|
+
|
148
|
+
# spawned_session is only valid for *exploit modules*
|
149
|
+
validate :no_spawned_session_for_non_exploits_except_logins
|
150
|
+
|
151
|
+
# target_session is only valid for *non-exploit modules*
|
152
|
+
validate :no_target_session_for_exploits
|
153
|
+
|
154
|
+
# Can't save without information on what module has run
|
155
|
+
validate :module_information_is_present
|
156
|
+
|
157
|
+
#
|
158
|
+
# Attribute Validations
|
159
|
+
#
|
160
|
+
|
161
|
+
# When the module was run
|
162
|
+
validates :attempted_at,
|
163
|
+
presence: true
|
164
|
+
# Result of running the module
|
165
|
+
validates :status,
|
166
|
+
inclusion: VALID_STATUSES
|
167
|
+
|
168
|
+
# Splits strings formatted like Msf::Module#fullname into components
|
169
|
+
#
|
170
|
+
# @example
|
171
|
+
# module_name = "exploit/windows/multi/mah-rad-exploit"
|
172
|
+
# module_name_components # => ["exploit","windows","multi","mah-rad-exploit"]
|
173
|
+
# @return [Array]
|
174
|
+
def module_name_components
|
175
|
+
module_fullname.split('/')
|
176
|
+
end
|
177
|
+
|
178
|
+
private
|
179
|
+
|
180
|
+
# Mark the object as invalid if there is no associated #module_name or {Mdm::ModuleDetail}
|
181
|
+
# @return [void]
|
182
|
+
def module_information_is_present
|
183
|
+
if module_fullname.blank?
|
184
|
+
errors.add(:base, "module_fullname cannot be blank")
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
# Mark the object as invalid if there is a spawned_session but the module is *not* an exploit
|
189
|
+
# and not an aux module with the word "login" in the final portion of `module_fullname`
|
190
|
+
#
|
191
|
+
# @return [void]
|
192
|
+
def no_spawned_session_for_non_exploits_except_logins
|
193
|
+
return true unless spawned_session.present?
|
194
|
+
return true if module_name_components.last.include?("login")
|
195
|
+
|
196
|
+
if module_name_components.first != 'exploit'
|
197
|
+
errors.add(:base, 'spawned_session cannot be set for non-exploit modules. Use target_session.')
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
# Mark the object as invalid if there is a target_session but the module is an exploit
|
202
|
+
# @return [void]
|
203
|
+
def no_target_session_for_exploits
|
204
|
+
return true unless target_session.present? # nothing to do unless target_session is set
|
205
|
+
|
206
|
+
if module_name_components.first == 'exploit'
|
207
|
+
return true if module_name_components[2] == 'local'
|
208
|
+
errors.add(:base, 'target_session cannot be set for exploit modules. Use spawned_session.')
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
|
213
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
class PasswordIsStrongValidator < ActiveModel::EachValidator
|
2
2
|
COMMON_PASSWORDS = %w{
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
password pass root admin metasploit
|
4
|
+
msf 123456 qwerty abc123 letmein monkey link182 demo
|
5
|
+
changeme test1234 rapid7
|
6
|
+
}
|
7
7
|
|
8
8
|
SPECIAL_CHARS = %q{!@"#$%&'()*+,-./:;<=>?[\\]^_`{|}~ }
|
9
9
|
|
@@ -105,4 +105,4 @@ class PasswordIsStrongValidator < ActiveModel::EachValidator
|
|
105
105
|
|
106
106
|
false
|
107
107
|
end
|
108
|
-
end
|
108
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateAutomaticExploitationMatches < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :automatic_exploitation_matches do |t|
|
4
|
+
t.integer :ref_id
|
5
|
+
t.string :state
|
6
|
+
t.integer :nexpose_data_vulnerability_definition_id
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
|
11
|
+
add_index :automatic_exploitation_matches, :ref_id
|
12
|
+
end
|
13
|
+
end
|