mihari 5.5.0 → 5.6.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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/docs/analyzers/passivetotal.md +4 -0
  3. data/docs/analyzers/securitytrails.md +4 -0
  4. data/docs/analyzers/virustotal.md +4 -0
  5. data/docs/analyzers/virustotal_intelligence.md +4 -0
  6. data/docs/emitters/hive.md +1 -1
  7. data/docs/emitters/slack.md +0 -5
  8. data/docs/rule.md +1 -4
  9. data/docs/usage.md +5 -2
  10. data/frontend/src/components/ErrorMessage.vue +0 -1
  11. data/frontend/src/components/alert/Alerts.vue +0 -1
  12. data/frontend/src/components/alert/AlertsWithPagination.vue +0 -1
  13. data/frontend/src/components/alert/AlertsWrapper.vue +0 -6
  14. data/frontend/src/components/alert/Form.vue +1 -3
  15. data/frontend/src/components/artifact/Artifact.vue +0 -17
  16. data/frontend/src/components/artifact/ArtifactWrapper.vue +0 -2
  17. data/frontend/src/components/artifact/WhoisRecord.vue +0 -3
  18. data/frontend/src/components/config/ConfigsWrapper.vue +0 -2
  19. data/frontend/src/components/rule/EditRule.vue +0 -3
  20. data/frontend/src/components/rule/EditRuleWrapper.vue +0 -2
  21. data/frontend/src/components/rule/Form.vue +1 -3
  22. data/frontend/src/components/rule/NewRule.vue +0 -3
  23. data/frontend/src/components/rule/Rule.vue +1 -7
  24. data/frontend/src/components/rule/RuleWrapper.vue +0 -2
  25. data/frontend/src/components/rule/RulesWrapper.vue +0 -6
  26. data/frontend/src/swagger.yaml +254 -254
  27. data/lib/mihari/analyzers/base.rb +4 -41
  28. data/lib/mihari/analyzers/passivetotal.rb +9 -0
  29. data/lib/mihari/analyzers/pulsedive.rb +1 -1
  30. data/lib/mihari/analyzers/rule.rb +24 -59
  31. data/lib/mihari/analyzers/securitytrails.rb +9 -0
  32. data/lib/mihari/analyzers/virustotal.rb +11 -2
  33. data/lib/mihari/analyzers/virustotal_intelligence.rb +16 -0
  34. data/lib/mihari/analyzers/zoomeye.rb +2 -2
  35. data/lib/mihari/base.rb +69 -0
  36. data/lib/mihari/cli/main.rb +36 -0
  37. data/lib/mihari/commands/alert.rb +6 -33
  38. data/lib/mihari/commands/rule.rb +7 -12
  39. data/lib/mihari/commands/search.rb +10 -38
  40. data/lib/mihari/constants.rb +3 -3
  41. data/lib/mihari/emitters/base.rb +3 -33
  42. data/lib/mihari/emitters/database.rb +1 -1
  43. data/lib/mihari/enrichers/base.rb +2 -33
  44. data/lib/mihari/enrichers/google_public_dns.rb +9 -0
  45. data/lib/mihari/schemas/analyzer.rb +24 -24
  46. data/lib/mihari/schemas/emitter.rb +6 -13
  47. data/lib/mihari/schemas/enricher.rb +4 -11
  48. data/lib/mihari/schemas/options.rb +27 -0
  49. data/lib/mihari/schemas/rule.rb +2 -2
  50. data/lib/mihari/services/alert_runner.rb +1 -1
  51. data/lib/mihari/services/rule_runner.rb +1 -11
  52. data/lib/mihari/types.rb +1 -14
  53. data/lib/mihari/version.rb +1 -1
  54. data/lib/mihari/web/public/assets/{index-33165282.css → index-56fc2187.css} +1 -1
  55. data/lib/mihari/web/public/assets/{index-b5d817a3.js → index-9cc489e6.js} +2 -2
  56. data/lib/mihari/web/public/index.html +2 -2
  57. data/lib/mihari.rb +67 -37
  58. data/mihari.gemspec +1 -0
  59. metadata +20 -4
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Mihari
4
4
  module Emitters
