mihari 7.6.1 → 7.6.3
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/.rubocop.yml +25 -5
- data/README.md +1 -0
- data/Rakefile +3 -1
- data/lefthook.yml +4 -4
- data/lib/mihari/clients/crtsh.rb +1 -1
- data/lib/mihari/clients/dnstwister.rb +1 -1
- data/lib/mihari/clients/google_public_dns.rb +1 -1
- data/lib/mihari/clients/mmdb.rb +1 -1
- data/lib/mihari/clients/shodan_internet_db.rb +1 -1
- data/lib/mihari/commands/rule.rb +27 -4
- data/lib/mihari/database.rb +1 -1
- data/lib/mihari/enrichers/base.rb +1 -1
- data/lib/mihari/enrichers/whois.rb +3 -1
- data/lib/mihari/models/artifact.rb +42 -6
- data/lib/mihari/rule.rb +24 -9
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/public/assets/index-BgJUBUyh.css +1 -0
- data/lib/mihari/web/public/assets/index-FQP-p7mX.js +1563 -0
- data/lib/mihari/web/public/index.html +2 -2
- data/lib/mihari/web/public/redoc-static.html +389 -389
- data/mihari.gemspec +44 -42
- data/mkdocs.yml +1 -1
- data/requirements.txt +2 -2
- metadata +126 -99
- data/build_frontend.sh +0 -11
- data/lib/mihari/web/public/assets/index-CNoViC5p.css +0 -1
- data/lib/mihari/web/public/assets/index-ruBsf_QV.js +0 -1783
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0d9b88f5339ebe2064567127db7fac4a4e0c9ec56648c575de2c96fcb16a3af8
|
4
|
+
data.tar.gz: 15f840a496f423dff92dcc34e2f7c4ad39ed7b1a370c053a5f5cdf29c39f84a2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f07c6c65db1dd47634e0f5919d1b6faa8250cc02d255226085c1fd88f6a32e78338a6ddeaa7b0f221e4593af81735635c4652cdfd46b415bfa0e5ecaf08cb0f1
|
7
|
+
data.tar.gz: 5d8411ddbee4e1e466e3521ec611ffba67e52ea3852e3cfce8f095978b60584b15cc541118064d2fd8bfa9e40c14720899efafa006f96543e7947fecbd5b76da
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 3.2
|
3
|
+
NewCops: enable
|
3
4
|
Metrics/BlockLength:
|
4
5
|
Max: 150
|
5
6
|
Exclude:
|
@@ -12,13 +13,32 @@ Metrics/MethodLength:
|
|
12
13
|
Metrics/AbcSize:
|
13
14
|
Max: 50
|
14
15
|
RSpec/MultipleMemoizedHelpers:
|
15
|
-
Max:
|
16
|
+
Max: 15
|
16
17
|
RSpec/ExampleLength:
|
17
18
|
Max: 20
|
18
|
-
RSpec/
|
19
|
-
|
19
|
+
RSpec/NestedGroups:
|
20
|
+
Max: 5
|
21
|
+
RSpec/RepeatedExampleGroupDescription:
|
22
|
+
Enabled: false
|
23
|
+
RSpec/ReceiveMessages:
|
24
|
+
Enabled: false
|
25
|
+
RSpec/MultipleExpectations:
|
26
|
+
Enabled: false
|
27
|
+
RSpec/SpecFilePathFormat:
|
28
|
+
Enabled: false
|
29
|
+
FactoryBot/SyntaxMethods:
|
30
|
+
Enabled: false
|
20
31
|
require:
|
32
|
+
- rubocop-capybara
|
21
33
|
- rubocop-factory_bot
|
34
|
+
- rubocop-performance
|
22
35
|
- rubocop-rake
|
23
36
|
- rubocop-rspec
|
24
37
|
- rubocop-yard
|
38
|
+
- standard
|
39
|
+
- standard-custom
|
40
|
+
- standard-performance
|
41
|
+
inherit_gem:
|
42
|
+
standard: config/base.yml
|
43
|
+
standard-custom: config/base.yml
|
44
|
+
standard-performance: config/base.yml
|
data/README.md
CHANGED
@@ -27,6 +27,7 @@ Mihari supports the following services by default.
|
|
27
27
|
- [SecurityTrails](https://securitytrails.com/)
|
28
28
|
- [Shodan](https://shodan.io)
|
29
29
|
- [urlscan.io](https://urlscan.io)
|
30
|
+
- [Validin](https://validin.com)
|
30
31
|
- [VirusTotal](http://virustotal.com) & [VirusTotal Intelligence](https://www.virustotal.com/gui/intelligence-overview)
|
31
32
|
- [ZoomEye](https://zoomeye.org)
|
32
33
|
|
data/Rakefile
CHANGED
@@ -3,8 +3,9 @@
|
|
3
3
|
require "time"
|
4
4
|
|
5
5
|
require "rspec/core/rake_task"
|
6
|
-
require "
|
6
|
+
require "rubocop/rake_task"
|
7
7
|
|
8
|
+
RuboCop::RakeTask.new
|
8
9
|
RSpec::Core::RakeTask.new(:spec)
|
9
10
|
|
10
11
|
task default: :spec
|
@@ -67,6 +68,7 @@ namespace :build do
|
|
67
68
|
end
|
68
69
|
end
|
69
70
|
|
71
|
+
desc "Build including Swagger doc and frontend assets"
|
70
72
|
task :build do
|
71
73
|
Rake::Task["build:swagger"].invoke
|
72
74
|
Rake::Task["build:frontend"].invoke
|
data/lefthook.yml
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
pre-commit:
|
2
2
|
commands:
|
3
|
-
|
3
|
+
rubocop:
|
4
4
|
glob: "*.rb"
|
5
|
-
run: bundle exec
|
5
|
+
run: bundle exec rubocop --fix {staged_files}
|
6
6
|
stage_fixed: true
|
7
7
|
eslint:
|
8
8
|
root: "frontend/"
|
@@ -19,5 +19,5 @@ pre-commit:
|
|
19
19
|
glob: "*.{js,ts,vue}"
|
20
20
|
run: npm run type-check
|
21
21
|
actionlint:
|
22
|
-
glob: ".github/workflows/*.yaml"
|
23
|
-
run: actionlint
|
22
|
+
glob: ".github/workflows/*.{yaml,yml}"
|
23
|
+
run: actionlint {staged_files}
|
data/lib/mihari/clients/crtsh.rb
CHANGED
data/lib/mihari/clients/mmdb.rb
CHANGED
data/lib/mihari/commands/rule.rb
CHANGED
@@ -26,14 +26,37 @@ module Mihari
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
desc "validate PATH", "Validate
|
29
|
+
desc "validate PATH", "Validate rule(s)"
|
30
30
|
#
|
31
|
-
# Validate
|
31
|
+
# Validate rule(s)
|
32
|
+
#
|
33
|
+
# @param [Array<String>] paths
|
34
|
+
#
|
35
|
+
def validate(*paths)
|
36
|
+
# @type [Array<Mihari::ValidationError>]
|
37
|
+
errors = paths.flat_map { |path| Dir.glob(path) }.map do |path|
|
38
|
+
Dry::Monads::Try[ValidationError] { Mihari::Rule.from_file(path) }
|
39
|
+
end.filter_map do |result|
|
40
|
+
result.exception if result.error?
|
41
|
+
end
|
42
|
+
return if errors.empty?
|
43
|
+
|
44
|
+
errors.each do |error|
|
45
|
+
data = Entities::ErrorMessage.represent(message: error.message, detail: error.detail)
|
46
|
+
warn JSON.pretty_generate(data.as_json)
|
47
|
+
end
|
48
|
+
|
49
|
+
exit 1
|
50
|
+
end
|
51
|
+
|
52
|
+
desc "format PATH", "format a rule"
|
53
|
+
#
|
54
|
+
# Format a rule file
|
32
55
|
#
|
33
56
|
# @param [String] path
|
34
57
|
#
|
35
|
-
def
|
36
|
-
rule = Dry::Monads::Try[ValidationError] { Mihari::Rule.
|
58
|
+
def format(path)
|
59
|
+
rule = Dry::Monads::Try[ValidationError] { Mihari::Rule.from_file(path) }.value!
|
37
60
|
puts rule.data.to_yaml
|
38
61
|
end
|
39
62
|
|
data/lib/mihari/database.rb
CHANGED
@@ -6,7 +6,7 @@ ActiveSupport::Inflector.inflections(:en) { |inflect| inflect.acronym "CPE" }
|
|
6
6
|
#
|
7
7
|
# Mihari v7 DB schema
|
8
8
|
#
|
9
|
-
class V7Schema < ActiveRecord::Migration[7.
|
9
|
+
class V7Schema < ActiveRecord::Migration[7.2]
|
10
10
|
def change
|
11
11
|
create_table :rules, id: :string, if_not_exists: true do |t|
|
12
12
|
t.string :title, null: false
|
@@ -16,7 +16,9 @@ module Mihari
|
|
16
16
|
def call(artifact)
|
17
17
|
return if artifact.domain.nil?
|
18
18
|
|
19
|
-
artifact.
|
19
|
+
artifact.tap do |tapped|
|
20
|
+
tapped.whois_record ||= memoized_lookup(PublicSuffix.domain(artifact.domain))
|
21
|
+
end
|
20
22
|
end
|
21
23
|
|
22
24
|
private
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "ostruct"
|
4
|
+
|
3
5
|
module Mihari
|
4
6
|
module Models
|
5
7
|
#
|
@@ -158,10 +160,7 @@ module Mihari
|
|
158
160
|
# @return [Boolean] true if it is unique. Otherwise false.
|
159
161
|
#
|
160
162
|
def unique?(base_time: nil, artifact_ttl: nil)
|
161
|
-
artifact = self.class.joins(:alert).where(
|
162
|
-
data:,
|
163
|
-
alert: {rule_id:}
|
164
|
-
).order(created_at: :desc).first
|
163
|
+
artifact = self.class.joins(:alert).where(data:, alert: {rule_id:}).order(created_at: :desc).first
|
165
164
|
return true if artifact.nil?
|
166
165
|
|
167
166
|
# check whether the artifact is decayed or not
|
@@ -179,7 +178,32 @@ module Mihari
|
|
179
178
|
end
|
180
179
|
|
181
180
|
def enrich
|
182
|
-
callable_enrichers
|
181
|
+
enrich_by_enrichers callable_enrichers
|
182
|
+
end
|
183
|
+
|
184
|
+
#
|
185
|
+
# @param [Array<Mihari::Enrichers::Base>] enrichers
|
186
|
+
# @param [Boolean] parallel
|
187
|
+
#
|
188
|
+
# @return [Mihari::Models::Artifact]
|
189
|
+
#
|
190
|
+
def enrich_by_enrichers(enrichers)
|
191
|
+
# NOTE: doing parallel with ActiveRecord objects is troublesome (e.g. connection issue, etc.)
|
192
|
+
# so converting the object to an OpenStruct object
|
193
|
+
s = struct
|
194
|
+
results = Parallel.map(enrichers) { |enricher| enricher.result s }
|
195
|
+
enriched = results.compact.map { |result| result.value_or(nil) }.compact
|
196
|
+
|
197
|
+
self.dns_records = enriched.map(&:dns_records).flatten.compact
|
198
|
+
self.cpes = enriched.map(&:cpes).flatten.compact
|
199
|
+
self.ports = enriched.map(&:ports).flatten.compact
|
200
|
+
self.vulnerabilities = enriched.map(&:vulnerabilities).flatten.compact
|
201
|
+
|
202
|
+
self.autonomous_system = enriched.map(&:autonomous_system).compact.first
|
203
|
+
self.geolocation = enriched.map(&:geolocation).compact.first
|
204
|
+
self.whois_record = enriched.map(&:whois_record).compact.first
|
205
|
+
|
206
|
+
self
|
183
207
|
end
|
184
208
|
|
185
209
|
#
|
@@ -195,6 +219,18 @@ module Mihari
|
|
195
219
|
end
|
196
220
|
end
|
197
221
|
|
222
|
+
def struct
|
223
|
+
OpenStruct.new(attributes).tap do |s|
|
224
|
+
s.domain = domain
|
225
|
+
s.cpes ||= []
|
226
|
+
s.dns_records ||= []
|
227
|
+
s.ports ||= []
|
228
|
+
s.reverse_dns_names ||= []
|
229
|
+
s.vulnerabilities ||= []
|
230
|
+
s.tags ||= []
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
198
234
|
class << self
|
199
235
|
# @!method search_by_filter(filter)
|
200
236
|
# @param [Mihari::Structs::Filters::Search] filter
|
@@ -212,7 +248,7 @@ module Mihari
|
|
212
248
|
#
|
213
249
|
def callable_enrichers
|
214
250
|
@callable_enrichers ||= Mihari.enrichers.map(&:new).select do |enricher|
|
215
|
-
enricher.callable?
|
251
|
+
enricher.callable? self
|
216
252
|
end
|
217
253
|
end
|
218
254
|
|
data/lib/mihari/rule.rb
CHANGED
@@ -5,6 +5,9 @@ module Mihari
|
|
5
5
|
include Concerns::FalsePositiveNormalizable
|
6
6
|
include Concerns::FalsePositiveValidatable
|
7
7
|
|
8
|
+
# @return [String, nil]
|
9
|
+
attr_reader :path_or_id
|
10
|
+
|
8
11
|
# @return [Hash]
|
9
12
|
attr_reader :data
|
10
13
|
|
@@ -19,9 +22,11 @@ module Mihari
|
|
19
22
|
#
|
20
23
|
# @param [Hash] data
|
21
24
|
#
|
22
|
-
|
25
|
+
# @param [Object] path_or_id
|
26
|
+
def initialize(path_or_id: nil, **data)
|
23
27
|
super()
|
24
28
|
|
29
|
+
@path_or_id = path_or_id
|
25
30
|
@data = data.deep_symbolize_keys
|
26
31
|
@errors = nil
|
27
32
|
@base_time = Time.now.utc
|
@@ -173,10 +178,7 @@ module Mihari
|
|
173
178
|
#
|
174
179
|
def enriched_artifacts
|
175
180
|
@enriched_artifacts ||= Parallel.map(unique_artifacts) do |artifact|
|
176
|
-
artifact.
|
177
|
-
# NOTE: To apply changes correctly, enrichers should be applied to an artifact serially
|
178
|
-
enrichers.each { |enricher| enricher.result(tapped) }
|
179
|
-
end
|
181
|
+
artifact.enrich_by_enrichers enrichers
|
180
182
|
end
|
181
183
|
end
|
182
184
|
|
@@ -251,16 +253,29 @@ module Mihari
|
|
251
253
|
end
|
252
254
|
|
253
255
|
class << self
|
256
|
+
#
|
257
|
+
# Load rule from YAML file
|
258
|
+
#
|
259
|
+
# @param [String] path
|
260
|
+
#
|
261
|
+
# @return [Mihari::Rule]
|
262
|
+
#
|
263
|
+
def from_file(path)
|
264
|
+
yaml = File.read(path)
|
265
|
+
from_yaml(yaml, path: path)
|
266
|
+
end
|
267
|
+
|
254
268
|
#
|
255
269
|
# Load rule from YAML string
|
256
270
|
#
|
257
271
|
# @param [String] yaml
|
272
|
+
# @param [String, nil] path
|
258
273
|
#
|
259
274
|
# @return [Mihari::Rule]
|
260
275
|
#
|
261
|
-
def from_yaml(yaml)
|
276
|
+
def from_yaml(yaml, path: nil)
|
262
277
|
data = YAML.safe_load(ERB.new(yaml).result, permitted_classes: [Date, Symbol])
|
263
|
-
new(**data)
|
278
|
+
new(path_or_id: path, **data)
|
264
279
|
end
|
265
280
|
|
266
281
|
#
|
@@ -269,7 +284,7 @@ module Mihari
|
|
269
284
|
# @return [Mihari::Rule]
|
270
285
|
#
|
271
286
|
def from_model(model)
|
272
|
-
new(**model.data)
|
287
|
+
new(path_or_id: model.id, **model.data)
|
273
288
|
end
|
274
289
|
end
|
275
290
|
|
@@ -409,7 +424,7 @@ module Mihari
|
|
409
424
|
@data = result.to_h
|
410
425
|
@errors = result.errors
|
411
426
|
|
412
|
-
raise ValidationError.new("
|
427
|
+
raise ValidationError.new("#{path_or_id}: validation failed", errors) if errors?
|
413
428
|
end
|
414
429
|
end
|
415
430
|
end
|
data/lib/mihari/version.rb
CHANGED