metasploit_data_models 0.23.1 → 0.23.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|