5
- class Base
5
+ class Base < Mihari::Base
6
6
  include Dry::Monads[:result, :try]
7
7
 
8
8
  include Mixins::Configurable
@@ -14,9 +14,6 @@ module Mihari
14
14
  # @return [Mihari::Services::Rule]
15
15
  attr_reader :rule
16
16
 
17
- # @return [Hash]
18
- attr_reader :options
19
-
20
17
  #
21
18
  # @param [Array<Mihari::Artifact>] artifacts
22
19
  # @param [Mihari::Services::RuleProxy] rule
@@ -24,37 +21,10 @@ module Mihari
24
21
  # @param [Hash] **_params
25
22
  #
26
23
  def initialize(artifacts:, rule:, options: nil, **_params)
24
+ super(options: options)
25
+
27
26
  @artifacts = artifacts
28
27
  @rule = rule
29
- @options = options || {}
30
- end
31
-
32
- #
33
- # @return [Integer]
34
- #
35
- def retry_interval
36
- options[:retry_interval] || Mihari.config.retry_interval
37
- end
38
-
39
- #
40
- # @return [Boolean]
41
- #
42
- def retry_exponential_backoff
43
- options[:retry_exponential_backoff] || Mihari.config.retry_exponential_backoff
44
- end
45
-
46
- #
47
- # @return [Integer]
48
- #
49
- def retry_times
50
- options[:retry_times] || Mihari.config.retry_times
51
- end
52
-
53
- #
54
- # @return [Integer, nil]
55
- #
56
- def timeout
57
- options[:timeout]
58
28
  end
59
29
 
60
30
  # @return [Boolean]
@@ -13,7 +13,7 @@ module Mihari
13
13
  # @return [Mihari::Alert, nil]
14
14
  #
15
15
  def emit
16
- return nil if artifacts.empty?
16
+ return if artifacts.empty?
17
17
 
18
18
  tags = rule.tags.filter_map { |name| Tag.find_or_create_by(name: name) }.uniq
19
19
  taggings = tags.map { |tag| Tagging.new(tag_id: tag.id) }
@@ -2,45 +2,14 @@
2
2
 
3
3
  module Mihari
4
4
  module Enrichers
5
- class Base
5
+ class Base < Mihari::Base
6
6
  include Mixins::Configurable
7
7
  include Mixins::Retriable
8
8
 
9
9
  include Dry::Monads[:result, :try]
10
10
 
11
- # @return [Hash]
12
- attr_reader :options
13
-
14
11
  def initialize(options: nil)
15
- @options = options || {}
16
- end
17
-
18
- #
19
- # @return [Integer]
20
- #
21
- def retry_interval
22
- options[:retry_interval] || Mihari.config.retry_interval
23
- end
24
-
25
- #
26
- # @return [Boolean]
27
- #
28
- def retry_exponential_backoff
29
- options[:retry_exponential_backoff] || Mihari.config.retry_exponential_backoff
30
- end
31
-
32
- #
33
- # @return [Integer]
34
- #
35
- def retry_times
36
- options[:retry_times] || Mihari.config.retry_times
37
- end
38
-
39
- #
40
- # @return [Integer, nil]
41
- #
42
- def timeout
43
- options[:timeout]
12
+ super(options: options)
44
13
  end
45
14
 
46
15
  def query_result(value)
@@ -38,6 +38,15 @@ module Mihari
38
38
  nil
39
39
  end
40
40
 
41
+ class << self
42
+ #
43
+ # @return [String]
44
+ #
45
+ def class_key
46
+ "google_public_dns"
47
+ end
48
+ end
49
+
41
50
  private
42
51
 
43
52
  def http
@@ -2,37 +2,31 @@
2
2
 
3
3
  module Mihari
4
4
  module Schemas
