mihari 7.1.3 → 7.3.0
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/Dockerfile +2 -2
- data/Rakefile +8 -1
- data/lefthook.yml +4 -1
- data/lib/mihari/actor.rb +16 -0
- data/lib/mihari/analyzers/base.rb +7 -25
- data/lib/mihari/analyzers/binaryedge.rb +0 -6
- data/lib/mihari/analyzers/censys.rb +0 -9
- data/lib/mihari/analyzers/circl.rb +0 -6
- data/lib/mihari/analyzers/fofa.rb +0 -6
- data/lib/mihari/analyzers/greynoise.rb +0 -6
- data/lib/mihari/analyzers/hunterhow.rb +0 -6
- data/lib/mihari/analyzers/onyphe.rb +0 -6
- data/lib/mihari/analyzers/otx.rb +0 -6
- data/lib/mihari/analyzers/passivetotal.rb +0 -4
- data/lib/mihari/analyzers/pulsedive.rb +0 -6
- data/lib/mihari/analyzers/securitytrails.rb +0 -4
- data/lib/mihari/analyzers/shodan.rb +0 -6
- data/lib/mihari/analyzers/urlscan.rb +0 -6
- data/lib/mihari/analyzers/virustotal.rb +0 -4
- data/lib/mihari/analyzers/virustotal_intelligence.rb +7 -6
- data/lib/mihari/analyzers/zoomeye.rb +0 -6
- data/lib/mihari/commands/web.rb +1 -1
- data/lib/mihari/concerns/falsepositive_normalizable.rb +30 -0
- data/lib/mihari/concerns/falsepositive_validatable.rb +1 -17
- data/lib/mihari/config.rb +1 -1
- data/lib/mihari/database.rb +18 -1
- data/lib/mihari/emitters/database.rb +0 -6
- data/lib/mihari/emitters/misp.rb +0 -6
- data/lib/mihari/emitters/slack.rb +5 -21
- data/lib/mihari/emitters/the_hive.rb +0 -6
- data/lib/mihari/enrichers/base.rb +54 -12
- data/lib/mihari/enrichers/google_public_dns.rb +28 -7
- data/lib/mihari/enrichers/mmdb.rb +25 -7
- data/lib/mihari/enrichers/shodan.rb +35 -4
- data/lib/mihari/enrichers/whois.rb +37 -31
- data/lib/mihari/entities/artifact.rb +6 -2
- data/lib/mihari/entities/autonomous_system.rb +1 -1
- data/lib/mihari/entities/cpe.rb +1 -1
- data/lib/mihari/entities/port.rb +1 -1
- data/lib/mihari/entities/vulnerability.rb +10 -0
- data/lib/mihari/errors.rb +2 -0
- data/lib/mihari/models/alert.rb +12 -0
- data/lib/mihari/models/artifact.rb +118 -159
- data/lib/mihari/models/rule.rb +21 -0
- data/lib/mihari/models/vulnerability.rb +12 -0
- data/lib/mihari/rule.rb +44 -29
- data/lib/mihari/schemas/alert.rb +3 -3
- data/lib/mihari/schemas/analyzer.rb +27 -27
- data/lib/mihari/schemas/emitter.rb +9 -9
- data/lib/mihari/schemas/macros.rb +2 -2
- data/lib/mihari/schemas/options.rb +2 -5
- data/lib/mihari/schemas/rule.rb +19 -12
- data/lib/mihari/services/builders.rb +0 -134
- data/lib/mihari/services/enrichers.rb +3 -1
- data/lib/mihari/services/feed.rb +2 -5
- data/lib/mihari/services/getters.rb +1 -1
- data/lib/mihari/services/proxies.rb +3 -3
- data/lib/mihari/structs/censys.rb +2 -2
- data/lib/mihari/structs/greynoise.rb +1 -1
- data/lib/mihari/structs/onyphe.rb +1 -1
- data/lib/mihari/structs/shodan.rb +59 -21
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/endpoints/artifacts.rb +4 -2
- data/lib/mihari/web/endpoints/rules.rb +1 -1
- data/lib/mihari/web/public/assets/{index-TOeU8PE2.js → index-JHS0L8KZ.js} +47 -47
- data/lib/mihari/web/public/assets/{index-dVaNxqTC.css → index-ReF8ffd-.css} +1 -1
- data/lib/mihari/web/public/index.html +2 -2
- data/lib/mihari/web/public/redoc-static.html +17 -17
- data/lib/mihari.rb +3 -0
- data/mihari.gemspec +2 -2
- data/requirements.txt +1 -1
- metadata +11 -8
@@ -7,14 +7,22 @@ module Mihari
|
|
7
7
|
#
|
8
8
|
class GooglePublicDNS < Base
|
9
9
|
#
|
10
|
-
#
|
10
|
+
# @param [Mihari::Models::Artifact] artifact
|
11
11
|
#
|
12
|
-
# @
|
12
|
+
# @return [Mihari::Models::Artifact]
|
13
13
|
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
client.query_all
|
14
|
+
def call(artifact)
|
15
|
+
return if artifact.domain.nil?
|
16
|
+
|
17
|
+
res = client.query_all(artifact.domain)
|
18
|
+
|
19
|
+
artifact.tap do |tapped|
|
20
|
+
if tapped.dns_records.empty?
|
21
|
+
tapped.dns_records = res.answers.map do |answer|
|
22
|
+
Models::DnsRecord.new(resource: answer.resource_type, value: answer.data)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
18
26
|
end
|
19
27
|
|
20
28
|
class << self
|
@@ -28,8 +36,21 @@ module Mihari
|
|
28
36
|
|
29
37
|
private
|
30
38
|
|
39
|
+
#
|
40
|
+
# @param [Mihari::Models::Artifact] artifact
|
41
|
+
#
|
42
|
+
# @return [Boolean]
|
43
|
+
#
|
44
|
+
def callable_relationships?(artifact)
|
45
|
+
artifact.dns_records.empty?
|
46
|
+
end
|
47
|
+
|
48
|
+
def supported_data_types
|
49
|
+
%w[url domain]
|
50
|
+
end
|
51
|
+
|
31
52
|
def client
|
32
|
-
Clients::GooglePublicDNS.new(timeout: timeout)
|
53
|
+
@client ||= Clients::GooglePublicDNS.new(timeout: timeout)
|
33
54
|
end
|
34
55
|
end
|
35
56
|
end
|
@@ -7,18 +7,36 @@ module Mihari
|
|
7
7
|
#
|
8
8
|
class MMDB < Base
|
9
9
|
#
|
10
|
-
#
|
10
|
+
# @param [Mihari::Models::Artifact] artifact
|
11
11
|
#
|
12
|
-
|
12
|
+
def call(artifact)
|
13
|
+
res = client.query(artifact.data)
|
14
|
+
|
15
|
+
artifact.tap do |tapped|
|
16
|
+
tapped.autonomous_system ||= Models::AutonomousSystem.new(number: res.asn) if res.asn
|
17
|
+
if res.country_code
|
18
|
+
tapped.geolocation ||= Models::Geolocation.new(
|
19
|
+
country: NormalizeCountry(res.country_code, to: :short),
|
20
|
+
country_code: res.country_code
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
#
|
29
|
+
# @param [Mihari::Models::Artifact] artifact
|
13
30
|
#
|
14
|
-
# @return [
|
31
|
+
# @return [Boolean]
|
15
32
|
#
|
16
|
-
def
|
17
|
-
|
33
|
+
def callable_relationships?(artifact)
|
34
|
+
artifact.geolocation.nil? || artifact.autonomous_system.nil?
|
18
35
|
end
|
19
|
-
memo_wise :call
|
20
36
|
|
21
|
-
|
37
|
+
def supported_data_types
|
38
|
+
%w[ip]
|
39
|
+
end
|
22
40
|
|
23
41
|
def client
|
24
42
|
@client ||= Clients::MMDB.new(timeout: timeout)
|
@@ -9,17 +9,48 @@ module Mihari
|
|
9
9
|
#
|
10
10
|
# Query Shodan Internet DB
|
11
11
|
#
|
12
|
-
# @param [
|
12
|
+
# @param [Mihari::Models::Artifact] artifact
|
13
13
|
#
|
14
14
|
# @return [Mihari::Structs::Shodan::InternetDBResponse, nil]
|
15
15
|
#
|
16
|
-
def call(
|
17
|
-
client.query
|
16
|
+
def call(artifact)
|
17
|
+
res = client.query(artifact.data)
|
18
|
+
|
19
|
+
artifact.tap do |tapped|
|
20
|
+
tapped.cpes = (res&.cpes || []).map { |cpe| Models::CPE.new(name: cpe) } if tapped.cpes.empty?
|
21
|
+
tapped.ports = (res&.ports || []).map { |port| Models::Port.new(number: port) } if tapped.ports.empty?
|
22
|
+
if tapped.reverse_dns_names.empty?
|
23
|
+
tapped.reverse_dns_names = (res&.hostnames || []).map do |name|
|
24
|
+
Models::ReverseDnsName.new(name: name)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# @param [Mihari::Models::Artifact] artifact
|
32
|
+
#
|
33
|
+
# @return [Boolean]
|
34
|
+
#
|
35
|
+
def callable?(artifact)
|
36
|
+
false unless supported_data_types.include?(artifact.data_type)
|
18
37
|
end
|
19
|
-
memo_wise :call
|
20
38
|
|
21
39
|
private
|
22
40
|
|
41
|
+
#
|
42
|
+
# @param [Mihari::Models::Artifact] artifact
|
43
|
+
#
|
44
|
+
# @return [Boolean]
|
45
|
+
#
|
46
|
+
def callable_relationships?(artifact)
|
47
|
+
artifact.cpes.empty? || artifact.ports.empty? || artifact.reverse_dns_names.empty?
|
48
|
+
end
|
49
|
+
|
50
|
+
def supported_data_types
|
51
|
+
%w[ip]
|
52
|
+
end
|
53
|
+
|
23
54
|
def client
|
24
55
|
@client ||= Clients::ShodanInternetDB.new(timeout: timeout)
|
25
56
|
end
|
@@ -8,58 +8,64 @@ module Mihari
|
|
8
8
|
# Whois enricher
|
9
9
|
#
|
10
10
|
class Whois < Base
|
11
|
+
prepend MemoWise
|
12
|
+
|
13
|
+
#
|
14
|
+
# Query IAIA Whois API
|
11
15
|
#
|
12
|
-
# @param [
|
16
|
+
# @param [Mihari::Models::Artifact] artifact
|
13
17
|
#
|
14
|
-
def
|
15
|
-
|
18
|
+
def call(artifact)
|
19
|
+
return if artifact.domain.nil?
|
20
|
+
|
21
|
+
domain = PublicSuffix.domain(artifact.domain)
|
22
|
+
record = memoized_lookup(domain)
|
23
|
+
return if record.parser.available?
|
24
|
+
|
25
|
+
artifact.whois_record ||= Models::WhoisRecord.new(
|
26
|
+
domain: domain,
|
27
|
+
created_on: get_created_on(record.parser),
|
28
|
+
updated_on: get_updated_on(record.parser),
|
29
|
+
expires_on: get_expires_on(record.parser),
|
30
|
+
registrar: get_registrar(record.parser),
|
31
|
+
contacts: get_contacts(record.parser)
|
32
|
+
)
|
16
33
|
end
|
17
34
|
|
35
|
+
private
|
36
|
+
|
18
37
|
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# @param [String] domain
|
38
|
+
# @param [Mihari::Models::Artifact] artifact
|
22
39
|
#
|
23
|
-
# @return [
|
40
|
+
# @return [Boolean]
|
24
41
|
#
|
25
|
-
def
|
26
|
-
|
42
|
+
def callable_relationships?(artifact)
|
43
|
+
artifact.whois_record.nil?
|
27
44
|
end
|
28
45
|
|
29
|
-
|
46
|
+
def supported_data_types
|
47
|
+
%w[url domain]
|
48
|
+
end
|
30
49
|
|
31
50
|
#
|
32
51
|
# @param [String] domain
|
33
52
|
#
|
34
53
|
# @return [Mihari::Models::WhoisRecord, nil]
|
35
54
|
#
|
36
|
-
def
|
37
|
-
|
38
|
-
parser = record.parser
|
39
|
-
return nil if parser.available?
|
40
|
-
|
41
|
-
Models::WhoisRecord.new(
|
42
|
-
domain: domain,
|
43
|
-
created_on: get_created_on(parser),
|
44
|
-
updated_on: get_updated_on(parser),
|
45
|
-
expires_on: get_expires_on(parser),
|
46
|
-
registrar: get_registrar(parser),
|
47
|
-
contacts: get_contacts(parser)
|
48
|
-
)
|
55
|
+
def memoized_lookup(domain)
|
56
|
+
whois.lookup domain
|
49
57
|
end
|
50
|
-
memo_wise :
|
58
|
+
memo_wise :memoized_lookup
|
51
59
|
|
52
60
|
#
|
53
61
|
# @return [::Whois::Client]
|
54
62
|
#
|
55
63
|
def whois
|
56
|
-
@whois ||=
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end
|
62
|
-
end.last
|
64
|
+
@whois ||= lambda do
|
65
|
+
return ::Whois::Client.new if timeout.nil?
|
66
|
+
|
67
|
+
::Whois::Client.new(timeout: timeout)
|
68
|
+
end.call
|
63
69
|
end
|
64
70
|
|
65
71
|
#
|
@@ -8,12 +8,12 @@ module Mihari
|
|
8
8
|
expose :data_type, documentation: { type: String, required: true }, as: :dataType
|
9
9
|
expose :source, documentation: { type: String, required: true }
|
10
10
|
expose :query, documentation: { type: String, required: false }
|
11
|
-
expose :metadata, documentation: { type: Hash }
|
12
11
|
expose :created_at, documentation: { type: DateTime, required: true }, as: :createdAt
|
12
|
+
expose :tags, using: Entities::Tag, documentation: { type: Entities::Tag, is_array: true, required: true }
|
13
13
|
end
|
14
14
|
|
15
15
|
class Artifact < BaseArtifact
|
16
|
-
expose :
|
16
|
+
expose :metadata, documentation: { type: Hash }
|
17
17
|
expose :autonomous_system, using: Entities::AutonomousSystem,
|
18
18
|
documentation: { type: Entities::AutonomousSystem, required: false }, as: :autonomousSystem
|
19
19
|
expose :geolocation, using: Entities::Geolocation, documentation: { type: Entities::Geolocation, required: false }
|
@@ -36,6 +36,10 @@ module Mihari
|
|
36
36
|
as: :ports do |status, _options|
|
37
37
|
status.ports.empty? ? nil : status.ports
|
38
38
|
end
|
39
|
+
expose :vulnerabilities, using: Vulnerability, documentation: { type: Vulnerability, is_array: true, required: false },
|
40
|
+
as: :vulnerabilities do |status, _options|
|
41
|
+
status.vulnerabilities.empty? ? nil : status.vulnerabilities
|
42
|
+
end
|
39
43
|
end
|
40
44
|
|
41
45
|
class ArtifactsWithPagination < Pagination
|
data/lib/mihari/entities/cpe.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module Mihari
|
4
4
|
module Entities
|
5
5
|
class CPE < Grape::Entity
|
6
|
-
expose :
|
6
|
+
expose :name, documentation: { type: String, required: true }
|
7
7
|
expose :created_at, documentation: { type: DateTime, required: true }, as: :createdAt
|
8
8
|
end
|
9
9
|
end
|
data/lib/mihari/entities/port.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module Mihari
|
4
4
|
module Entities
|
5
5
|
class Port < Grape::Entity
|
6
|
-
expose :
|
6
|
+
expose :number, documentation: { type: Integer, required: true }
|
7
7
|
expose :created_at, documentation: { type: DateTime, required: true }, as: :createdAt
|
8
8
|
end
|
9
9
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Entities
|
5
|
+
class Vulnerability < Grape::Entity
|
6
|
+
expose :name, documentation: { type: String, required: true }
|
7
|
+
expose :created_at, documentation: { type: DateTime, required: true }, as: :createdAt
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
data/lib/mihari/errors.rb
CHANGED
data/lib/mihari/models/alert.rb
CHANGED
@@ -6,6 +6,18 @@ module Mihari
|
|
6
6
|
# Alert model
|
7
7
|
#
|
8
8
|
class Alert < ActiveRecord::Base
|
9
|
+
# @!attribute [r] id
|
10
|
+
# @return [Integer, nil]
|
11
|
+
|
12
|
+
# @!attribute [rw] created_at
|
13
|
+
# @return [DateTime]
|
14
|
+
|
15
|
+
# @!attribute [r] rule
|
16
|
+
# @return [Mihari::Models::Rule]
|
17
|
+
|
18
|
+
# @!attribute [r] artifacts
|
19
|
+
# @return [Array<Mihari::Models::Artifact>]
|
20
|
+
|
9
21
|
belongs_to :rule
|
10
22
|
|
11
23
|
has_many :artifacts, dependent: :destroy
|
@@ -17,6 +17,90 @@ module Mihari
|
|
17
17
|
# Artifact model
|
18
18
|
#
|
19
19
|
class Artifact < ActiveRecord::Base
|
20
|
+
# @!attribute [r] id
|
21
|
+
# @return [Integer, nil]
|
22
|
+
|
23
|
+
# @!attribute [rw] data
|
24
|
+
# @return [String]
|
25
|
+
|
26
|
+
# @!attribute [rw] data_type
|
27
|
+
# @return [String]
|
28
|
+
|
29
|
+
# @!attribute [rw] source
|
30
|
+
# @return [String, nil]
|
31
|
+
|
32
|
+
# @!attribute [rw] query
|
33
|
+
# @return [String, nil]
|
34
|
+
|
35
|
+
# @!attribute [rw] metadata
|
36
|
+
# @return [Hash, nil]
|
37
|
+
|
38
|
+
# @!attribute [rw] created_at
|
39
|
+
# @return [DateTime]
|
40
|
+
|
41
|
+
# @!attribute [r] alert
|
42
|
+
# @return [Mihari::Models::Alert]
|
43
|
+
|
44
|
+
# @!attribute [r] rule
|
45
|
+
# @return [Mihari::Models::Rule]
|
46
|
+
|
47
|
+
# @!attribute [rw] autonomous_system
|
48
|
+
# @return [Mihari::Models::AutonomousSystem, nil]
|
49
|
+
|
50
|
+
# @!attribute [rw] geolocation
|
51
|
+
# @return [Mihari::Models::Geolocation, nil]
|
52
|
+
|
53
|
+
# @!attribute [rw] whois_record
|
54
|
+
# @return [Mihari::Models::WhoisRecord, nil]
|
55
|
+
|
56
|
+
# @!attribute [rw] cpes
|
57
|
+
# @return [Array<Mihari::Models::CPE>]
|
58
|
+
|
59
|
+
# @!attribute [rw] dns_records
|
60
|
+
# @return [Array<Mihari::Models::DnsRecord>]
|
61
|
+
|
62
|
+
# @!attribute [rw] ports
|
63
|
+
# @return [Array<Mihari::Models::Port>]
|
64
|
+
|
65
|
+
# @!attribute [rw] reverse_dns_names
|
66
|
+
# @return [Array<Mihari::Models::ReverseDnsName>]
|
67
|
+
|
68
|
+
# @!attribute [rw] vulnerabilities
|
69
|
+
# @return [Array<Mihari::Models::Vulnerability>]
|
70
|
+
|
71
|
+
# @!attribute [r] alert
|
72
|
+
# @return [Mihari::Models::Alert]
|
73
|
+
|
74
|
+
# @!attribute [r] rule
|
75
|
+
# @return [Mihari::Models::Rule]
|
76
|
+
|
77
|
+
# @!attribute [rw] autonomous_system
|
78
|
+
# @return [Mihari::Models::AutonomousSystem, nil]
|
79
|
+
|
80
|
+
# @!attribute [rw] geolocation
|
81
|
+
# @return [Mihari::Models::Geolocation, nil]
|
82
|
+
|
83
|
+
# @!attribute [rw] whois_record
|
84
|
+
# @return [Mihari::Models::WhoisRecord, nil]
|
85
|
+
|
86
|
+
# @!attribute [rw] cpes
|
87
|
+
# @return [Array<Mihari::Models::CPE>]
|
88
|
+
|
89
|
+
# @!attribute [rw] dns_records
|
90
|
+
# @return [Array<Mihari::Models::DnsRecord>]
|
91
|
+
|
92
|
+
# @!attribute [rw] ports
|
93
|
+
# @return [Array<Mihari::Models::Port>]
|
94
|
+
|
95
|
+
# @!attribute [rw] reverse_dns_names
|
96
|
+
# @return [Array<Mihari::Models::ReverseDnsName>]
|
97
|
+
|
98
|
+
# @!attribute [rw] vulnerabilities
|
99
|
+
# @return [Array<Mihari::Models::Vulnerability>]
|
100
|
+
|
101
|
+
# @!attribute [rw] tags
|
102
|
+
# @return [Array<Mihari::Models::Tag>]
|
103
|
+
|
20
104
|
belongs_to :alert
|
21
105
|
|
22
106
|
has_one :autonomous_system, dependent: :destroy
|
@@ -28,6 +112,8 @@ module Mihari
|
|
28
112
|
has_many :dns_records, dependent: :destroy
|
29
113
|
has_many :ports, dependent: :destroy
|
30
114
|
has_many :reverse_dns_names, dependent: :destroy
|
115
|
+
has_many :vulnerabilities, dependent: :destroy
|
116
|
+
|
31
117
|
has_many :tags, through: :alert
|
32
118
|
|
33
119
|
include ActiveModel::Validations
|
@@ -38,13 +124,14 @@ module Mihari
|
|
38
124
|
attributes :id, :data, :data_type, :source, :query, :created_at, "alert.id", "rule.id", "rule.title",
|
39
125
|
"rule.description"
|
40
126
|
attributes tag: "tags.name"
|
41
|
-
attributes asn: "autonomous_system.
|
127
|
+
attributes asn: "autonomous_system.number"
|
42
128
|
attributes country_code: "geolocation.country_code"
|
43
129
|
attributes "dns_record.value": "dns_records.value"
|
44
130
|
attributes "dns_record.resource": "dns_records.resource"
|
45
131
|
attributes reverse_dns_name: "reverse_dns_names.name"
|
46
132
|
attributes cpe: "cpes.name"
|
47
|
-
attributes
|
133
|
+
attributes vuln: "vulnerabilities.name"
|
134
|
+
attributes port: "ports.number"
|
48
135
|
end
|
49
136
|
|
50
137
|
validates_with ArtifactValidator
|
@@ -54,6 +141,14 @@ module Mihari
|
|
54
141
|
# @return [String, nil]
|
55
142
|
attr_accessor :rule_id
|
56
143
|
|
144
|
+
before_destroy do
|
145
|
+
@alert = alert
|
146
|
+
end
|
147
|
+
|
148
|
+
after_destroy do
|
149
|
+
@alert.destroy unless @alert.artifacts.any?
|
150
|
+
end
|
151
|
+
|
57
152
|
#
|
58
153
|
# Check uniqueness
|
59
154
|
#
|
@@ -79,122 +174,25 @@ module Mihari
|
|
79
174
|
artifact.created_at < decayed_at
|
80
175
|
end
|
81
176
|
|
82
|
-
|
83
|
-
|
84
|
-
#
|
85
|
-
# @param [Mihari::Enrichers::Whois] enricher
|
86
|
-
#
|
87
|
-
def enrich_whois(enricher = Enrichers::Whois.new)
|
88
|
-
return unless can_enrich_whois?
|
89
|
-
|
90
|
-
self.whois_record = Services::WhoisRecordBuilder.call(domain, enricher: enricher)
|
91
|
-
end
|
92
|
-
|
93
|
-
#
|
94
|
-
# Enrich DNS records
|
95
|
-
#
|
96
|
-
# @param [Mihari::Enrichers::GooglePublicDNS] enricher
|
97
|
-
#
|
98
|
-
def enrich_dns(enricher = Enrichers::GooglePublicDNS.new)
|
99
|
-
return unless can_enrich_dns?
|
100
|
-
|
101
|
-
self.dns_records = Services::DnsRecordBuilder.call(domain, enricher: enricher)
|
102
|
-
end
|
103
|
-
|
104
|
-
#
|
105
|
-
# Enrich reverse DNS names
|
106
|
-
#
|
107
|
-
# @param [Mihari::Enrichers::Shodan] enricher
|
108
|
-
#
|
109
|
-
def enrich_reverse_dns(enricher = Enrichers::Shodan.new)
|
110
|
-
return unless can_enrich_reverse_dns?
|
111
|
-
|
112
|
-
self.reverse_dns_names = Services::ReverseDnsNameBuilder.call(data, enricher: enricher)
|
113
|
-
end
|
114
|
-
|
115
|
-
#
|
116
|
-
# Enrich geolocation
|
117
|
-
#
|
118
|
-
# @param [Mihari::Enrichers::IPInfo] enricher
|
119
|
-
#
|
120
|
-
def enrich_geolocation(enricher = Enrichers::MMDB.new)
|
121
|
-
return unless can_enrich_geolocation?
|
122
|
-
|
123
|
-
self.geolocation = Services::GeolocationBuilder.call(data, enricher: enricher)
|
124
|
-
end
|
125
|
-
|
126
|
-
#
|
127
|
-
# Enrich AS
|
128
|
-
#
|
129
|
-
# @param [Mihari::Enrichers::IPInfo] enricher
|
130
|
-
#
|
131
|
-
def enrich_autonomous_system(enricher = Enrichers::MMDB.new)
|
132
|
-
return unless can_enrich_autonomous_system?
|
133
|
-
|
134
|
-
self.autonomous_system = Services::AutonomousSystemBuilder.call(data, enricher: enricher)
|
135
|
-
end
|
136
|
-
|
137
|
-
#
|
138
|
-
# Enrich ports
|
139
|
-
#
|
140
|
-
# @param [Mihari::Enrichers::Shodan] enricher
|
141
|
-
#
|
142
|
-
def enrich_ports(enricher = Enrichers::Shodan.new)
|
143
|
-
return unless can_enrich_ports?
|
144
|
-
|
145
|
-
self.ports = Services::PortBuilder.call(data, enricher: enricher)
|
177
|
+
def enrichable?
|
178
|
+
!callable_enrichers.empty?
|
146
179
|
end
|
147
180
|
|
148
|
-
|
149
|
-
|
150
|
-
#
|
151
|
-
# @param [Mihari::Enrichers::Shodan] enricher
|
152
|
-
#
|
153
|
-
def enrich_cpes(enricher = Enrichers::Shodan.new)
|
154
|
-
return unless can_enrich_cpes?
|
155
|
-
|
156
|
-
self.cpes = Services::CPEBuilder.call(data, enricher: enricher)
|
181
|
+
def enrich
|
182
|
+
callable_enrichers.each { |enricher| enricher.result self }
|
157
183
|
end
|
158
184
|
|
159
185
|
#
|
160
|
-
#
|
161
|
-
#
|
162
|
-
def enrich_all
|
163
|
-
enrich_autonomous_system mmdb
|
164
|
-
enrich_dns
|
165
|
-
enrich_geolocation mmdb
|
166
|
-
enrich_reverse_dns shodan
|
167
|
-
enrich_whois
|
168
|
-
enrich_ports shodan
|
169
|
-
enrich_cpes shodan
|
170
|
-
end
|
171
|
-
|
172
|
-
ENRICH_METHODS_BY_ENRICHER = {
|
173
|
-
Enrichers::Whois => %i[
|
174
|
-
enrich_whois
|
175
|
-
],
|
176
|
-
Enrichers::MMDB => %i[
|
177
|
-
enrich_autonomous_system
|
178
|
-
enrich_geolocation
|
179
|
-
],
|
180
|
-
Enrichers::Shodan => %i[
|
181
|
-
enrich_ports
|
182
|
-
enrich_cpes
|
183
|
-
enrich_reverse_dns
|
184
|
-
],
|
185
|
-
Enrichers::GooglePublicDNS => %i[
|
186
|
-
enrich_dns
|
187
|
-
]
|
188
|
-
}.freeze
|
189
|
-
|
190
|
-
#
|
191
|
-
# Enrich by name of enricher
|
192
|
-
#
|
193
|
-
# @param [Mihari::Enrichers::Base] enricher
|
186
|
+
# @return [String, nil]
|
194
187
|
#
|
195
|
-
def
|
196
|
-
|
197
|
-
|
188
|
+
def domain
|
189
|
+
case data_type
|
190
|
+
when "domain"
|
191
|
+
data
|
192
|
+
when "url"
|
193
|
+
host = Addressable::URI.parse(data).host
|
194
|
+
(DataType.type(host) == "ip") ? nil : host
|
195
|
+
end
|
198
196
|
end
|
199
197
|
|
200
198
|
class << self
|
@@ -209,60 +207,21 @@ module Mihari
|
|
209
207
|
|
210
208
|
private
|
211
209
|
|
212
|
-
def set_data_type
|
213
|
-
self.data_type = DataType.type(data)
|
214
|
-
end
|
215
|
-
|
216
|
-
def set_rule_id
|
217
|
-
@set_rule_id ||= nil
|
218
|
-
end
|
219
|
-
|
220
|
-
def mmdb
|
221
|
-
@mmdb ||= Enrichers::MMDB.new
|
222
|
-
end
|
223
|
-
|
224
|
-
def shodan
|
225
|
-
@shodan ||= Enrichers::Shodan.new
|
226
|
-
end
|
227
|
-
|
228
210
|
#
|
229
|
-
# @return [
|
211
|
+
# @return [Array<Mihari::Enrichers::Base>]
|
230
212
|
#
|
231
|
-
def
|
232
|
-
|
233
|
-
|
234
|
-
data
|
235
|
-
when "url"
|
236
|
-
Addressable::URI.parse(data).host
|
213
|
+
def callable_enrichers
|
214
|
+
@callable_enrichers ||= Mihari.enrichers.map(&:new).select do |enricher|
|
215
|
+
enricher.callable?(self)
|
237
216
|
end
|
238
217
|
end
|
239
218
|
|
240
|
-
def
|
241
|
-
|
242
|
-
end
|
243
|
-
|
244
|
-
def can_enrich_dns?
|
245
|
-
%w[domain url].include?(data_type) && dns_records.empty?
|
246
|
-
end
|
247
|
-
|
248
|
-
def can_enrich_reverse_dns?
|
249
|
-
data_type == "ip" && reverse_dns_names.empty?
|
250
|
-
end
|
251
|
-
|
252
|
-
def can_enrich_geolocation?
|
253
|
-
data_type == "ip" && geolocation.nil?
|
254
|
-
end
|
255
|
-
|
256
|
-
def can_enrich_autonomous_system?
|
257
|
-
data_type == "ip" && autonomous_system.nil?
|
258
|
-
end
|
259
|
-
|
260
|
-
def can_enrich_ports?
|
261
|
-
data_type == "ip" && ports.empty?
|
219
|
+
def set_data_type
|
220
|
+
self.data_type = DataType.type(data)
|
262
221
|
end
|
263
222
|
|
264
|
-
def
|
265
|
-
|
223
|
+
def set_rule_id
|
224
|
+
@set_rule_id ||= nil
|
266
225
|
end
|
267
226
|
end
|
268
227
|
end
|