metasploit-credential 0.14.3 → 0.14.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|