5
- AnalyzerOptions = Dry::Schema.Params do
6
- optional(:pagination_interval).value(:integer).default(Mihari.config.pagination_interval)
7
- optional(:pagination_limit).value(:integer).default(Mihari.config.pagination_limit)
8
- optional(:retry_times).value(:integer).default(Mihari.config.retry_times)
9
- optional(:retry_interval).value(:integer).default(Mihari.config.retry_interval)
10
- optional(:retry_exponential_backoff).value(:bool).default(Mihari.config.retry_exponential_backoff)
11
- optional(:ignore_error).value(:bool).default(Mihari.config.ignore_error)
12
- optional(:timeout).value(:integer)
13
- end
14
-
15
- AnalyzerWithoutAPIKey = Dry::Schema.Params do
16
- required(:analyzer).value(Types::String.enum("dnstwister"))
17
- required(:query).value(:string)
18
- optional(:options).hash(AnalyzerOptions)
19
- end
20
-
21
- AnalyzerWithAPIKey = Dry::Schema.Params do
5
+ AnalyzerAPIKeyPagination = Dry::Schema.Params do
22
6
  required(:analyzer).value(
23
7
  Types::String.enum(
24
8
  "binaryedge",
25
9
  "greynoise",
26
10
  "onyphe",
11
+ "shodan",
12
+ "urlscan",
13
+ "virustotal_intelligence",
14
+ "vt_intel"
15
+ )
16
+ )
17
+ required(:query).value(:string)
18
+ optional(:api_key).value(:string)
19
+ optional(:options).hash(AnalyzerPaginationOptions)
20
+ end
21
+
22
+ AnalyzerAPIKey = Dry::Schema.Params do
23
+ required(:analyzer).value(
24
+ Types::String.enum(
27
25
  "otx",
28
26
  "pulsedive",
29
27
  "securitytrails",
30
- "shodan",
31
28
  "st",
32
- "urlscan",
33
- "virustotal_intelligence",
34
29
  "virustotal",
35
- "vt_intel",
36
30
  "vt"
37
31
  )
38
32
  )
@@ -41,12 +35,18 @@ module Mihari
41
35
  optional(:options).hash(AnalyzerOptions)
42
36
  end
43
37
 
38
+ DNSTwister = Dry::Schema.Params do
39
+ required(:analyzer).value(Types::String.enum("dnstwister"))
40
+ required(:query).value(:string)
41
+ optional(:options).hash(AnalyzerOptions)
42
+ end
43
+
44
44
  Censys = Dry::Schema.Params do
45
45
  required(:analyzer).value(Types::String.enum("censys"))
46
46
  required(:query).value(:string)
47
47
  optional(:id).value(:string)
48
48
  optional(:secret).value(:string)
49
- optional(:options).hash(AnalyzerOptions)
49
+ optional(:options).hash(AnalyzerPaginationOptions)
50
50
  end
51
51
 
52
52
  CIRCL = Dry::Schema.Params do
@@ -69,7 +69,7 @@ module Mihari
69
69
  required(:analyzer).value(Types::String.enum("zoomeye"))
70
70
  required(:query).value(:string)
71
71
  required(:type).value(Types::String.enum("host", "web"))
72
- optional(:options).hash(AnalyzerOptions)
72
+ optional(:options).hash(AnalyzerPaginationOptions)
73
73
  end
74
74
 
75
75
  Crtsh = Dry::Schema.Params do
@@ -85,7 +85,7 @@ module Mihari
85
85
  required(:start_time).value(:date)
86
86
  required(:end_time).value(:date)
87
87
  optional(:api_key).value(:string)
88
- optional(:options).hash(AnalyzerOptions)
88
+ optional(:options).hash(AnalyzerPaginationOptions)
89
89
  end
90
90
 
91
91
  Feed = Dry::Schema.Params do
@@ -3,38 +3,31 @@
3
3
  module Mihari
4
4
  module Schemas
5
5
  module Emitters
6
- EmitterOptions = Dry::Schema.Params do
7
- optional(:retry_times).value(:integer).default(Mihari.config.retry_times)
8
- optional(:retry_interval).value(:integer).default(Mihari.config.retry_interval)
9
- optional(:retry_exponential_backoff).value(:bool).default(Mihari.config.retry_exponential_backoff)
10
- optional(:timeout).value(:integer)
11
- end
12
-
13
6
  Database = Dry::Schema.Params do
