metasploit-credential 0.14.3 → 0.14.4
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/lib/metasploit/credential.rb +20 -0
- data/lib/metasploit/credential/core_validations.rb +103 -107
- data/lib/metasploit/credential/creation.rb +482 -489
- data/lib/metasploit/credential/engine.rb +32 -27
- data/lib/metasploit/credential/exporter.rb +1 -0
- data/lib/metasploit/credential/exporter/base.rb +29 -37
- data/lib/metasploit/credential/importer.rb +2 -1
- data/lib/metasploit/credential/importer/base.rb +54 -61
- data/lib/metasploit/credential/origin.rb +8 -0
- data/lib/metasploit/credential/search.rb +8 -0
- data/lib/metasploit/credential/search/operation.rb +6 -0
- data/lib/metasploit/credential/search/operator.rb +6 -0
- data/lib/metasploit/credential/version.rb +4 -2
- data/spec/dummy/config/database.yml +11 -13
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fbe2434217b52c3bac09f0768a85e6b18fd12b8e
|
4
|
+
data.tar.gz: 29a368a665d73fc777b043f87fcfb8743a18792e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7cf0f29712e070a36008dd3080eb2dcccb496cd0dfd63977d096615a09575d01f4da8fa6039efbe955aa93b5248e0090cc03e0405648c6abfbceb65c68236151
|
7
|
+
data.tar.gz: 4335440dec2ea65b8be23d68019f50a7900cf33562cdfd01be166958f1c5de437738be0d4f8d2aade5b65fda436e013a040976db45aa79ef7eced976f12979ba
|
@@ -16,6 +16,8 @@ require 'zip'
|
|
16
16
|
# Project
|
17
17
|
#
|
18
18
|
|
19
|
+
autoload :NonNilValidator, 'non_nil_validator'
|
20
|
+
|
19
21
|
# Shared namespace for metasploit gems; used in {https://github.com/rapid7/metasploit-credential metasploit-credential},
|
20
22
|
# {https://github.com/rapid7/metasploit-framework metasploit-framework}, and
|
21
23
|
# {https://github.com/rapid7/metasploit-model metasploit-model}
|
@@ -24,13 +26,31 @@ module Metasploit
|
|
24
26
|
module Credential
|
25
27
|
extend ActiveSupport::Autoload
|
26
28
|
|
29
|
+
autoload :BlankPassword
|
30
|
+
autoload :BlankUsername
|
31
|
+
autoload :Core
|
32
|
+
autoload :CoreValidations
|
27
33
|
autoload :Creation
|
34
|
+
autoload :Engine
|
28
35
|
autoload :EntityRelationshipDiagram
|
29
36
|
autoload :Exporter
|
30
37
|
autoload :Importer
|
38
|
+
autoload :Login
|
31
39
|
autoload :Migrator
|
40
|
+
autoload :NonreplayableHash
|
41
|
+
autoload :NTLMHash
|
32
42
|
autoload :Origin
|
43
|
+
autoload :Password
|
44
|
+
autoload :PasswordHash
|
45
|
+
autoload :PostgresMD5
|
46
|
+
autoload :Private
|
47
|
+
autoload :Public
|
48
|
+
autoload :Realm
|
49
|
+
autoload :ReplayableHash
|
50
|
+
autoload :Search
|
51
|
+
autoload :SSHKey
|
33
52
|
autoload :Text
|
53
|
+
autoload :Username
|
34
54
|
|
35
55
|
# The prefix for all `ActiveRecord::Base#table_name`s for `ActiveRecord::Base` subclasses under this namespace.
|
36
56
|
#
|
@@ -1,119 +1,115 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
module CoreValidations
|
7
|
-
extend ActiveSupport::Concern
|
1
|
+
# This mixin is intended to provide all of the common validations sued by {Metasploit::Credential::Core} and anything
|
2
|
+
# that mimics it's behaviour by tying together {Metasploit::Credential::Public}, {Metasploit::Credential::Private},
|
3
|
+
# and {Metasploit::Credential::Realm} objects.
|
4
|
+
module Metasploit::Credential::CoreValidations
|
5
|
+
extend ActiveSupport::Concern
|
8
6
|
|
9
|
-
|
7
|
+
included do
|
10
8
|
|
11
|
-
|
12
|
-
|
9
|
+
validate :minimum_presence
|
10
|
+
validate :public_for_ssh_key
|
13
11
|
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
#
|
13
|
+
# Attribute Validations
|
14
|
+
#
|
17
15
|
|
18
16
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
17
|
+
# replicates 'unique_private_metasploit_credential_cores' index
|
18
|
+
validates :private_id,
|
19
|
+
uniqueness: {
|
20
|
+
message: 'is already taken for credential cores with only a private credential',
|
21
|
+
scope: [
|
22
|
+
:workspace_id,
|
23
|
+
# realm_id and public_id need to be included in scope so validator uses IS NULL.
|
24
|
+
:realm_id,
|
25
|
+
:public_id
|
26
|
+
]
|
27
|
+
},
|
28
|
+
if: '!realm.present? && !public.present? && private.present?'
|
29
|
+
# replicates 'unique_public_metasploit_credential_cores' index
|
30
|
+
validates :public_id,
|
31
|
+
uniqueness: {
|
32
|
+
message: 'is already taken for credential cores with only a public credential',
|
33
|
+
scope: [
|
34
|
+
:workspace_id,
|
35
|
+
# realm_id and private_id need to be included in scope so validator uses IS NULL.
|
36
|
+
:realm_id,
|
37
|
+
:private_id
|
38
|
+
]
|
39
|
+
},
|
40
|
+
if: '!realm.present? && public.present? && !private.present?'
|
41
|
+
# replicates 'unique_realmless_metasploit_credential_cores' index
|
42
|
+
validates :private_id,
|
43
|
+
uniqueness: {
|
44
|
+
message: 'is already taken for credential cores without a credential realm',
|
45
|
+
scope: [
|
46
|
+
:workspace_id,
|
47
|
+
# realm_id needs to be included in scope so validator uses IS NULL.
|
48
|
+
:realm_id,
|
49
|
+
:public_id
|
50
|
+
]
|
51
|
+
},
|
52
|
+
if: '!realm.present? && public.present? && private.present?'
|
53
|
+
# replicates 'unique_publicless_metasploit_credential_cores' index
|
54
|
+
validates :private_id,
|
55
|
+
uniqueness: {
|
56
|
+
message: 'is already taken for credential cores without a public credential',
|
57
|
+
scope: [
|
58
|
+
:workspace_id,
|
59
|
+
:realm_id,
|
60
|
+
# public_id needs to be included in scope so validator uses IS NULL.
|
61
|
+
:public_id
|
62
|
+
]
|
63
|
+
},
|
64
|
+
if: 'realm.present? && !public.present? && private.present?'
|
65
|
+
# replicates 'unique_privateless_metasploit_credential_cores' index
|
66
|
+
validates :public_id,
|
67
|
+
uniqueness: {
|
68
|
+
message: 'is already taken for credential cores without a private credential',
|
69
|
+
scope: [
|
70
|
+
:workspace_id,
|
71
|
+
:realm_id,
|
72
|
+
# private_id needs to be included in scope so validator uses IS NULL.
|
73
|
+
:private_id
|
74
|
+
]
|
75
|
+
},
|
76
|
+
if: 'realm.present? && public.present? && !private.present?'
|
77
|
+
# replicates 'unique_complete_metasploit_credential_cores' index
|
78
|
+
validates :private_id,
|
79
|
+
uniqueness: {
|
80
|
+
message: 'is already taken for complete credential cores',
|
81
|
+
scope: [
|
82
|
+
:workspace_id,
|
83
|
+
:realm_id,
|
84
|
+
:public_id
|
85
|
+
]
|
86
|
+
},
|
87
|
+
if: 'realm.present? && public.present? && private.present?'
|
88
|
+
validates :workspace,
|
89
|
+
presence: true
|
92
90
|
|
93
|
-
|
91
|
+
private
|
94
92
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
unless any_present
|
104
|
-
errors.add(:base, :minimum_presence)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# Validates that a Core's Private of type {Metasploit::Credential::SSHKey} has a {Metasploit::Credential::Public}
|
109
|
-
def public_for_ssh_key
|
110
|
-
if private.present? && private.type == Metasploit::Credential::SSHKey.name
|
111
|
-
errors.add(:base, :public_for_ssh_key) unless public.present?
|
112
|
-
end
|
113
|
-
end
|
93
|
+
# Validates that at least one of {#private}, {#public}, or {#realm} is present.
|
94
|
+
#
|
95
|
+
# @return [void]
|
96
|
+
def minimum_presence
|
97
|
+
any_present = [:private, :public, :realm].any? { |attribute|
|
98
|
+
send(attribute).present?
|
99
|
+
}
|
114
100
|
|
101
|
+
unless any_present
|
102
|
+
errors.add(:base, :minimum_presence)
|
103
|
+
end
|
104
|
+
end
|
115
105
|
|
106
|
+
# Validates that a Core's Private of type {Metasploit::Credential::SSHKey} has a {Metasploit::Credential::Public}
|
107
|
+
def public_for_ssh_key
|
108
|
+
if private.present? && private.type == Metasploit::Credential::SSHKey.name
|
109
|
+
errors.add(:base, :public_for_ssh_key) unless public.present?
|
116
110
|
end
|
117
111
|
end
|
112
|
+
|
113
|
+
|
118
114
|
end
|
119
|
-
end
|
115
|
+
end
|
@@ -1,549 +1,542 @@
|
|
1
1
|
# Implements a set of "convenience methods" for creating credentials and related portions of the object graph. Creates
|
2
2
|
# {Metasploit::Credential::Core} objects and their attendant relationships as well as {Metasploit::Credential::Login}
|
3
3
|
# objects and their attendant {Mdm::Host} and {Mdm::Service} objects.
|
4
|
-
module Metasploit
|
5
|
-
module Credential
|
6
|
-
# Helper methods for finding or creating a tree of credentials. The method ensure that duplicate credentials are
|
7
|
-
# not created.
|
8
|
-
module Creation
|
9
|
-
|
10
|
-
# Returns true if ActiveRecord has an active database connection, false otherwise.
|
11
|
-
# @return [Boolean]
|
12
|
-
def active_db?
|
13
|
-
ActiveRecord::Base.connected?
|
14
|
-
end
|
4
|
+
module Metasploit::Credential::Creation
|
15
5
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
#
|
22
|
-
# @option opts [String] :username the username to find or create the {Metasploit::Credential::Public} from
|
23
|
-
# @option opts [String] :password the password to find or create the {Metasploit::Credential::Password} from
|
24
|
-
# @option opts [Fixnum] :core_id the id for the originating {Metasploit::Credential::Core}
|
25
|
-
def create_cracked_credential(opts={})
|
26
|
-
return nil unless active_db?
|
27
|
-
|
28
|
-
if self.respond_to?(:[]) and self[:task]
|
29
|
-
opts[:task_id] ||= self[:task].record.id
|
30
|
-
end
|
6
|
+
# Returns true if ActiveRecord has an active database connection, false otherwise.
|
7
|
+
# @return [Boolean]
|
8
|
+
def active_db?
|
9
|
+
ActiveRecord::Base.connected?
|
10
|
+
end
|
31
11
|
|
32
|
-
|
33
|
-
|
34
|
-
|
12
|
+
# This method takes a few simple parameters and creates a new username/password
|
13
|
+
# credential that was obtained by cracking a hash. It reuses the relevant
|
14
|
+
# components form the originating {Metasploit::Credential::Core} and builds new
|
15
|
+
# {Metasploit::Credential::Login} objects based on the ones attached to the originating
|
16
|
+
# {Metasploit::Credential::Core}
|
17
|
+
#
|
18
|
+
# @option opts [String] :username the username to find or create the {Metasploit::Credential::Public} from
|
19
|
+
# @option opts [String] :password the password to find or create the {Metasploit::Credential::Password} from
|
20
|
+
# @option opts [Fixnum] :core_id the id for the originating {Metasploit::Credential::Core}
|
21
|
+
def create_cracked_credential(opts={})
|
22
|
+
return nil unless active_db?
|
23
|
+
|
24
|
+
if self.respond_to?(:[]) and self[:task]
|
25
|
+
opts[:task_id] ||= self[:task].record.id
|
26
|
+
end
|
35
27
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
old_realm_id = nil
|
28
|
+
username = opts.fetch(:username)
|
29
|
+
password = opts.fetch(:password)
|
30
|
+
core_id = opts.fetch(:core_id)
|
40
31
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
old_realm_id = old_core.realm.id if old_core.realm
|
46
|
-
end
|
32
|
+
private = nil
|
33
|
+
public = nil
|
34
|
+
old_core = nil
|
35
|
+
old_realm_id = nil
|
47
36
|
|
48
|
-
|
37
|
+
retry_transaction do
|
38
|
+
private = Metasploit::Credential::Password.where(data: password).first_or_create!
|
39
|
+
public = Metasploit::Credential::Public.where(username: username).first_or_create!
|
40
|
+
old_core = Metasploit::Credential::Core.find(core_id)
|
41
|
+
old_realm_id = old_core.realm.id if old_core.realm
|
42
|
+
end
|
49
43
|
|
50
|
-
|
51
|
-
core = Metasploit::Credential::Core.where(public_id: public.id, private_id: private.id, realm_id: old_realm_id, workspace_id: old_core.workspace_id).first_or_initialize
|
52
|
-
if core.origin_id.nil?
|
53
|
-
origin = Metasploit::Credential::Origin::CrackedPassword.where(metasploit_credential_core_id: core_id).first_or_create!
|
54
|
-
core.origin = origin
|
55
|
-
end
|
56
|
-
if opts[:task_id]
|
57
|
-
core.tasks << Mdm::Task.find(opts[:task_id])
|
58
|
-
end
|
59
|
-
core.save!
|
60
|
-
end
|
44
|
+
core = nil
|
61
45
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
core
|
46
|
+
retry_transaction do
|
47
|
+
core = Metasploit::Credential::Core.where(public_id: public.id, private_id: private.id, realm_id: old_realm_id, workspace_id: old_core.workspace_id).first_or_initialize
|
48
|
+
if core.origin_id.nil?
|
49
|
+
origin = Metasploit::Credential::Origin::CrackedPassword.where(metasploit_credential_core_id: core_id).first_or_create!
|
50
|
+
core.origin = origin
|
51
|
+
end
|
52
|
+
if opts[:task_id]
|
53
|
+
core.tasks << Mdm::Task.find(opts[:task_id])
|
71
54
|
end
|
55
|
+
core.save!
|
56
|
+
end
|
72
57
|
|
58
|
+
old_core.logins.each do |login|
|
59
|
+
service_id = login.service_id
|
60
|
+
new_login = Metasploit::Credential::Login.where(core_id: core.id, service_id: service_id).first_or_initialize
|
61
|
+
if new_login.status.blank?
|
62
|
+
new_login.status = Metasploit::Model::Login::Status::UNTRIED
|
63
|
+
end
|
64
|
+
new_login.save!
|
65
|
+
end
|
66
|
+
core
|
67
|
+
end
|
73
68
|
|
74
|
-
# This method is responsible for creation {Metasploit::Credential::Core} objects
|
75
|
-
# and all sub-objects that it is dependent upon.
|
76
|
-
#
|
77
|
-
# @option opts [String] :jtr_format The format for John the ripper to use to try and crack this
|
78
|
-
# @option opts [Symbol] :origin_type The Origin type we are trying to create
|
79
|
-
# @option opts [String] :address The address of the `Mdm::Host` to link this Origin to
|
80
|
-
# @option opts [Fixnum] :port The port number of the `Mdm::Service` to link this Origin to
|
81
|
-
# @option opts [String] :service_name The service name to use for the `Mdm::Service`
|
82
|
-
# @option opts [String] :protocol The protocol type of the `Mdm::Service` to link this Origin to
|
83
|
-
# @option opts [String] :module_fullname The fullname of the Metasploit Module to link this Origin to
|
84
|
-
# @option opts [Fixnum] :workspace_id The ID of the `Mdm::Workspace` to use for the `Mdm::Host`
|
85
|
-
# @option opts [Fixnum] :task_id The ID of the `Mdm::Task` to link this Origin and Core to
|
86
|
-
# @option opts [String] :filename The filename of the file that was imported
|
87
|
-
# @option opts [Fixnum] :user_id The ID of the `Mdm::User` to link this Origin to
|
88
|
-
# @option opts [Fixnum] :session_id The ID of the `Mdm::Session` to link this Origin to
|
89
|
-
# @option opts [String] :post_reference_name The reference name of the Metasploit Post module to link the origin to
|
90
|
-
# @option opts [String] :private_data The actual data for the private (e.g. password, hash, key etc)
|
91
|
-
# @option opts [Symbol] :private_type The type of {Metasploit::Credential::Private} to create
|
92
|
-
# @option opts [String] :username The username to use for the {Metasploit::Credential::Public}
|
93
|
-
# @raise [KeyError] if a required option is missing
|
94
|
-
# @raise [ArgumentError] if an invalid :private_type is specified
|
95
|
-
# @raise [ArgumentError] if an invalid :origin_type is specified
|
96
|
-
# @return [NilClass] if there is no active database connection
|
97
|
-
# @return [Metasploit::Credential::Core]
|
98
|
-
# @example Reporting a Bruteforced Credential
|
99
|
-
# create_credential(
|
100
|
-
# origin_type: :service,
|
101
|
-
# address: '192.168.1.100',
|
102
|
-
# port: 445,
|
103
|
-
# service_name: 'smb',
|
104
|
-
# protocol: 'tcp',
|
105
|
-
# module_fullname: 'auxiliary/scanner/smb/smb_login',
|
106
|
-
# workspace_id: myworkspace.id,
|
107
|
-
# private_data: 'password1',
|
108
|
-
# private_type: :password,
|
109
|
-
# username: 'Administrator'
|
110
|
-
# )
|
111
|
-
def create_credential(opts={})
|
112
|
-
return nil unless active_db?
|
113
|
-
|
114
|
-
if self.respond_to?(:[]) and self[:task]
|
115
|
-
opts[:task_id] ||= self[:task].record.id
|
116
|
-
end
|
117
69
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
70
|
+
# This method is responsible for creation {Metasploit::Credential::Core} objects
|
71
|
+
# and all sub-objects that it is dependent upon.
|
72
|
+
#
|
73
|
+
# @option opts [String] :jtr_format The format for John the ripper to use to try and crack this
|
74
|
+
# @option opts [Symbol] :origin_type The Origin type we are trying to create
|
75
|
+
# @option opts [String] :address The address of the `Mdm::Host` to link this Origin to
|
76
|
+
# @option opts [Fixnum] :port The port number of the `Mdm::Service` to link this Origin to
|
77
|
+
# @option opts [String] :service_name The service name to use for the `Mdm::Service`
|
78
|
+
# @option opts [String] :protocol The protocol type of the `Mdm::Service` to link this Origin to
|
79
|
+
# @option opts [String] :module_fullname The fullname of the Metasploit Module to link this Origin to
|
80
|
+
# @option opts [Fixnum] :workspace_id The ID of the `Mdm::Workspace` to use for the `Mdm::Host`
|
81
|
+
# @option opts [Fixnum] :task_id The ID of the `Mdm::Task` to link this Origin and Core to
|
82
|
+
# @option opts [String] :filename The filename of the file that was imported
|
83
|
+
# @option opts [Fixnum] :user_id The ID of the `Mdm::User` to link this Origin to
|
84
|
+
# @option opts [Fixnum] :session_id The ID of the `Mdm::Session` to link this Origin to
|
85
|
+
# @option opts [String] :post_reference_name The reference name of the Metasploit Post module to link the origin to
|
86
|
+
# @option opts [String] :private_data The actual data for the private (e.g. password, hash, key etc)
|
87
|
+
# @option opts [Symbol] :private_type The type of {Metasploit::Credential::Private} to create
|
88
|
+
# @option opts [String] :username The username to use for the {Metasploit::Credential::Public}
|
89
|
+
# @raise [KeyError] if a required option is missing
|
90
|
+
# @raise [ArgumentError] if an invalid :private_type is specified
|
91
|
+
# @raise [ArgumentError] if an invalid :origin_type is specified
|
92
|
+
# @return [NilClass] if there is no active database connection
|
93
|
+
# @return [Metasploit::Credential::Core]
|
94
|
+
# @example Reporting a Bruteforced Credential
|
95
|
+
# create_credential(
|
96
|
+
# origin_type: :service,
|
97
|
+
# address: '192.168.1.100',
|
98
|
+
# port: 445,
|
99
|
+
# service_name: 'smb',
|
100
|
+
# protocol: 'tcp',
|
101
|
+
# module_fullname: 'auxiliary/scanner/smb/smb_login',
|
102
|
+
# workspace_id: myworkspace.id,
|
103
|
+
# private_data: 'password1',
|
104
|
+
# private_type: :password,
|
105
|
+
# username: 'Administrator'
|
106
|
+
# )
|
107
|
+
def create_credential(opts={})
|
108
|
+
return nil unless active_db?
|
109
|
+
|
110
|
+
if self.respond_to?(:[]) and self[:task]
|
111
|
+
opts[:task_id] ||= self[:task].record.id
|
112
|
+
end
|
123
113
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
114
|
+
if opts[:origin]
|
115
|
+
origin = opts[:origin]
|
116
|
+
else
|
117
|
+
origin = create_credential_origin(opts)
|
118
|
+
end
|
128
119
|
|
129
|
-
|
130
|
-
|
131
|
-
|
120
|
+
core_opts = {
|
121
|
+
origin: origin,
|
122
|
+
workspace_id: opts.fetch(:workspace_id)
|
123
|
+
}
|
132
124
|
|
133
|
-
|
134
|
-
|
135
|
-
|
125
|
+
if opts.has_key?(:realm_key) && opts.has_key?(:realm_value)
|
126
|
+
core_opts[:realm] = create_credential_realm(opts)
|
127
|
+
end
|
136
128
|
|
137
|
-
|
138
|
-
|
139
|
-
|
129
|
+
if opts.has_key?(:private_type) && opts.has_key?(:private_data)
|
130
|
+
core_opts[:private] = create_credential_private(opts)
|
131
|
+
end
|
140
132
|
|
141
|
-
|
142
|
-
|
143
|
-
|
133
|
+
if opts.has_key?(:username)
|
134
|
+
core_opts[:public] = create_credential_public(opts)
|
135
|
+
end
|
144
136
|
|
145
|
-
|
146
|
-
|
137
|
+
if opts.has_key?(:task_id)
|
138
|
+
core_opts[:task_id] = opts[:task_id]
|
139
|
+
end
|
147
140
|
|
148
|
-
|
149
|
-
|
150
|
-
# @option opts [Metasploit::Credential::Origin] :origin The origin object to tie the core to
|
151
|
-
# @option opts [Metasploit::Credential::Public] :public The {Metasploit::Credential::Public} component
|
152
|
-
# @option opts [Metasploit::Credential::Private] :private The {Metasploit::Credential::Private} component
|
153
|
-
# @option opts [Metasploit::Credential::Realm] :realm The {Metasploit::Credential::Realm} component
|
154
|
-
# @option opts [Fixnum] :workspace_id The ID of the `Mdm::Workspace` to tie the Core to
|
155
|
-
# @option opts [Fixnum] :task_id The ID of the `Mdm::Task` to link this Core to
|
156
|
-
# @return [NilClass] if there is no active database connection
|
157
|
-
# @return [Metasploit::Credential::Core]
|
158
|
-
def create_credential_core(opts={})
|
159
|
-
return nil unless active_db?
|
160
|
-
|
161
|
-
if self.respond_to?(:[]) and self[:task]
|
162
|
-
opts[:task_id] ||= self[:task].record.id
|
163
|
-
end
|
141
|
+
create_credential_core(core_opts)
|
142
|
+
end
|
164
143
|
|
165
|
-
|
166
|
-
|
144
|
+
# This method is responsible for creating {Metasploit::Credential::Core} objects.
|
145
|
+
#
|
146
|
+
# @option opts [Metasploit::Credential::Origin] :origin The origin object to tie the core to
|
147
|
+
# @option opts [Metasploit::Credential::Public] :public The {Metasploit::Credential::Public} component
|
148
|
+
# @option opts [Metasploit::Credential::Private] :private The {Metasploit::Credential::Private} component
|
149
|
+
# @option opts [Metasploit::Credential::Realm] :realm The {Metasploit::Credential::Realm} component
|
150
|
+
# @option opts [Fixnum] :workspace_id The ID of the `Mdm::Workspace` to tie the Core to
|
151
|
+
# @option opts [Fixnum] :task_id The ID of the `Mdm::Task` to link this Core to
|
152
|
+
# @return [NilClass] if there is no active database connection
|
153
|
+
# @return [Metasploit::Credential::Core]
|
154
|
+
def create_credential_core(opts={})
|
155
|
+
return nil unless active_db?
|
156
|
+
|
157
|
+
if self.respond_to?(:[]) and self[:task]
|
158
|
+
opts[:task_id] ||= self[:task].record.id
|
159
|
+
end
|
167
160
|
|
168
|
-
|
169
|
-
|
170
|
-
realm_id = opts[:realm].try(:id)
|
161
|
+
origin = opts.fetch(:origin)
|
162
|
+
workspace_id = opts.fetch(:workspace_id)
|
171
163
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
if core.origin_id.nil?
|
176
|
-
core.origin = origin
|
177
|
-
end
|
178
|
-
if opts[:task_id]
|
179
|
-
core.tasks << Mdm::Task.find(opts[:task_id])
|
180
|
-
end
|
181
|
-
core.save!
|
182
|
-
end
|
164
|
+
private_id = opts[:private].try(:id)
|
165
|
+
public_id = opts[:public].try(:id)
|
166
|
+
realm_id = opts[:realm].try(:id)
|
183
167
|
|
184
|
-
|
168
|
+
core = nil
|
169
|
+
retry_transaction do
|
170
|
+
core = Metasploit::Credential::Core.where(private_id: private_id, public_id: public_id, realm_id: realm_id, workspace_id: workspace_id).first_or_initialize
|
171
|
+
if core.origin_id.nil?
|
172
|
+
core.origin = origin
|
185
173
|
end
|
174
|
+
if opts[:task_id]
|
175
|
+
core.tasks << Mdm::Task.find(opts[:task_id])
|
176
|
+
end
|
177
|
+
core.save!
|
178
|
+
end
|
186
179
|
|
187
|
-
|
188
|
-
|
189
|
-
# credential for.
|
190
|
-
#
|
191
|
-
# @option opts [String] :access_level The access level to assign to this login if we know it
|
192
|
-
# @option opts [String] :address The address of the `Mdm::Host` to link this Login to
|
193
|
-
# @option opts [DateTime] :last_attempted_at The last time this Login was attempted
|
194
|
-
# @option opts [Metasploit::Credential::Core] :core The {Metasploit::Credential::Core} to link this login to
|
195
|
-
# @option opts [Fixnum] :port The port number of the `Mdm::Service` to link this Login to
|
196
|
-
# @option opts [String] :service_name The service name to use for the `Mdm::Service`
|
197
|
-
# @option opts [String] :status The status for the Login object
|
198
|
-
# @option opts [String] :protocol The protocol type of the `Mdm::Service` to link this Login to
|
199
|
-
# @option opts [Fixnum] :workspace_id The ID of the `Mdm::Workspace` to use for the `Mdm::Host`
|
200
|
-
# @option opts [Fixnum] :task_id The ID of the `Mdm::Task` to link this Login to
|
201
|
-
# @raise [KeyError] if a required option is missing
|
202
|
-
# @return [NilClass] if there is no active database connection
|
203
|
-
# @return [Metasploit::Credential::Login]
|
204
|
-
def create_credential_login(opts={})
|
205
|
-
return nil unless active_db?
|
206
|
-
|
207
|
-
if self.respond_to?(:[]) and self[:task]
|
208
|
-
opts[:task_id] ||= self[:task].record.id
|
209
|
-
end
|
180
|
+
core
|
181
|
+
end
|
210
182
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
183
|
+
# This method is responsible for creating a {Metasploit::Credential::Login} object
|
184
|
+
# which ties a {Metasploit::Credential::Core} to the `Mdm::Service` it is a valid
|
185
|
+
# credential for.
|
186
|
+
#
|
187
|
+
# @option opts [String] :access_level The access level to assign to this login if we know it
|
188
|
+
# @option opts [String] :address The address of the `Mdm::Host` to link this Login to
|
189
|
+
# @option opts [DateTime] :last_attempted_at The last time this Login was attempted
|
190
|
+
# @option opts [Metasploit::Credential::Core] :core The {Metasploit::Credential::Core} to link this login to
|
191
|
+
# @option opts [Fixnum] :port The port number of the `Mdm::Service` to link this Login to
|
192
|
+
# @option opts [String] :service_name The service name to use for the `Mdm::Service`
|
193
|
+
# @option opts [String] :status The status for the Login object
|
194
|
+
# @option opts [String] :protocol The protocol type of the `Mdm::Service` to link this Login to
|
195
|
+
# @option opts [Fixnum] :workspace_id The ID of the `Mdm::Workspace` to use for the `Mdm::Host`
|
196
|
+
# @option opts [Fixnum] :task_id The ID of the `Mdm::Task` to link this Login to
|
197
|
+
# @raise [KeyError] if a required option is missing
|
198
|
+
# @return [NilClass] if there is no active database connection
|
199
|
+
# @return [Metasploit::Credential::Login]
|
200
|
+
def create_credential_login(opts={})
|
201
|
+
return nil unless active_db?
|
202
|
+
|
203
|
+
if self.respond_to?(:[]) and self[:task]
|
204
|
+
opts[:task_id] ||= self[:task].record.id
|
205
|
+
end
|
215
206
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
207
|
+
core = opts.fetch(:core)
|
208
|
+
access_level = opts.fetch(:access_level, nil)
|
209
|
+
last_attempted_at = opts.fetch(:last_attempted_at, nil)
|
210
|
+
status = opts.fetch(:status, Metasploit::Model::Login::Status::UNTRIED)
|
220
211
|
|
221
|
-
|
222
|
-
|
223
|
-
|
212
|
+
login_object = nil
|
213
|
+
retry_transaction do
|
214
|
+
service_object = create_credential_service(opts)
|
215
|
+
login_object = Metasploit::Credential::Login.where(core_id: core.id, service_id: service_object.id).first_or_initialize
|
224
216
|
|
225
|
-
|
226
|
-
|
227
|
-
if status == Metasploit::Model::Login::Status::UNTRIED
|
228
|
-
if login_object.last_attempted_at.nil?
|
229
|
-
login_object.status = status
|
230
|
-
end
|
231
|
-
else
|
232
|
-
login_object.status = status
|
233
|
-
end
|
234
|
-
login_object.save!
|
235
|
-
end
|
236
|
-
|
237
|
-
login_object
|
217
|
+
if opts[:task_id]
|
218
|
+
login_object.tasks << Mdm::Task.find(opts[:task_id])
|
238
219
|
end
|
239
220
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
# @option opts [Fixnum] :port The port number of the `Mdm::Service` to link this Origin to
|
246
|
-
# @option opts [String] :service_name The service name to use for the `Mdm::Service`
|
247
|
-
# @option opts [String] :protocol The protocol type of the `Mdm::Service` to link this Origin to
|
248
|
-
# @option opts [String] :module_fullname The fullname of the Metasploit Module to link this Origin to
|
249
|
-
# @option opts [Fixnum] :workspace_id The ID of the `Mdm::Workspace` to use for the `Mdm::Host`
|
250
|
-
# @option opts [Fixnum] :task_id The ID of the `Mdm::Task` to link this Origin to
|
251
|
-
# @option opts [String] :filename The filename of the file that was imported
|
252
|
-
# @option opts [Fixnum] :user_id The ID of the `Mdm::User` to link this Origin to
|
253
|
-
# @option opts [Fixnum] :session_id The ID of the `Mdm::Session` to link this Origin to
|
254
|
-
# @option opts [String] :post_reference_name The reference name of the Metasploit Post module to link the origin to
|
255
|
-
# @raise [ArgumentError] if an invalid origin_type was provided
|
256
|
-
# @raise [KeyError] if a required option is missing
|
257
|
-
# @return [NilClass] if there is no connected database
|
258
|
-
# @return [Metasploit::Credential::Origin::Manual] if :origin_type was :manual
|
259
|
-
# @return [Metasploit::Credential::Origin::Import] if :origin_type was :import
|
260
|
-
# @return [Metasploit::Credential::Origin::Service] if :origin_type was :service
|
261
|
-
# @return [Metasploit::Credential::Origin::Session] if :origin_type was :session
|
262
|
-
def create_credential_origin(opts={})
|
263
|
-
return nil unless active_db?
|
264
|
-
case opts[:origin_type]
|
265
|
-
when :cracked_password
|
266
|
-
create_credential_origin_cracked_password(opts)
|
267
|
-
when :import
|
268
|
-
create_credential_origin_import(opts)
|
269
|
-
when :manual
|
270
|
-
create_credential_origin_manual(opts)
|
271
|
-
when :service
|
272
|
-
create_credential_origin_service(opts)
|
273
|
-
when :session
|
274
|
-
create_credential_origin_session(opts)
|
275
|
-
else
|
276
|
-
raise ArgumentError, "Unknown Origin Type #{opts[:origin_type]}"
|
221
|
+
login_object.access_level = access_level if access_level
|
222
|
+
login_object.last_attempted_at = last_attempted_at if last_attempted_at
|
223
|
+
if status == Metasploit::Model::Login::Status::UNTRIED
|
224
|
+
if login_object.last_attempted_at.nil?
|
225
|
+
login_object.status = status
|
277
226
|
end
|
227
|
+
else
|
228
|
+
login_object.status = status
|
278
229
|
end
|
230
|
+
login_object.save!
|
231
|
+
end
|
279
232
|
|
280
|
-
|
281
|
-
|
282
|
-
# that previously existed in the database.
|
283
|
-
#
|
284
|
-
# @option opts [Fixnum] :originating_core_id The ID of the originating Credential core.
|
285
|
-
# @return [NilClass] if there is no connected database
|
286
|
-
# @return [Metasploit::Credential::Origin::CrackedPassword] The created {Metasploit::Credential::Origin::CrackedPassword} object
|
287
|
-
def create_credential_origin_cracked_password(opts={})
|
288
|
-
return nil unless active_db?
|
289
|
-
originating_core_id = opts.fetch(:originating_core_id)
|
290
|
-
|
291
|
-
retry_transaction do
|
292
|
-
Metasploit::Credential::Origin::CrackedPassword.where(metasploit_credential_core_id: originating_core_id ).first_or_create!
|
293
|
-
end
|
294
|
-
end
|
233
|
+
login_object
|
234
|
+
end
|
295
235
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
236
|
+
# This method is responsible for creating the various Credential::Origin objects.
|
237
|
+
# It takes a key for the Origin type and delegates to the correct sub-method.
|
238
|
+
#
|
239
|
+
# @option opts [Symbol] :origin_type The Origin type we are trying to create
|
240
|
+
# @option opts [String] :address The address of the `Mdm::Host` to link this Origin to
|
241
|
+
# @option opts [Fixnum] :port The port number of the `Mdm::Service` to link this Origin to
|
242
|
+
# @option opts [String] :service_name The service name to use for the `Mdm::Service`
|
243
|
+
# @option opts [String] :protocol The protocol type of the `Mdm::Service` to link this Origin to
|
244
|
+
# @option opts [String] :module_fullname The fullname of the Metasploit Module to link this Origin to
|
245
|
+
# @option opts [Fixnum] :workspace_id The ID of the `Mdm::Workspace` to use for the `Mdm::Host`
|
246
|
+
# @option opts [Fixnum] :task_id The ID of the `Mdm::Task` to link this Origin to
|
247
|
+
# @option opts [String] :filename The filename of the file that was imported
|
248
|
+
# @option opts [Fixnum] :user_id The ID of the `Mdm::User` to link this Origin to
|
249
|
+
# @option opts [Fixnum] :session_id The ID of the `Mdm::Session` to link this Origin to
|
250
|
+
# @option opts [String] :post_reference_name The reference name of the Metasploit Post module to link the origin to
|
251
|
+
# @raise [ArgumentError] if an invalid origin_type was provided
|
252
|
+
# @raise [KeyError] if a required option is missing
|
253
|
+
# @return [NilClass] if there is no connected database
|
254
|
+
# @return [Metasploit::Credential::Origin::Manual] if :origin_type was :manual
|
255
|
+
# @return [Metasploit::Credential::Origin::Import] if :origin_type was :import
|
256
|
+
# @return [Metasploit::Credential::Origin::Service] if :origin_type was :service
|
257
|
+
# @return [Metasploit::Credential::Origin::Session] if :origin_type was :session
|
258
|
+
def create_credential_origin(opts={})
|
259
|
+
return nil unless active_db?
|
260
|
+
case opts[:origin_type]
|
261
|
+
when :cracked_password
|
262
|
+
create_credential_origin_cracked_password(opts)
|
263
|
+
when :import
|
264
|
+
create_credential_origin_import(opts)
|
265
|
+
when :manual
|
266
|
+
create_credential_origin_manual(opts)
|
267
|
+
when :service
|
268
|
+
create_credential_origin_service(opts)
|
269
|
+
when :session
|
270
|
+
create_credential_origin_session(opts)
|
271
|
+
else
|
272
|
+
raise ArgumentError, "Unknown Origin Type #{opts[:origin_type]}"
|
273
|
+
end
|
274
|
+
end
|
310
275
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
276
|
+
# This method is responsible for creating {Metasploit::Credential::Origin::CrackedPassword} objects.
|
277
|
+
# These are the origins that show that a password Credential was obtained by cracking a hash Credential
|
278
|
+
# that previously existed in the database.
|
279
|
+
#
|
280
|
+
# @option opts [Fixnum] :originating_core_id The ID of the originating Credential core.
|
281
|
+
# @return [NilClass] if there is no connected database
|
282
|
+
# @return [Metasploit::Credential::Origin::CrackedPassword] The created {Metasploit::Credential::Origin::CrackedPassword} object
|
283
|
+
def create_credential_origin_cracked_password(opts={})
|
284
|
+
return nil unless active_db?
|
285
|
+
originating_core_id = opts.fetch(:originating_core_id)
|
286
|
+
|
287
|
+
retry_transaction do
|
288
|
+
Metasploit::Credential::Origin::CrackedPassword.where(metasploit_credential_core_id: originating_core_id ).first_or_create!
|
289
|
+
end
|
290
|
+
end
|
325
291
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
module_fullname = opts.fetch(:module_fullname)
|
341
|
-
|
342
|
-
service_object = create_credential_service(opts)
|
343
|
-
|
344
|
-
retry_transaction do
|
345
|
-
Metasploit::Credential::Origin::Service.where(service_id: service_object.id, module_full_name: module_fullname).first_or_create!
|
346
|
-
end
|
292
|
+
# This method is responsible for creating {Metasploit::Credential::Origin::Import} objects.
|
293
|
+
#
|
294
|
+
# @option opts [String] :filename The filename of the file that was imported
|
295
|
+
# @raise [KeyError] if a required option is missing
|
296
|
+
# @return [NilClass] if there is no connected database
|
297
|
+
# @return [Metasploit::Credential::Origin::Manual] The created {Metasploit::Credential::Origin::Import} object
|
298
|
+
def create_credential_origin_import(opts={})
|
299
|
+
return nil unless active_db?
|
300
|
+
filename = opts.fetch(:filename)
|
301
|
+
|
302
|
+
retry_transaction do
|
303
|
+
Metasploit::Credential::Origin::Import.where(filename: filename).first_or_create!
|
304
|
+
end
|
305
|
+
end
|
347
306
|
|
348
|
-
|
307
|
+
# This method is responsible for creating {Metasploit::Credential::Origin::Manual} objects.
|
308
|
+
#
|
309
|
+
# @option opts [Fixnum] :user_id The ID of the `Mdm::User` to link this Origin to
|
310
|
+
# @raise [KeyError] if a required option is missing
|
311
|
+
# @return [NilClass] if there is no connected database
|
312
|
+
# @return [Metasploit::Credential::Origin::Manual] The created {Metasploit::Credential::Origin::Manual} object
|
313
|
+
def create_credential_origin_manual(opts={})
|
314
|
+
return nil unless active_db?
|
315
|
+
user_id = opts.fetch(:user_id)
|
316
|
+
|
317
|
+
retry_transaction do
|
318
|
+
Metasploit::Credential::Origin::Manual.where(user_id: user_id).first_or_create!
|
319
|
+
end
|
320
|
+
end
|
349
321
|
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
322
|
+
# This method is responsible for creating {Metasploit::Credential::Origin::Service} objects.
|
323
|
+
# If there is not a matching `Mdm::Host` it will create it. If there is not a matching
|
324
|
+
# `Mdm::Service` it will create that too.
|
325
|
+
#
|
326
|
+
# @option opts [String] :address The address of the `Mdm::Host` to link this Origin to
|
327
|
+
# @option opts [Fixnum] :port The port number of the `Mdm::Service` to link this Origin to
|
328
|
+
# @option opts [String] :service_name The service name to use for the `Mdm::Service`
|
329
|
+
# @option opts [String] :protocol The protocol type of the `Mdm::Service` to link this Origin to
|
330
|
+
# @option opts [String] :module_fullname The fullname of the Metasploit Module to link this Origin to
|
331
|
+
# @raise [KeyError] if a required option is missing
|
332
|
+
# @return [NilClass] if there is no connected database
|
333
|
+
# @return [Metasploit::Credential::Origin::Service] The created {Metasploit::Credential::Origin::Service} object
|
334
|
+
def create_credential_origin_service(opts={})
|
335
|
+
return nil unless active_db?
|
336
|
+
module_fullname = opts.fetch(:module_fullname)
|
337
|
+
|
338
|
+
service_object = create_credential_service(opts)
|
339
|
+
|
340
|
+
retry_transaction do
|
341
|
+
Metasploit::Credential::Origin::Service.where(service_id: service_object.id, module_full_name: module_fullname).first_or_create!
|
342
|
+
end
|
366
343
|
|
367
|
-
|
368
|
-
# It will create the correct subclass based on the type.
|
369
|
-
#
|
370
|
-
# @option opts [String] :jtr_format The format for John the ripper to use to try and crack this
|
371
|
-
# @option opts [String] :private_data The actual data for the private (e.g. password, hash, key etc)
|
372
|
-
# @option opts [Symbol] :private_type The type of {Metasploit::Credential::Private} to create
|
373
|
-
# @raise [ArgumentError] if a valid type is not supplied
|
374
|
-
# @raise [KeyError] if a required option is missing
|
375
|
-
# @return [NilClass] if there is no active database connection
|
376
|
-
# @return [Metasploit::Credential::Password] if the private_type was :password
|
377
|
-
# @return [Metasploit::Credential::SSHKey] if the private_type was :ssh_key
|
378
|
-
# @return [Metasploit::Credential::NTLMHash] if the private_type was :ntlm_hash
|
379
|
-
# @return [Metasploit::Credential::NonreplayableHash] if the private_type was :nonreplayable_hash
|
380
|
-
def create_credential_private(opts={})
|
381
|
-
return nil unless active_db?
|
382
|
-
private_data = opts.fetch(:private_data)
|
383
|
-
private_type = opts.fetch(:private_type)
|
384
|
-
|
385
|
-
private_object = nil
|
386
|
-
|
387
|
-
retry_transaction do
|
388
|
-
if private_data.blank?
|
389
|
-
private_object = Metasploit::Credential::BlankPassword.where(data:'').first_or_create
|
390
|
-
else
|
391
|
-
case private_type
|
392
|
-
when :password
|
393
|
-
private_object = Metasploit::Credential::Password.where(data: private_data).first_or_create
|
394
|
-
when :ssh_key
|
395
|
-
private_object = Metasploit::Credential::SSHKey.where(data: private_data).first_or_create
|
396
|
-
when :ntlm_hash
|
397
|
-
private_object = Metasploit::Credential::NTLMHash.where(data: private_data).first_or_create
|
398
|
-
private_object.jtr_format = 'nt,lm'
|
399
|
-
when :postgres_md5
|
400
|
-
private_object = Metasploit::Credential::PostgresMD5.where(data: private_data).first_or_create
|
401
|
-
private_object.jtr_format = 'raw-md5,postgres'
|
402
|
-
when :nonreplayable_hash
|
403
|
-
private_object = Metasploit::Credential::NonreplayableHash.where(data: private_data).first_or_create
|
404
|
-
if opts[:jtr_format].present?
|
405
|
-
private_object.jtr_format = opts[:jtr_format]
|
406
|
-
end
|
407
|
-
else
|
408
|
-
raise ArgumentError, "Invalid Private type: #{private_type}"
|
409
|
-
end
|
410
|
-
end
|
411
|
-
private_object.save!
|
412
|
-
end
|
413
|
-
private_object
|
414
|
-
end
|
344
|
+
end
|
415
345
|
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
346
|
+
# This method is responsible for creating {Metasploit::Credential::Origin::Session} objects.
|
347
|
+
#
|
348
|
+
# @option opts [Fixnum] :session_id The ID of the `Mdm::Session` to link this Origin to
|
349
|
+
# @option opts [String] :post_reference_name The reference name of the Metasploit Post module to link the origin to
|
350
|
+
# @raise [KeyError] if a required option is missing
|
351
|
+
# @return [NilClass] if there is no connected database
|
352
|
+
# @return [Metasploit::Credential::Origin::Session] The created {Metasploit::Credential::Origin::Session} object
|
353
|
+
def create_credential_origin_session(opts={})
|
354
|
+
return nil unless active_db?
|
355
|
+
session_id = opts.fetch(:session_id)
|
356
|
+
post_reference_name = opts.fetch(:post_reference_name)
|
357
|
+
|
358
|
+
retry_transaction do
|
359
|
+
Metasploit::Credential::Origin::Session.where(session_id: session_id, post_reference_name: post_reference_name).first_or_create!
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
# This method is responsible for the creation of {Metasploit::Credential::Private} objects.
|
364
|
+
# It will create the correct subclass based on the type.
|
365
|
+
#
|
366
|
+
# @option opts [String] :jtr_format The format for John the ripper to use to try and crack this
|
367
|
+
# @option opts [String] :private_data The actual data for the private (e.g. password, hash, key etc)
|
368
|
+
# @option opts [Symbol] :private_type The type of {Metasploit::Credential::Private} to create
|
369
|
+
# @raise [ArgumentError] if a valid type is not supplied
|
370
|
+
# @raise [KeyError] if a required option is missing
|
371
|
+
# @return [NilClass] if there is no active database connection
|
372
|
+
# @return [Metasploit::Credential::Password] if the private_type was :password
|
373
|
+
# @return [Metasploit::Credential::SSHKey] if the private_type was :ssh_key
|
374
|
+
# @return [Metasploit::Credential::NTLMHash] if the private_type was :ntlm_hash
|
375
|
+
# @return [Metasploit::Credential::NonreplayableHash] if the private_type was :nonreplayable_hash
|
376
|
+
def create_credential_private(opts={})
|
377
|
+
return nil unless active_db?
|
378
|
+
private_data = opts.fetch(:private_data)
|
379
|
+
private_type = opts.fetch(:private_type)
|
380
|
+
|
381
|
+
private_object = nil
|
382
|
+
|
383
|
+
retry_transaction do
|
384
|
+
if private_data.blank?
|
385
|
+
private_object = Metasploit::Credential::BlankPassword.where(data:'').first_or_create
|
386
|
+
else
|
387
|
+
case private_type
|
388
|
+
when :password
|
389
|
+
private_object = Metasploit::Credential::Password.where(data: private_data).first_or_create
|
390
|
+
when :ssh_key
|
391
|
+
private_object = Metasploit::Credential::SSHKey.where(data: private_data).first_or_create
|
392
|
+
when :ntlm_hash
|
393
|
+
private_object = Metasploit::Credential::NTLMHash.where(data: private_data).first_or_create
|
394
|
+
private_object.jtr_format = 'nt,lm'
|
395
|
+
when :postgres_md5
|
396
|
+
private_object = Metasploit::Credential::PostgresMD5.where(data: private_data).first_or_create
|
397
|
+
private_object.jtr_format = 'raw-md5,postgres'
|
398
|
+
when :nonreplayable_hash
|
399
|
+
private_object = Metasploit::Credential::NonreplayableHash.where(data: private_data).first_or_create
|
400
|
+
if opts[:jtr_format].present?
|
401
|
+
private_object.jtr_format = opts[:jtr_format]
|
431
402
|
end
|
403
|
+
else
|
404
|
+
raise ArgumentError, "Invalid Private type: #{private_type}"
|
432
405
|
end
|
433
406
|
end
|
407
|
+
private_object.save!
|
408
|
+
end
|
409
|
+
private_object
|
410
|
+
end
|
434
411
|
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
end
|
412
|
+
# This method is responsible for the creation of {Metasploit::Credential::Public} objects.
|
413
|
+
#
|
414
|
+
# @option opts [String] :username The username to use for the {Metasploit::Credential::Public}
|
415
|
+
# @raise [KeyError] if a required option is missing
|
416
|
+
# @return [NilClass] if there is no active database connection
|
417
|
+
# @return [Metasploit::Credential::Public]
|
418
|
+
def create_credential_public(opts={})
|
419
|
+
return nil unless active_db?
|
420
|
+
username = opts.fetch(:username)
|
421
|
+
|
422
|
+
retry_transaction do
|
423
|
+
if username.blank?
|
424
|
+
Metasploit::Credential::BlankUsername.where(username:'').first_or_create!
|
425
|
+
else
|
426
|
+
Metasploit::Credential::Username.where(username: username).first_or_create!
|
451
427
|
end
|
428
|
+
end
|
429
|
+
end
|
452
430
|
|
431
|
+
# This method is responsible for creating the {Metasploit::Credential::Realm} objects
|
432
|
+
# that may be required.
|
433
|
+
#
|
434
|
+
# @option opts [String] :realm_key The type of Realm this is (e.g. 'Active Directory Domain')
|
435
|
+
# @option opts [String] :realm_value The actual Realm name (e.g. contosso)
|
436
|
+
# @raise [KeyError] if a required option is missing
|
437
|
+
# @return [NilClass] if there is no active database connection
|
438
|
+
# @return [Metasploit::Credential::Realm] if it successfully creates or finds the object
|
439
|
+
def create_credential_realm(opts={})
|
440
|
+
return nil unless active_db?
|
441
|
+
realm_key = opts.fetch(:realm_key)
|
442
|
+
realm_value = opts.fetch(:realm_value)
|
443
|
+
|
444
|
+
retry_transaction do
|
445
|
+
Metasploit::Credential::Realm.where(key: realm_key, value: realm_value).first_or_create!
|
446
|
+
end
|
447
|
+
end
|
453
448
|
|
454
449
|
|
455
|
-
# This method is responsible for creating a barebones `Mdm::Service` object
|
456
|
-
# for use by Credential object creation.
|
457
|
-
#
|
458
|
-
# @option opts [String] :address The address of the `Mdm::Host`
|
459
|
-
# @option opts [Fixnum] :port The port number of the `Mdm::Service`
|
460
|
-
# @option opts [String] :service_name The service name to use for the `Mdm::Service`
|
461
|
-
# @option opts [String] :protocol The protocol type of the `Mdm::Service``
|
462
|
-
# @option opts [Fixnum] :workspace_id The ID of the `Mdm::Workspace` to use for the `Mdm::Host`
|
463
|
-
# @raise [KeyError] if a required option is missing
|
464
|
-
# @return [NilClass] if there is no connected database
|
465
|
-
# @return [Mdm::Service]
|
466
|
-
def create_credential_service(opts={})
|
467
|
-
return nil unless active_db?
|
468
|
-
address = opts.fetch(:address)
|
469
|
-
port = opts.fetch(:port)
|
470
|
-
service_name = opts.fetch(:service_name)
|
471
|
-
protocol = opts.fetch(:protocol)
|
472
|
-
workspace_id = opts.fetch(:workspace_id)
|
473
|
-
|
474
|
-
host_object = Mdm::Host.where(address: address, workspace_id: workspace_id).first_or_create
|
475
|
-
service_object = Mdm::Service.where(host_id: host_object.id, port: port, proto: protocol).first_or_initialize
|
476
|
-
|
477
|
-
service_object.name = service_name
|
478
|
-
service_object.state = "open"
|
479
|
-
service_object.save!
|
480
|
-
|
481
|
-
service_object
|
482
|
-
end
|
483
450
|
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
core = Metasploit::Credential::Core.where(public_id: pub_obj, private_id: priv_obj, realm_id: realm_obj).first
|
513
|
-
|
514
|
-
# Do nothing else if we have no matching core. Otherwise look for a Login.
|
515
|
-
if core.present?
|
516
|
-
login = core.logins.joins(service: :host).where(services: { port: port, proto: protocol } ).where( hosts: {address: address}).readonly(false).first
|
517
|
-
|
518
|
-
if login.present?
|
519
|
-
login.status = status
|
520
|
-
login.last_attempted_at = DateTime.now
|
521
|
-
login.save!
|
522
|
-
end
|
523
|
-
|
524
|
-
end
|
451
|
+
# This method is responsible for creating a barebones `Mdm::Service` object
|
452
|
+
# for use by Credential object creation.
|
453
|
+
#
|
454
|
+
# @option opts [String] :address The address of the `Mdm::Host`
|
455
|
+
# @option opts [Fixnum] :port The port number of the `Mdm::Service`
|
456
|
+
# @option opts [String] :service_name The service name to use for the `Mdm::Service`
|
457
|
+
# @option opts [String] :protocol The protocol type of the `Mdm::Service``
|
458
|
+
# @option opts [Fixnum] :workspace_id The ID of the `Mdm::Workspace` to use for the `Mdm::Host`
|
459
|
+
# @raise [KeyError] if a required option is missing
|
460
|
+
# @return [NilClass] if there is no connected database
|
461
|
+
# @return [Mdm::Service]
|
462
|
+
def create_credential_service(opts={})
|
463
|
+
return nil unless active_db?
|
464
|
+
address = opts.fetch(:address)
|
465
|
+
port = opts.fetch(:port)
|
466
|
+
service_name = opts.fetch(:service_name)
|
467
|
+
protocol = opts.fetch(:protocol)
|
468
|
+
workspace_id = opts.fetch(:workspace_id)
|
469
|
+
|
470
|
+
host_object = Mdm::Host.where(address: address, workspace_id: workspace_id).first_or_create
|
471
|
+
service_object = Mdm::Service.where(host_id: host_object.id, port: port, proto: protocol).first_or_initialize
|
472
|
+
|
473
|
+
service_object.name = service_name
|
474
|
+
service_object.state = "open"
|
475
|
+
service_object.save!
|
476
|
+
|
477
|
+
service_object
|
478
|
+
end
|
525
479
|
|
480
|
+
# This method checks to see if a {Metasploit::Credential::Login} exists for a given
|
481
|
+
# set of details. If it does exists, we then appropriately set the status to one of our
|
482
|
+
# failure statuses.
|
483
|
+
#
|
484
|
+
# @option opts [String] :address The address of the host we attempted
|
485
|
+
# @option opts [Fixnum] :port the port of the service we attempted
|
486
|
+
# @option opts [String] :protocol the transport protocol of the service we attempted
|
487
|
+
# @option opts [String] :public A string representation of the public we tried
|
488
|
+
# @option opts [String] :private A string representation of the private we tried
|
489
|
+
# @option opts [Symbol] :status The status symbol from the {Metasploit::Framework::LoginScanner::Result}
|
490
|
+
# @raise [KeyError] if any of the above options are missing
|
491
|
+
# @return [void] Do not worry about the return value from this method
|
492
|
+
def invalidate_login(opts = {})
|
493
|
+
return nil unless active_db?
|
494
|
+
address = opts.fetch(:address)
|
495
|
+
port = opts.fetch(:port)
|
496
|
+
protocol = opts.fetch(:protocol)
|
497
|
+
public = opts.fetch(:username, nil)
|
498
|
+
private = opts.fetch(:private_data, nil)
|
499
|
+
realm_key = opts.fetch(:realm_key, nil)
|
500
|
+
realm_value = opts.fetch(:realm_value, nil)
|
501
|
+
status = opts.fetch(:status)
|
502
|
+
|
503
|
+
|
504
|
+
pub_obj = Metasploit::Credential::Public.where(username: public).first.try(:id)
|
505
|
+
priv_obj = Metasploit::Credential::Private.where(data: private).first.try(:id)
|
506
|
+
realm_obj = Metasploit::Credential::Realm.where(key: realm_key, value: realm_value).first.try(:id)
|
507
|
+
|
508
|
+
core = Metasploit::Credential::Core.where(public_id: pub_obj, private_id: priv_obj, realm_id: realm_obj).first
|
509
|
+
|
510
|
+
# Do nothing else if we have no matching core. Otherwise look for a Login.
|
511
|
+
if core.present?
|
512
|
+
login = core.logins.joins(service: :host).where(services: { port: port, proto: protocol } ).where( hosts: {address: address}).readonly(false).first
|
513
|
+
|
514
|
+
if login.present?
|
515
|
+
login.status = status
|
516
|
+
login.last_attempted_at = DateTime.now
|
517
|
+
login.save!
|
526
518
|
end
|
527
519
|
|
520
|
+
end
|
528
521
|
|
529
|
-
|
530
|
-
|
531
|
-
# This method wraps a block in a retry if we get a RecordNotUnique validation error.
|
532
|
-
# This helps guard against race conditions.
|
533
|
-
def retry_transaction(&block)
|
534
|
-
tries = 3
|
535
|
-
begin
|
536
|
-
yield
|
537
|
-
rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique
|
538
|
-
tries -= 1
|
539
|
-
if tries > 0
|
540
|
-
retry
|
541
|
-
else
|
542
|
-
raise
|
543
|
-
end
|
544
|
-
end
|
545
|
-
end
|
522
|
+
end
|
546
523
|
|
524
|
+
|
525
|
+
private
|
526
|
+
|
527
|
+
# This method wraps a block in a retry if we get a RecordNotUnique validation error.
|
528
|
+
# This helps guard against race conditions.
|
529
|
+
def retry_transaction(&block)
|
530
|
+
tries = 3
|
531
|
+
begin
|
532
|
+
yield
|
533
|
+
rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique
|
534
|
+
tries -= 1
|
535
|
+
if tries > 0
|
536
|
+
retry
|
537
|
+
else
|
538
|
+
raise
|
539
|
+
end
|
547
540
|
end
|
548
541
|
end
|
549
542
|
end
|