mihari 5.6.1 → 5.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/frontend/package-lock.json +173 -176
- data/frontend/package.json +9 -9
- data/lib/mihari/{base.rb → actor.rb} +16 -2
- data/lib/mihari/analyzers/base.rb +5 -10
- data/lib/mihari/analyzers/censys.rb +1 -1
- data/lib/mihari/analyzers/hunterhow.rb +1 -1
- data/lib/mihari/analyzers/passivetotal.rb +1 -1
- data/lib/mihari/analyzers/pulsedive.rb +1 -1
- data/lib/mihari/analyzers/securitytrails.rb +1 -1
- data/lib/mihari/analyzers/urlscan.rb +1 -1
- data/lib/mihari/analyzers/virustotal.rb +5 -5
- data/lib/mihari/analyzers/zoomeye.rb +3 -3
- data/lib/mihari/clients/crtsh.rb +2 -2
- data/lib/mihari/clients/passivetotal.rb +4 -4
- data/lib/mihari/clients/securitytrails.rb +3 -3
- data/lib/mihari/commands/rule.rb +2 -11
- data/lib/mihari/commands/search.rb +1 -1
- data/lib/mihari/emitters/base.rb +13 -24
- data/lib/mihari/emitters/database.rb +7 -9
- data/lib/mihari/emitters/misp.rb +14 -38
- data/lib/mihari/emitters/slack.rb +14 -11
- data/lib/mihari/emitters/the_hive.rb +16 -44
- data/lib/mihari/emitters/webhook.rb +31 -21
- data/lib/mihari/enrichers/base.rb +1 -6
- data/lib/mihari/enrichers/whois.rb +1 -1
- data/lib/mihari/models/alert.rb +75 -73
- data/lib/mihari/models/artifact.rb +182 -180
- data/lib/mihari/models/autonomous_system.rb +22 -20
- data/lib/mihari/models/cpe.rb +21 -19
- data/lib/mihari/models/dns.rb +24 -22
- data/lib/mihari/models/geolocation.rb +22 -20
- data/lib/mihari/models/port.rb +21 -19
- data/lib/mihari/models/reverse_dns.rb +21 -19
- data/lib/mihari/models/rule.rb +67 -65
- data/lib/mihari/models/tag.rb +5 -3
- data/lib/mihari/models/tagging.rb +5 -3
- data/lib/mihari/models/whois.rb +18 -16
- data/lib/mihari/rule.rb +352 -0
- data/lib/mihari/schemas/analyzer.rb +94 -87
- data/lib/mihari/schemas/emitter.rb +9 -5
- data/lib/mihari/schemas/enricher.rb +8 -4
- data/lib/mihari/schemas/mixins.rb +15 -0
- data/lib/mihari/schemas/rule.rb +3 -10
- data/lib/mihari/services/alert_builder.rb +1 -1
- data/lib/mihari/services/alert_proxy.rb +10 -6
- data/lib/mihari/services/alert_runner.rb +4 -4
- data/lib/mihari/services/rule_builder.rb +3 -3
- data/lib/mihari/services/rule_runner.rb +5 -5
- data/lib/mihari/structs/binaryedge.rb +1 -1
- data/lib/mihari/structs/censys.rb +6 -6
- data/lib/mihari/structs/config.rb +1 -1
- data/lib/mihari/structs/greynoise.rb +5 -5
- data/lib/mihari/structs/hunterhow.rb +3 -3
- data/lib/mihari/structs/onyphe.rb +5 -5
- data/lib/mihari/structs/shodan.rb +6 -6
- data/lib/mihari/structs/urlscan.rb +3 -3
- data/lib/mihari/structs/virustotal_intelligence.rb +3 -3
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/endpoints/alerts.rb +4 -4
- data/lib/mihari/web/endpoints/artifacts.rb +6 -6
- data/lib/mihari/web/endpoints/rules.rb +10 -17
- data/lib/mihari/web/endpoints/tags.rb +2 -2
- data/lib/mihari/web/public/assets/{index-9cc489e6.js → index-28d4c79d.js} +48 -48
- data/lib/mihari/web/public/index.html +1 -1
- data/lib/mihari.rb +6 -8
- data/mihari.gemspec +1 -2
- data/requirements.txt +1 -1
- metadata +8 -22
- data/lib/mihari/analyzers/rule.rb +0 -232
- data/lib/mihari/services/rule_proxy.rb +0 -182
|
@@ -1,229 +1,231 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
class ArtifactValidator < ActiveModel::Validator
|
|
4
|
-
def validate(record)
|
|
5
|
-
return if record.data_type
|
|
6
|
-
|
|
7
|
-
record.errors.add :data, "#{record.data} is not supported"
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
3
|
module Mihari
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
module Models
|
|
5
|
+
class ArtifactValidator < ActiveModel::Validator
|
|
6
|
+
def validate(record)
|
|
7
|
+
return if record.data_type
|
|
14
8
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
record.errors.add :data, "#{record.data} is not supported"
|
|
10
|
+
end
|
|
11
|
+
end
|
|
18
12
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
has_many :ports, dependent: :destroy
|
|
22
|
-
has_many :reverse_dns_names, dependent: :destroy
|
|
13
|
+
class Artifact < ActiveRecord::Base
|
|
14
|
+
belongs_to :alert
|
|
23
15
|
|
|
24
|
-
|
|
16
|
+
has_one :autonomous_system, dependent: :destroy
|
|
17
|
+
has_one :geolocation, dependent: :destroy
|
|
18
|
+
has_one :whois_record, dependent: :destroy
|
|
25
19
|
|
|
26
|
-
|
|
20
|
+
has_many :cpes, dependent: :destroy
|
|
21
|
+
has_many :dns_records, dependent: :destroy
|
|
22
|
+
has_many :ports, dependent: :destroy
|
|
23
|
+
has_many :reverse_dns_names, dependent: :destroy
|
|
27
24
|
|
|
28
|
-
|
|
29
|
-
attr_accessor :tags
|
|
25
|
+
include ActiveModel::Validations
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
attr_accessor :rule_id
|
|
27
|
+
validates_with ArtifactValidator
|
|
33
28
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
data_ = attrs[:data]
|
|
29
|
+
# @return [Array<Mihari::Tag>] Tags
|
|
30
|
+
attr_accessor :tags
|
|
37
31
|
|
|
38
|
-
|
|
32
|
+
# @return [String, nil] Rule ID
|
|
33
|
+
attr_accessor :rule_id
|
|
39
34
|
|
|
40
|
-
|
|
35
|
+
def initialize(*args, **kwargs)
|
|
36
|
+
attrs = args.first || kwargs
|
|
37
|
+
data_ = attrs[:data]
|
|
41
38
|
|
|
42
|
-
|
|
39
|
+
raise TypeError if data_.is_a?(Array) || data_.is_a?(Hash)
|
|
43
40
|
|
|
44
|
-
|
|
45
|
-
@rule_id = ""
|
|
46
|
-
end
|
|
41
|
+
super(*args, **kwargs)
|
|
47
42
|
|
|
48
|
-
|
|
49
|
-
# Check uniqueness of artifact
|
|
50
|
-
#
|
|
51
|
-
# @param [Time, nil] base_time Base time to check decaying
|
|
52
|
-
# @param [Integer, nil] artifact_lifetime Artifact lifetime (TTL) in seconds
|
|
53
|
-
#
|
|
54
|
-
# @return [Boolean] true if it is unique. Otherwise false.
|
|
55
|
-
#
|
|
56
|
-
def unique?(base_time: nil, artifact_lifetime: nil)
|
|
57
|
-
artifact = self.class.joins(:alert).where(
|
|
58
|
-
data: data,
|
|
59
|
-
alert: { rule_id: rule_id }
|
|
60
|
-
).order(created_at: :desc).first
|
|
61
|
-
return true if artifact.nil?
|
|
62
|
-
|
|
63
|
-
# check whether the artifact is decayed or not
|
|
64
|
-
return false if artifact_lifetime.nil?
|
|
65
|
-
|
|
66
|
-
# use the current UTC time if base_time is not given (for testing)
|
|
67
|
-
base_time ||= Time.now.utc
|
|
68
|
-
|
|
69
|
-
decayed_at = base_time - (artifact_lifetime || -1).seconds
|
|
70
|
-
artifact.created_at < decayed_at
|
|
71
|
-
end
|
|
43
|
+
self.data_type = TypeChecker.type(data)
|
|
72
44
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
# @param [Mihari::Enrichers::Whois] enricher
|
|
77
|
-
#
|
|
78
|
-
def enrich_whois(enricher = Enrichers::Whois.new)
|
|
79
|
-
return unless can_enrich_whois?
|
|
45
|
+
@tags = []
|
|
46
|
+
@rule_id = ""
|
|
47
|
+
end
|
|
80
48
|
|
|
81
|
-
|
|
82
|
-
|
|
49
|
+
#
|
|
50
|
+
# Check uniqueness of artifact
|
|
51
|
+
#
|
|
52
|
+
# @param [Time, nil] base_time Base time to check decaying
|
|
53
|
+
# @param [Integer, nil] artifact_lifetime Artifact lifetime (TTL) in seconds
|
|
54
|
+
#
|
|
55
|
+
# @return [Boolean] true if it is unique. Otherwise false.
|
|
56
|
+
#
|
|
57
|
+
def unique?(base_time: nil, artifact_lifetime: nil)
|
|
58
|
+
artifact = self.class.joins(:alert).where(
|
|
59
|
+
data: data,
|
|
60
|
+
alert: { rule_id: rule_id }
|
|
61
|
+
).order(created_at: :desc).first
|
|
62
|
+
return true if artifact.nil?
|
|
63
|
+
|
|
64
|
+
# check whether the artifact is decayed or not
|
|
65
|
+
return false if artifact_lifetime.nil?
|
|
66
|
+
|
|
67
|
+
# use the current UTC time if base_time is not given (for testing)
|
|
68
|
+
base_time ||= Time.now.utc
|
|
69
|
+
|
|
70
|
+
decayed_at = base_time - (artifact_lifetime || -1).seconds
|
|
71
|
+
artifact.created_at < decayed_at
|
|
72
|
+
end
|
|
83
73
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
74
|
+
#
|
|
75
|
+
# Enrich(add) whois record
|
|
76
|
+
#
|
|
77
|
+
# @param [Mihari::Enrichers::Whois] enricher
|
|
78
|
+
#
|
|
79
|
+
def enrich_whois(enricher = Enrichers::Whois.new)
|
|
80
|
+
return unless can_enrich_whois?
|
|
91
81
|
|
|
92
|
-
|
|
93
|
-
|
|
82
|
+
self.whois_record = WhoisRecord.build_by_domain(normalize_as_domain(data), enricher: enricher)
|
|
83
|
+
end
|
|
94
84
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
85
|
+
#
|
|
86
|
+
# Enrich(add) DNS records
|
|
87
|
+
#
|
|
88
|
+
# @param [Mihari::Enrichers::GooglePublicDNS] enricher
|
|
89
|
+
#
|
|
90
|
+
def enrich_dns(enricher = Enrichers::GooglePublicDNS.new)
|
|
91
|
+
return unless can_enrich_dns?
|
|
102
92
|
|
|
103
|
-
|
|
104
|
-
|
|
93
|
+
self.dns_records = DnsRecord.build_by_domain(normalize_as_domain(data), enricher: enricher)
|
|
94
|
+
end
|
|
105
95
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
96
|
+
#
|
|
97
|
+
# Enrich(add) reverse DNS names
|
|
98
|
+
#
|
|
99
|
+
# @param [Mihari::Enrichers::Shodan] enricher
|
|
100
|
+
#
|
|
101
|
+
def enrich_reverse_dns(enricher = Enrichers::Shodan.new)
|
|
102
|
+
return unless can_enrich_revese_dns?
|
|
113
103
|
|
|
114
|
-
|
|
115
|
-
|
|
104
|
+
self.reverse_dns_names = ReverseDnsName.build_by_ip(data, enricher: enricher)
|
|
105
|
+
end
|
|
116
106
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
107
|
+
#
|
|
108
|
+
# Enrich(add) geolocation
|
|
109
|
+
#
|
|
110
|
+
# @param [Mihari::Enrichers::IPInfo] enricher
|
|
111
|
+
#
|
|
112
|
+
def enrich_geolocation(enricher = Enrichers::IPInfo.new)
|
|
113
|
+
return unless can_enrich_geolocation?
|
|
124
114
|
|
|
125
|
-
|
|
126
|
-
|
|
115
|
+
self.geolocation = Geolocation.build_by_ip(data, enricher: enricher)
|
|
116
|
+
end
|
|
127
117
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
118
|
+
#
|
|
119
|
+
# Enrich AS
|
|
120
|
+
#
|
|
121
|
+
# @param [Mihari::Enrichers::IPInfo] enricher
|
|
122
|
+
#
|
|
123
|
+
def enrich_autonomous_system(enricher = Enrichers::IPInfo.new)
|
|
124
|
+
return unless can_enrich_autonomous_system?
|
|
135
125
|
|
|
136
|
-
|
|
137
|
-
|
|
126
|
+
self.autonomous_system = AutonomousSystem.build_by_ip(data, enricher: enricher)
|
|
127
|
+
end
|
|
138
128
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
129
|
+
#
|
|
130
|
+
# Enrich ports
|
|
131
|
+
#
|
|
132
|
+
# @param [Mihari::Enrichers::Shodan] enricher
|
|
133
|
+
#
|
|
134
|
+
def enrich_ports(enricher = Enrichers::Shodan.new)
|
|
135
|
+
return unless can_enrich_ports?
|
|
146
136
|
|
|
147
|
-
|
|
148
|
-
|
|
137
|
+
self.ports = Port.build_by_ip(data, enricher: enricher)
|
|
138
|
+
end
|
|
149
139
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
enrich_reverse_dns
|
|
158
|
-
enrich_whois
|
|
159
|
-
enrich_ports
|
|
160
|
-
enrich_cpes
|
|
161
|
-
end
|
|
140
|
+
#
|
|
141
|
+
# Enrich CPEs
|
|
142
|
+
#
|
|
143
|
+
# @param [Mihari::Enrichers::Shodan] enricher
|
|
144
|
+
#
|
|
145
|
+
def enrich_cpes(enricher = Enrichers::Shodan.new)
|
|
146
|
+
return unless can_enrich_cpes?
|
|
162
147
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
148
|
+
self.cpes = CPE.build_by_ip(data, enricher: enricher)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
#
|
|
152
|
+
# Enrich all the enrichable relationships of the artifact
|
|
153
|
+
#
|
|
154
|
+
def enrich_all
|
|
168
155
|
enrich_autonomous_system
|
|
156
|
+
enrich_dns
|
|
169
157
|
enrich_geolocation
|
|
170
|
-
|
|
171
|
-
|
|
158
|
+
enrich_reverse_dns
|
|
159
|
+
enrich_whois
|
|
172
160
|
enrich_ports
|
|
173
161
|
enrich_cpes
|
|
174
|
-
enrich_reverse_dns
|
|
175
|
-
],
|
|
176
|
-
Enrichers::GooglePublicDNS => %i[
|
|
177
|
-
enrich_dns
|
|
178
|
-
]
|
|
179
|
-
}.freeze
|
|
180
|
-
|
|
181
|
-
#
|
|
182
|
-
# Enrich by name of enricher
|
|
183
|
-
#
|
|
184
|
-
# @param [Mihari::Enrichers::Base] enricher
|
|
185
|
-
#
|
|
186
|
-
def enrich_by_enricher(enricher)
|
|
187
|
-
methods = ENRICH_METHODS_BY_ENRICHER[enricher.class] || []
|
|
188
|
-
methods.each do |method|
|
|
189
|
-
send(method, enricher) if respond_to?(method)
|
|
190
162
|
end
|
|
191
|
-
end
|
|
192
163
|
|
|
193
|
-
|
|
164
|
+
ENRICH_METHODS_BY_ENRICHER = {
|
|
165
|
+
Enrichers::Whois => %i[
|
|
166
|
+
enrich_whois
|
|
167
|
+
],
|
|
168
|
+
Enrichers::IPInfo => %i[
|
|
169
|
+
enrich_autonomous_system
|
|
170
|
+
enrich_geolocation
|
|
171
|
+
],
|
|
172
|
+
Enrichers::Shodan => %i[
|
|
173
|
+
enrich_ports
|
|
174
|
+
enrich_cpes
|
|
175
|
+
enrich_reverse_dns
|
|
176
|
+
],
|
|
177
|
+
Enrichers::GooglePublicDNS => %i[
|
|
178
|
+
enrich_dns
|
|
179
|
+
]
|
|
180
|
+
}.freeze
|
|
181
|
+
|
|
182
|
+
#
|
|
183
|
+
# Enrich by name of enricher
|
|
184
|
+
#
|
|
185
|
+
# @param [Mihari::Enrichers::Base] enricher
|
|
186
|
+
#
|
|
187
|
+
def enrich_by_enricher(enricher)
|
|
188
|
+
methods = ENRICH_METHODS_BY_ENRICHER[enricher.class] || []
|
|
189
|
+
methods.each do |method|
|
|
190
|
+
send(method, enricher) if respond_to?(method)
|
|
191
|
+
end
|
|
192
|
+
end
|
|
194
193
|
|
|
195
|
-
|
|
196
|
-
return url_or_domain if data_type == "domain"
|
|
194
|
+
private
|
|
197
195
|
|
|
198
|
-
|
|
199
|
-
|
|
196
|
+
def normalize_as_domain(url_or_domain)
|
|
197
|
+
return url_or_domain if data_type == "domain"
|
|
200
198
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
end
|
|
199
|
+
Addressable::URI.parse(url_or_domain).host
|
|
200
|
+
end
|
|
204
201
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
202
|
+
def can_enrich_whois?
|
|
203
|
+
%w[domain url].include?(data_type) && whois_record.nil?
|
|
204
|
+
end
|
|
208
205
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
206
|
+
def can_enrich_dns?
|
|
207
|
+
%w[domain url].include?(data_type) && dns_records.empty?
|
|
208
|
+
end
|
|
212
209
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
210
|
+
def can_enrich_revese_dns?
|
|
211
|
+
data_type == "ip" && reverse_dns_names.empty?
|
|
212
|
+
end
|
|
216
213
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
214
|
+
def can_enrich_geolocation?
|
|
215
|
+
data_type == "ip" && geolocation.nil?
|
|
216
|
+
end
|
|
220
217
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
218
|
+
def can_enrich_autonomous_system?
|
|
219
|
+
data_type == "ip" && autonomous_system.nil?
|
|
220
|
+
end
|
|
224
221
|
|
|
225
|
-
|
|
226
|
-
|
|
222
|
+
def can_enrich_ports?
|
|
223
|
+
data_type == "ip" && ports.empty?
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def can_enrich_cpes?
|
|
227
|
+
data_type == "ip" && cpes.empty?
|
|
228
|
+
end
|
|
227
229
|
end
|
|
228
230
|
end
|
|
229
231
|
end
|
|
@@ -1,30 +1,32 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Mihari
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
module Models
|
|
5
|
+
class AutonomousSystem < ActiveRecord::Base
|
|
6
|
+
belongs_to :artifact
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
class << self
|
|
9
|
+
include Dry::Monads[:result]
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
11
|
+
#
|
|
12
|
+
# Build AS
|
|
13
|
+
#
|
|
14
|
+
# @param [String] ip
|
|
15
|
+
# @param [Mihari::Enrichers::IPInfo] enricher
|
|
16
|
+
#
|
|
17
|
+
# @return [Mihari::AutonomousSystem, nil]
|
|
18
|
+
#
|
|
19
|
+
def build_by_ip(ip, enricher: Enrichers::IPInfo.new)
|
|
20
|
+
result = enricher.query_result(ip).bind do |res|
|
|
21
|
+
value = res&.asn
|
|
22
|
+
if value.nil?
|
|
23
|
+
Success nil
|
|
24
|
+
else
|
|
25
|
+
Success new(asn: value)
|
|
26
|
+
end
|
|
25
27
|
end
|
|
28
|
+
result.value_or nil
|
|
26
29
|
end
|
|
27
|
-
result.value_or nil
|
|
28
30
|
end
|
|
29
31
|
end
|
|
30
32
|
end
|
data/lib/mihari/models/cpe.rb
CHANGED
|
@@ -1,29 +1,31 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Mihari
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
module Models
|
|
5
|
+
class CPE < ActiveRecord::Base
|
|
6
|
+
belongs_to :artifact
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
class << self
|
|
9
|
+
include Dry::Monads[:result]
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
11
|
+
#
|
|
12
|
+
# Build CPEs
|
|
13
|
+
#
|
|
14
|
+
# @param [String] ip
|
|
15
|
+
# @param [Mihari::Enrichers::Shodan] enricher
|
|
16
|
+
#
|
|
17
|
+
# @return [Array<Mihari::CPE>]
|
|
18
|
+
#
|
|
19
|
+
def build_by_ip(ip, enricher: Enrichers::Shodan.new)
|
|
20
|
+
result = enricher.query_result(ip).bind do |res|
|
|
21
|
+
if res.nil?
|
|
22
|
+
Success []
|
|
23
|
+
else
|
|
24
|
+
Success(res.cpes.map { |cpe| new(cpe: cpe) })
|
|
25
|
+
end
|
|
24
26
|
end
|
|
27
|
+
result.value_or []
|
|
25
28
|
end
|
|
26
|
-
result.value_or []
|
|
27
29
|
end
|
|
28
30
|
end
|
|
29
31
|
end
|
data/lib/mihari/models/dns.rb
CHANGED
|
@@ -1,31 +1,33 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Mihari
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
module Models
|
|
5
|
+
class DnsRecord < ActiveRecord::Base
|
|
6
|
+
belongs_to :artifact
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
class << self
|
|
9
|
+
include Dry::Monads[:result]
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
11
|
+
#
|
|
12
|
+
# Build DNS records
|
|
13
|
+
#
|
|
14
|
+
# @param [String] domain
|
|
15
|
+
# @param [Mihari::Enrichers::Shodan] enricher
|
|
16
|
+
#
|
|
17
|
+
# @return [Array<Mihari::Models::DnsRecord>]
|
|
18
|
+
#
|
|
19
|
+
def build_by_domain(domain, enricher: Enrichers::GooglePublicDNS.new)
|
|
20
|
+
result = enricher.query_result(domain).bind do |responses|
|
|
21
|
+
Success(
|
|
22
|
+
responses.map do |res|
|
|
23
|
+
res.answers.map do |answer|
|
|
24
|
+
new(resource: answer.resource_type, value: answer.data)
|
|
25
|
+
end
|
|
26
|
+
end.flatten
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
result.value_or []
|
|
27
30
|
end
|
|
28
|
-
result.value_or []
|
|
29
31
|
end
|
|
30
32
|
end
|
|
31
33
|
end
|
|
@@ -3,30 +3,32 @@
|
|
|
3
3
|
require "normalize_country"
|
|
4
4
|
|
|
5
5
|
module Mihari
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
module Models
|
|
7
|
+
class Geolocation < ActiveRecord::Base
|
|
8
|
+
belongs_to :artifact
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
class << self
|
|
11
|
+
include Dry::Monads[:result]
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
13
|
+
#
|
|
14
|
+
# Build Geolocation
|
|
15
|
+
#
|
|
16
|
+
# @param [String] ip
|
|
17
|
+
# @param [Mihari::Enrichers::IPinfo] enricher
|
|
18
|
+
#
|
|
19
|
+
# @return [Mihari::Geolocation, nil]
|
|
20
|
+
#
|
|
21
|
+
def build_by_ip(ip, enricher: Enrichers::IPInfo.new)
|
|
22
|
+
result = enricher.query_result(ip).bind do |res|
|
|
23
|
+
value = res&.country_code
|
|
24
|
+
if value.nil?
|
|
25
|
+
Success nil
|
|
26
|
+
else
|
|
27
|
+
Success new(country: NormalizeCountry(value, to: :short), country_code: value)
|
|
28
|
+
end
|
|
27
29
|
end
|
|
30
|
+
result.value_or nil
|
|
28
31
|
end
|
|
29
|
-
result.value_or nil
|
|
30
32
|
end
|
|
31
33
|
end
|
|
32
34
|
end
|
data/lib/mihari/models/port.rb
CHANGED
|
@@ -1,29 +1,31 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Mihari
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
module Models
|
|
5
|
+
class Port < ActiveRecord::Base
|
|
6
|
+
belongs_to :artifact
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
class << self
|
|
9
|
+
include Dry::Monads[:result]
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
11
|
+
#
|
|
12
|
+
# Build ports
|
|
13
|
+
#
|
|
14
|
+
# @param [String] ip
|
|
15
|
+
# @param [Mihari::Enrichers::Shodan] enricher
|
|
16
|
+
#
|
|
17
|
+
# @return [Array<Mihari::Port>]
|
|
18
|
+
#
|
|
19
|
+
def build_by_ip(ip, enricher: Enrichers::Shodan.new)
|
|
20
|
+
result = enricher.query_result(ip).bind do |res|
|
|
21
|
+
if res.nil?
|
|
22
|
+
Success []
|
|
23
|
+
else
|
|
24
|
+
Success(res.ports.map { |port| new(port: port) })
|
|
25
|
+
end
|
|
24
26
|
end
|
|
27
|
+
result.value_or []
|
|
25
28
|
end
|
|
26
|
-
result.value_or []
|
|
27
29
|
end
|
|
28
30
|
end
|
|
29
31
|
end
|