14
7
  required(:emitter).value(Types::String.enum("database"))
15
- optional(:options).hash(EmitterOptions)
8
+ optional(:options).hash(Options)
16
9
  end
17
10
 
18
11
  MISP = Dry::Schema.Params do
19
12
  required(:emitter).value(Types::String.enum("misp"))
20
13
  optional(:url).value(:string)
21
14
  optional(:api_key).value(:string)
22
- optional(:options).hash(EmitterOptions)
15
+ optional(:options).hash(Options)
23
16
  end
24
17
 
25
18
  TheHive = Dry::Schema.Params do
26
- required(:emitter).value(Types::String.enum("the_hive"))
19
+ required(:emitter).value(Types::String.enum("thehive"))
27
20
  optional(:url).value(:string)
28
21
  optional(:api_key).value(:string)
29
22
  optional(:api_version).value(Types::String.enum("v4", "v5")).default("v4")
30
- optional(:options).hash(EmitterOptions)
23
+ optional(:options).hash(Options)
31
24
  end
32
25
 
33
26
  Slack = Dry::Schema.Params do
34
27
  required(:emitter).value(Types::String.enum("slack"))
35
28
  optional(:webhook_url).value(:string)
36
29
  optional(:channel).value(:string)
37
- optional(:options).hash(EmitterOptions)
30
+ optional(:options).hash(Options)
38
31
  end
39
32
 
40
33
  Webhook = Dry::Schema.Params do
@@ -43,7 +36,7 @@ module Mihari
43
36
  optional(:method).value(Types::HTTPRequestMethods).default("POST")
44
37
  optional(:headers).value(:hash).default({})
45
38
  optional(:template).value(:string)
46
- optional(:options).hash(EmitterOptions)
39
+ optional(:options).hash(Options)
47
40
  end
48
41
  end
49
42
  end
@@ -3,32 +3,25 @@
3
3
  module Mihari
4
4
  module Schemas
5
5
  module Enrichers
6
- EnricherOptions = Dry::Schema.Params do
7
- optional(:retry_times).value(:integer).default(Mihari.config.retry_times)
8
- optional(:retry_interval).value(:integer).default(Mihari.config.retry_interval)
9
- optional(:retry_exponential_backoff).value(:bool).default(Mihari.config.retry_exponential_backoff)
10
- optional(:timeout).value(:integer)
11
- end
12
-
13
6
  IPInfo = Dry::Schema.Params do
14
7
  required(:enricher).value(Types::String.enum("ipinfo"))
15
8
  optional(:api_key).value(:string)
16
- optional(:options).hash(EnricherOptions)
9
+ optional(:options).hash(Options)
17
10
  end
18
11
 
19
12
  Whois = Dry::Schema.Params do
20
13
  required(:enricher).value(Types::String.enum("whois"))
21
- optional(:options).hash(EnricherOptions)
14
+ optional(:options).hash(Options)
22
15
  end
23
16
 
24
17
  Shodan = Dry::Schema.Params do
25
18
  required(:enricher).value(Types::String.enum("shodan"))
26
- optional(:options).hash(EnricherOptions)
19
+ optional(:options).hash(Options)
27
20
  end
28
21
 
29
22
  GooglePublicDNS = Dry::Schema.Params do
30
23
  required(:enricher).value(Types::String.enum("google_public_dns"))
31
- optional(:options).hash(EnricherOptions)
24
+ optional(:options).hash(Options)
32
25
  end
33
26
  end
34
27
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/schema"
4
+
5
+ module Mihari
6
+ module Schemas
7
+ Options = Dry::Schema.Params do
8
+ optional(:retry_times).value(:integer).default(Mihari.config.retry_times)
9
+ optional(:retry_interval).value(:integer).default(Mihari.config.retry_interval)
10
+ optional(:retry_exponential_backoff).value(:bool).default(Mihari.config.retry_exponential_backoff)
11
+ optional(:timeout).value(:integer)
12
+ end
13
+
14
+ IgnoreErrorOptions = Dry::Schema.Params do
15
+ optional(:ignore_error).value(:bool).default(Mihari.config.ignore_error)
16
+ end
17
+
18
+ AnalyzerOptions = Options | IgnoreErrorOptions
19
+
20
+ PaginationOptions = Dry::Schema.Params do
21
+ optional(:pagination_interval).value(:integer).default(Mihari.config.pagination_interval)
22
+ optional(:pagination_limit).value(:integer).default(Mihari.config.pagination_limit)
23
+ end
24
+
25
+ AnalyzerPaginationOptions = AnalyzerOptions | PaginationOptions
26
+ end
27
+ end
@@ -22,7 +22,7 @@ module Mihari
22
22
  optional(:updated_on).value(:date)
23
23
 
24
24
  required(:queries).value(:array).each do
25
- AnalyzerWithoutAPIKey | AnalyzerWithAPIKey | Censys | CIRCL | PassiveTotal | ZoomEye | Crtsh | Feed | HunterHow
25
+ AnalyzerAPIKey | AnalyzerAPIKeyPagination | Censys | CIRCL | PassiveTotal | ZoomEye | Crtsh | Feed | HunterHow | DNSTwister
26
26
  end
27
27
 
28
28
  optional(:emitters).value(:array).each do
@@ -33,7 +33,7 @@ module Mihari
33
33
  Enrichers::Whois | Enrichers::IPInfo | Enrichers::Shodan | Enrichers::GooglePublicDNS
34
34
  end.default(DEFAULT_ENRICHERS)
35
35
 
36
- optional(:data_types).value(array[Types::DataTypes]).default(DEFAULT_DATA_TYPES)
36
+ optional(:data_types).value(array[Types::DataTypes]).default(Mihari::Types::DataTypes.values)
37
37
  optional(:falsepositives).value(array[:string]).default([])
38
38
 
39
39
  optional(:artifact_lifetime).value(:integer)
@@ -16,7 +16,7 @@ module Mihari
16
16
  # @return [Mihari::Alert]
17
17
  #
18
18
  def run
19
- emitter = Mihari::Emitters::Database.new(artifacts: alert.artifacts, rule: alert.rule)
19
+ emitter = Emitters::Database.new(artifacts: alert.artifacts, rule: alert.rule)
20
20
  emitter.emit
21
21
  end
22
22
 
@@ -5,21 +5,11 @@ module Mihari
5
5
  class RuleRunner
6
6
  include Dry::Monads[:result, :try]
7
7
 
8
- include Mixins::ErrorNotification
9
-
10
8
  # @return [Mihari::Services::RuleProxy]
11
9
  attr_reader :rule
12
10
 
13
- # @return [Boolean]
14
- attr_reader :force_overwrite
15
-
16
- def initialize(rule, force_overwrite:)
11
+ def initialize(rule)
17
12
  @rule = rule
18
- @force_overwrite = force_overwrite
19
- end
20
-
21
- def force_overwrite?
22
- force_overwrite
23
13
  end
24
14
 
25
15
  #
data/lib/mihari/types.rb CHANGED
@@ -12,21 +12,8 @@ module Mihari
12
12
  Double = Strict::Float | Strict::Integer
13
13
  DateTime = Strict::DateTime
14
14
 
15
- DataTypes = Types::String.enum(*DEFAULT_DATA_TYPES)
15
+ DataTypes = Types::String.enum("hash", "ip", "domain", "url", "mail")
16
16
 
17
17
  HTTPRequestMethods = Types::String.enum("GET", "POST")
18
- HTTPRequestPayloadTypes = Types::String.enum("application/json", "application/x-www-form-urlencoded")
19
-
20
- EmitterTypes = Types::String.enum(
21
- "database",
22
- "webhook"
23
- )
24
-
25
- EnricherTypes = Types::String.enum(
26
- "whois",
27
- "ipinfo",
28
- "shodan",
29
- "google_public_dns"
30
- )
31
18
  end
32
19
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- VERSION = "5.5.0"
4
+ VERSION = "5.6.0"
5
5
  end