mihari 3.12.0 → 4.0.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 (160) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mihari/analyzers/base.rb +6 -6
  3. data/lib/mihari/analyzers/binaryedge.rb +3 -5
  4. data/lib/mihari/analyzers/censys.rb +1 -3
  5. data/lib/mihari/analyzers/circl.rb +0 -3
  6. data/lib/mihari/analyzers/crtsh.rb +7 -5
  7. data/lib/mihari/analyzers/dnpedia.rb +4 -4
  8. data/lib/mihari/analyzers/dnstwister.rb +1 -4
  9. data/lib/mihari/analyzers/feed.rb +0 -3
  10. data/lib/mihari/analyzers/greynoise.rb +1 -3
  11. data/lib/mihari/analyzers/onyphe.rb +1 -3
  12. data/lib/mihari/analyzers/otx.rb +0 -3
  13. data/lib/mihari/analyzers/passivetotal.rb +8 -9
  14. data/lib/mihari/analyzers/pulsedive.rb +7 -5
  15. data/lib/mihari/analyzers/rule.rb +5 -6
  16. data/lib/mihari/analyzers/securitytrails.rb +10 -7
  17. data/lib/mihari/analyzers/shodan.rb +2 -4
  18. data/lib/mihari/analyzers/spyse.rb +10 -11
  19. data/lib/mihari/analyzers/urlscan.rb +5 -6
  20. data/lib/mihari/analyzers/virustotal.rb +8 -9
  21. data/lib/mihari/analyzers/virustotal_intelligence.rb +4 -5
  22. data/lib/mihari/analyzers/zoomeye.rb +4 -5
  23. data/lib/mihari/cli/base.rb +0 -5
  24. data/lib/mihari/cli/init.rb +0 -2
  25. data/lib/mihari/cli/main.rb +4 -6
  26. data/lib/mihari/cli/mixins/utils.rb +2 -18
  27. data/lib/mihari/commands/init.rb +0 -18
  28. data/lib/mihari/commands/search.rb +20 -15
  29. data/lib/mihari/commands/validator.rb +7 -19
  30. data/lib/mihari/commands/web.rb +0 -3
  31. data/lib/mihari/database.rb +67 -15
  32. data/lib/mihari/emitters/misp.rb +0 -1
  33. data/lib/mihari/emitters/slack.rb +3 -4
  34. data/lib/mihari/emitters/stdout.rb +0 -2
  35. data/lib/mihari/emitters/the_hive.rb +0 -1
  36. data/lib/mihari/emitters/webhook.rb +1 -5
  37. data/lib/mihari/enrichers/ipinfo.rb +0 -2
  38. data/lib/mihari/errors.rb +2 -0
  39. data/lib/mihari/feed/reader.rb +22 -8
  40. data/lib/mihari/mixins/database.rb +14 -0
  41. data/lib/mihari/mixins/disallowed_data_value.rb +1 -4
  42. data/lib/mihari/mixins/rule.rb +34 -31
  43. data/lib/mihari/models/alert.rb +3 -3
  44. data/lib/mihari/models/artifact.rb +0 -5
  45. data/lib/mihari/models/autonomous_system.rb +0 -2
  46. data/lib/mihari/models/dns.rb +0 -3
  47. data/lib/mihari/models/geolocation.rb +0 -1
  48. data/lib/mihari/models/reverse_dns.rb +0 -3
  49. data/lib/mihari/models/rule.rb +73 -0
  50. data/lib/mihari/models/tag.rb +0 -2
  51. data/lib/mihari/models/tagging.rb +0 -2
  52. data/lib/mihari/models/whois.rb +0 -2
  53. data/lib/mihari/notifiers/exception_notifier.rb +0 -2
  54. data/lib/mihari/schemas/analyzer.rb +0 -5
  55. data/lib/mihari/schemas/macros.rb +0 -2
  56. data/lib/mihari/schemas/rule.rb +0 -5
  57. data/lib/mihari/structs/alert.rb +0 -3
  58. data/lib/mihari/structs/censys.rb +3 -4
  59. data/lib/mihari/structs/greynoise.rb +3 -4
  60. data/lib/mihari/structs/ipinfo.rb +0 -3
  61. data/lib/mihari/structs/onyphe.rb +5 -6
  62. data/lib/mihari/structs/rule.rb +121 -0
  63. data/lib/mihari/structs/shodan.rb +3 -4
  64. data/lib/mihari/structs/urlscan.rb +0 -3
  65. data/lib/mihari/structs/virustotal_intelligence.rb +3 -4
  66. data/lib/mihari/type_checker.rb +2 -6
  67. data/lib/mihari/types.rb +0 -2
  68. data/lib/mihari/version.rb +1 -1
  69. data/lib/mihari/web/api.rb +4 -0
  70. data/lib/mihari/web/app.rb +5 -7
  71. data/lib/mihari/web/endpoints/alerts.rb +7 -3
  72. data/lib/mihari/web/endpoints/artifacts.rb +6 -3
  73. data/lib/mihari/web/endpoints/command.rb +2 -1
  74. data/lib/mihari/web/endpoints/configs.rb +2 -1
  75. data/lib/mihari/web/endpoints/ip_addresses.rb +2 -1
  76. data/lib/mihari/web/endpoints/rules.rb +140 -0
  77. data/lib/mihari/web/endpoints/sources.rb +2 -1
  78. data/lib/mihari/web/endpoints/tags.rb +4 -2
  79. data/lib/mihari/web/entities/artifact.rb +2 -0
  80. data/lib/mihari/web/entities/rule.rb +35 -0
  81. data/lib/mihari/web/middleware/connection_adapter.rb +19 -0
  82. data/lib/mihari/web/public/index.html +1 -1
  83. data/lib/mihari/web/public/redoc-static.html +35 -21
  84. data/lib/mihari/web/public/static/js/app.49ab738a.js +21 -0
  85. data/lib/mihari/web/public/static/js/app.49ab738a.js.map +1 -0
  86. data/lib/mihari.rb +40 -34
  87. data/mihari.gemspec +3 -5
  88. data/sig/lib/mihari/analyzers/binaryedge.rbs +0 -3
  89. data/sig/lib/mihari/analyzers/censys.rbs +0 -3
  90. data/sig/lib/mihari/analyzers/circl.rbs +1 -3
  91. data/sig/lib/mihari/analyzers/crtsh.rbs +1 -3
  92. data/sig/lib/mihari/analyzers/dnpedia.rbs +1 -4
  93. data/sig/lib/mihari/analyzers/dnstwister.rbs +1 -3
  94. data/sig/lib/mihari/analyzers/feed.rbs +0 -3
  95. data/sig/lib/mihari/analyzers/onyphe.rbs +0 -3
  96. data/sig/lib/mihari/analyzers/otx.rbs +1 -3
  97. data/sig/lib/mihari/analyzers/passivetotal.rbs +3 -5
  98. data/sig/lib/mihari/analyzers/pulsedive.rbs +2 -4
  99. data/sig/lib/mihari/analyzers/securitytrails.rbs +3 -5
  100. data/sig/lib/mihari/analyzers/shodan.rbs +0 -3
  101. data/sig/lib/mihari/analyzers/spyse.rbs +4 -6
  102. data/sig/lib/mihari/analyzers/urlscan.rbs +1 -3
  103. data/sig/lib/mihari/analyzers/virustotal.rbs +4 -6
  104. data/sig/lib/mihari/analyzers/virustotal_intelligence.rbs +0 -3
  105. data/sig/lib/mihari/analyzers/zoomeye.rbs +2 -4
  106. data/sig/lib/mihari/commands/init.rbs +0 -2
  107. data/sig/lib/mihari/commands/validator.rbs +0 -2
  108. data/sig/lib/mihari/emitters/slack.rbs +0 -1
  109. data/sig/lib/mihari/feed/reader.rbs +1 -1
  110. data/sig/lib/mihari/mixins/disallowed_data_value.rbs +0 -2
  111. data/sig/lib/mihari/mixins/rule.rbs +5 -12
  112. data/sig/lib/mihari/models/alert.rbs +1 -1
  113. data/sig/lib/mihari/models/artifact.rbs +2 -0
  114. data/sig/lib/mihari/models/rule.rbs +14 -0
  115. data/sig/lib/mihari/structs/rule.rbs +56 -0
  116. data/sig/lib/mihari.rbs +0 -2
  117. metadata +18 -79
  118. data/lib/mihari/cli/analyzer.rb +0 -55
  119. data/lib/mihari/commands/binaryedge.rb +0 -21
  120. data/lib/mihari/commands/censys.rb +0 -22
  121. data/lib/mihari/commands/circl.rb +0 -21
  122. data/lib/mihari/commands/crtsh.rb +0 -22
  123. data/lib/mihari/commands/dnpedia.rb +0 -21
  124. data/lib/mihari/commands/dnstwister.rb +0 -21
  125. data/lib/mihari/commands/feed.rb +0 -26
  126. data/lib/mihari/commands/greynoise.rb +0 -21
  127. data/lib/mihari/commands/json.rb +0 -42
  128. data/lib/mihari/commands/onyphe.rb +0 -21
  129. data/lib/mihari/commands/otx.rb +0 -21
  130. data/lib/mihari/commands/passivetotal.rb +0 -22
  131. data/lib/mihari/commands/pulsedive.rb +0 -21
  132. data/lib/mihari/commands/securitytrails.rb +0 -22
  133. data/lib/mihari/commands/shodan.rb +0 -21
  134. data/lib/mihari/commands/spyse.rb +0 -22
  135. data/lib/mihari/commands/urlscan.rb +0 -22
  136. data/lib/mihari/commands/virustotal.rb +0 -22
  137. data/lib/mihari/commands/virustotal_intelligence.rb +0 -22
  138. data/lib/mihari/commands/zoomeye.rb +0 -22
  139. data/lib/mihari/mixins/configuration.rb +0 -100
  140. data/lib/mihari/mixins/hash.rb +0 -20
  141. data/lib/mihari/schemas/configuration.rb +0 -44
  142. data/lib/mihari/web/public/grape.rb +0 -73
  143. data/sig/lib/mihari/cli/analyzer.rbs +0 -43
  144. data/sig/lib/mihari/commands/binaryedge.rbs +0 -7
  145. data/sig/lib/mihari/commands/censys.rbs +0 -7
  146. data/sig/lib/mihari/commands/circl.rbs +0 -7
  147. data/sig/lib/mihari/commands/crtsh.rbs +0 -7
  148. data/sig/lib/mihari/commands/dnpedia.rbs +0 -7
  149. data/sig/lib/mihari/commands/dnstwister.rbs +0 -7
  150. data/sig/lib/mihari/commands/feed.rbs +0 -7
  151. data/sig/lib/mihari/commands/onyphe.rbs +0 -7
  152. data/sig/lib/mihari/commands/otx.rbs +0 -7
  153. data/sig/lib/mihari/commands/passivetotal.rbs +0 -7
  154. data/sig/lib/mihari/commands/pulsedive.rbs +0 -7
  155. data/sig/lib/mihari/commands/securitytrails.rbs +0 -7
  156. data/sig/lib/mihari/commands/shodan.rbs +0 -7
  157. data/sig/lib/mihari/commands/spyse.rbs +0 -7
  158. data/sig/lib/mihari/commands/urlscan.rbs +0 -7
  159. data/sig/lib/mihari/commands/virustotal.rbs +0 -7
  160. data/sig/lib/mihari/commands/zoomeye.rbs +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a17c14dffe68b2f82316858615371036996a3a2b6d31d3c6a5c431294c38634
4
- data.tar.gz: 97afaf2f8b20985b0908cc1fe5778fe75ab7d0e1bf13b990a7b4165c92843604
3
+ metadata.gz: 1a42a8897840d2f2268f88c6734c1633642256ef08667c39f45f5d03ac13874f
4
+ data.tar.gz: 89bdd5aa38f833e3158464915ec46c05e8c0bb6f17d34fe397d1590c59a57d7c
5
5
  SHA512:
6
- metadata.gz: 418d7f278536e245196723d2ebbe0d99934b0db3278e8f8178470241c67f25e05d0aacf7bab2b766ce69d0589a79e87eca554a91fe4cfae5cfa12cd52d97fb61
7
- data.tar.gz: 9e90193273ee40c9956a138c2c73b713eb610a3ebdc1c9def73a6d354c4124a97e6842e438004956b3edc3206dfee8bae5771a86e964b59a2a7065a1f910891f
6
+ metadata.gz: f62927fdb96eabffd99106bf03178e6eb573ee5e58b8fa2bb94b6b6b2ea898324fd65656bbb128aab67196ad03da959603dd73108c8840e883560d673c8afa5f
7
+ data.tar.gz: 2e752fa7ab93691ad6c38ec534af3bab14e27f2b66127dc00fc016f26554ea29fc2c743d2bdaef93d85e816d8a47e54d2d41bb6dafaabf711cfb2c833c3ff0ff
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "dry-initializer"
4
- require "parallel"
5
-
6
3
  module Mihari
7
4
  module Analyzers
8
5
  class Base
@@ -10,6 +7,7 @@ module Mihari
10
7
 
11
8
  include Mixins::AutonomousSystem
12
9
  include Mixins::Configurable
10
+ include Mixins::Database
13
11
  include Mixins::Retriable
14
12
 
15
13
  attr_accessor :ignore_old_artifacts, :ignore_threshold
@@ -52,10 +50,12 @@ module Mihari
52
50
  # @return [nil]
53
51
  #
54
52
  def run
55
- set_enriched_artifacts
53
+ with_db_connection do
54
+ set_enriched_artifacts
56
55
 
57
- Parallel.each(valid_emitters) do |emitter|
58
- run_emitter emitter
56
+ Parallel.each(valid_emitters) do |emitter|
57
+ run_emitter emitter
58
+ end
59
59
  end
60
60
  end
61
61
 
@@ -6,9 +6,6 @@ module Mihari
6
6
  module Analyzers
7
7
  class BinaryEdge < Base
8
8
  param :query
9
- option :title, default: proc { "BinaryEdge search" }
10
- option :description, default: proc { "query = #{query}" }
11
- option :tags, default: proc { [] }
12
9
 
13
10
  option :interval, default: proc { 0 }
14
11
 
@@ -19,9 +16,10 @@ module Mihari
19
16
  results.map do |result|
20
17
  events = result["events"] || []
21
18
  events.filter_map do |event|
22
- event.dig "target", "ip"
19
+ data = event.dig("target", "ip")
20
+ data.nil? ? nil : Artifact.new(data: data, source: source, metadata: event)
23
21
  end
24
- end.flatten.compact.uniq
22
+ end.flatten
25
23
  end
26
24
 
27
25
  private
@@ -6,9 +6,6 @@ module Mihari
6
6
  module Analyzers
7
7
  class Censys < Base
8
8
  param :query
9
- option :title, default: proc { "Censys search" }
10
- option :description, default: proc { "query = #{query}" }
11
- option :tags, default: proc { [] }
12
9
 
13
10
  option :interval, default: proc { 0 }
14
11
 
@@ -77,6 +74,7 @@ module Mihari
77
74
  Artifact.new(
78
75
  data: hit.ip,
79
76
  source: source,
77
+ metadata: hit.metadata,
80
78
  autonomous_system: as,
81
79
  geolocation: geolocation
82
80
  )
@@ -8,9 +8,6 @@ module Mihari
8
8
  include Mixins::Refang
9
9
 
10
10
  param :query
11
- option :title, default: proc { "CIRCL passive DNS/SSL search" }
12
- option :description, default: proc { "query = #{query}" }
13
- option :tags, default: proc { [] }
14
11
 
15
12
  attr_reader :type
16
13
 
@@ -6,15 +6,17 @@ module Mihari
6
6
  module Analyzers
7
7
  class Crtsh < Base
8
8
  param :query
9
- option :title, default: proc { "crt.sh search" }
10
- option :description, default: proc { "query = #{query}" }
11
- option :tags, default: proc { [] }
9
+
12
10
  option :exclude_expired, default: proc { true }
13
11
 
14
12
  def artifacts
15
13
  results = search
16
- name_values = results.filter_map { |result| result["name_value"] }
17
- name_values.map(&:lines).flatten.uniq.map(&:chomp)
14
+ results.map do |result|
15
+ values = result["name_value"].to_s.lines.map(&:chomp)
16
+ values.map do |value|
17
+ Artifact.new(data: value, source: source, metadata: result)
18
+ end
19
+ end.flatten
18
20
  end
19
21
 
20
22
  private
@@ -6,8 +6,7 @@ module Mihari
6
6
  module Analyzers
7
7
  class DNPedia < Base
8
8
  param :query
9
- option :title, default: proc { "DNPedia domain search" }
10
- option :description, default: proc { "query = #{query}" }
9
+
11
10
  option :tags, default: proc { [] }
12
11
 
13
12
  def artifacts
@@ -23,13 +22,14 @@ module Mihari
23
22
  #
24
23
  # Search
25
24
  #
26
- # @return [Array<String>]
25
+ # @return [Array<Mihari::Artifact>]
27
26
  #
28
27
  def search
29
28
  res = api.search(query)
30
29
  rows = res["rows"] || []
31
30
  rows.map do |row|
32
- [row["name"], row["zoneid"]].join(".")
31
+ data = [row["name"], row["zoneid"]].join(".")
32
+ Artifact.new(data: data, source: source, metadata: row)
33
33
  end
34
34
  end
35
35
  end
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "dnstwister"
4
- require "resolv"
5
- require "parallel"
6
4
 
7
5
  module Mihari
8
6
  module Analyzers
@@ -10,8 +8,7 @@ module Mihari
10
8
  include Mixins::Refang
11
9
 
12
10
  param :query
13
- option :title, default: proc { "dnstwister domain search" }
14
- option :description, default: proc { "query = #{query}" }
11
+
15
12
  option :tags, default: proc { [] }
16
13
 
17
14
  attr_reader :type
@@ -7,9 +7,6 @@ module Mihari
7
7
  module Analyzers
8
8
  class Feed < Base
9
9
  param :query
10
- option :title, default: proc { "Feed" }
11
- option :description, default: proc { "query = #{query}" }
12
- option :tags, default: proc { [] }
13
10
 
14
11
  option :http_request_method, default: proc { "GET" }
15
12
  option :http_request_headers, default: proc { {} }
@@ -6,9 +6,6 @@ module Mihari
6
6
  module Analyzers
7
7
  class GreyNoise < Base
8
8
  param :query
9
- option :title, default: proc { "GreyNoise search" }
10
- option :description, default: proc { "query = #{query}" }
11
- option :tags, default: proc { [] }
12
9
 
13
10
  def artifacts
14
11
  res = Structs::GreyNoise::Response.from_dynamic!(search)
@@ -56,6 +53,7 @@ module Mihari
56
53
  Artifact.new(
57
54
  data: datum.ip,
58
55
  source: source,
56
+ metadata: datum.metadata_,
59
57
  autonomous_system: as,
60
58
  geolocation: geolocation
61
59
  )
@@ -7,9 +7,6 @@ module Mihari
7
7
  module Analyzers
8
8
  class Onyphe < Base
9
9
  param :query
10
- option :title, default: proc { "Onyphe search" }
11
- option :description, default: proc { "query = #{query}" }
12
- option :tags, default: proc { [] }
13
10
 
14
11
  option :interval, default: proc { 0 }
15
12
 
@@ -89,6 +86,7 @@ module Mihari
89
86
  Artifact.new(
90
87
  data: result.ip,
91
88
  source: source,
89
+ metadata: result.metadata,
92
90
  autonomous_system: as,
93
91
  geolocation: geolocation
94
92
  )
@@ -8,9 +8,6 @@ module Mihari
8
8
  include Mixins::Refang
9
9
 
10
10
  param :query
11
- option :title, default: proc { "OTX search" }
12
- option :description, default: proc { "query = #{query}" }
13
- option :tags, default: proc { [] }
14
11
 
15
12
  attr_reader :type
16
13
 
@@ -8,9 +8,6 @@ module Mihari
8
8
  include Mixins::Refang
9
9
 
10
10
  param :query
11
- option :title, default: proc { "PassiveTotal search" }
12
- option :description, default: proc { "query = #{query}" }
13
- option :tags, default: proc { [] }
14
11
 
15
12
  attr_reader :type
16
13
 
@@ -75,27 +72,29 @@ module Mihari
75
72
  #
76
73
  # Reverse whois search
77
74
  #
78
- # @return [Array<String>]
75
+ # @return [Array<Mihari::Artifact>]
79
76
  #
80
77
  def reverse_whois_search
81
78
  res = api.whois.search(query: query, field: "email")
82
79
  results = res["results"] || []
83
80
  results.map do |result|
84
- result["domain"]
85
- end.flatten.compact.uniq
81
+ data = result["domain"]
82
+ Artifact.new(data: data, source: source, metadata: result)
83
+ end.flatten
86
84
  end
87
85
 
88
86
  #
89
87
  # Passive SSL search
90
88
  #
91
- # @return [Array<String>]
89
+ # @return [Array<Mihari::Artifact>]
92
90
  #
93
91
  def ssl_search
94
92
  res = api.ssl.history(query)
95
93
  results = res["results"] || []
96
94
  results.map do |result|
97
- result["ipAddresses"]
98
- end.flatten.compact.uniq
95
+ data = result["ipAddresses"]
96
+ Artifact.new(data: data, source: source, metadata: result)
97
+ end.flatten
99
98
  end
100
99
  end
101
100
  end
@@ -8,9 +8,6 @@ module Mihari
8
8
  include Mixins::Refang
9
9
 
10
10
  param :query
11
- option :title, default: proc { "Pulsedive search" }
12
- option :description, default: proc { "query = #{query}" }
13
- option :tags, default: proc { [] }
14
11
 
15
12
  attr_reader :type
16
13
 
@@ -47,7 +44,7 @@ module Mihari
47
44
  #
48
45
  # Search
49
46
  #
50
- # @return [Array<String>]
47
+ # @return [Array<Mihari::Artifact>]
51
48
  #
52
49
  def search
53
50
  raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
@@ -57,7 +54,12 @@ module Mihari
57
54
 
58
55
  properties = api.indicator.get_properties_by_id(iid)
59
56
  (properties["dns"] || []).filter_map do |property|
60
- property["value"] if ["A", "PTR"].include?(property["name"])
57
+ if ["A", "PTR"].include?(property["name"])
58
+ nil
59
+ else
60
+ data = property["value"]
61
+ Artifact.new(data: data, source: source, metadata: property)
62
+ end
61
63
  end
62
64
  end
63
65
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "uuidtools"
4
-
5
3
  module Mihari
6
4
  module Analyzers
7
5
  ANALYZER_TO_CLASS = {
@@ -31,13 +29,14 @@ module Mihari
31
29
  }.freeze
32
30
 
33
31
  class Rule < Base
34
- include Mihari::Mixins::DisallowedDataValue
32
+ include Mixins::DisallowedDataValue
33
+ include Mixins::Rule
35
34
 
36
35
  option :title
37
36
  option :description
38
37
  option :queries
39
38
 
40
- option :id, default: proc {}
39
+ option :id, default: proc { "" }
41
40
  option :tags, default: proc { [] }
42
41
  option :allowed_data_types, default: proc { ALLOWED_DATA_TYPES }
43
42
  option :disallowed_data_values, default: proc { [] }
@@ -47,7 +46,7 @@ module Mihari
47
46
  def initialize(**kwargs)
48
47
  super(**kwargs)
49
48
 
50
- @source = id || UUIDTools::UUID.md5_create(UUIDTools::UUID_URL_NAMESPACE, title + description).to_s
49
+ @source = id
51
50
 
52
51
  validate_analyzer_configurations
53
52
  end
@@ -69,7 +68,7 @@ module Mihari
69
68
  # set interval in the top level
70
69
  options = params[:options] || {}
71
70
  interval = options[:interval]
72
- params[:interval] = interval
71
+ params[:interval] = interval if interval
73
72
 
74
73
  analyzer = klass.new(query, **params)
75
74
 
@@ -8,9 +8,6 @@ module Mihari
8
8
  include Mixins::Refang
9
9
 
10
10
  param :query
11
- option :title, default: proc { "SecurityTrails search" }
12
- option :description, default: proc { "query = #{query}" }
13
- option :tags, default: proc { [] }
14
11
 
15
12
  attr_reader :type
16
13
 
@@ -47,7 +44,7 @@ module Mihari
47
44
  #
48
45
  # IP/domain/mail search
49
46
  #
50
- # @return [Array<String>]
47
+ # @return [Array<String>, Array<Mihari::Artifact>]
51
48
  #
52
49
  def search
53
50
  case type
@@ -78,12 +75,15 @@ module Mihari
78
75
  #
79
76
  # IP search
80
77
  #
81
- # @return [Array<String>]
78
+ # @return [Array<Mihari::Artifact>]
82
79
  #
83
80
  def ip_search
84
81
  result = api.domains.search(filter: { ipv4: query })
85
82
  records = result["records"] || []
86
- records.filter_map { |record| record["hostname"] }.uniq
83
+ records.filter_map do |record|
84
+ data = record["hostname"]
85
+ Artifact.new(data: data, source: source, metadata: record)
86
+ end
87
87
  end
88
88
 
89
89
  #
@@ -94,7 +94,10 @@ module Mihari
94
94
  def mail_search
95
95
  result = api.domains.search(filter: { whois_email: query })
96
96
  records = result["records"] || []
97
- records.filter_map { |record| record["hostname"] }.uniq
97
+ records.filter_map do |record|
98
+ data = record["hostname"]
99
+ Artifact.new(data: data, source: source, metadata: record)
100
+ end
98
101
  end
99
102
  end
100
103
  end
@@ -6,9 +6,6 @@ module Mihari
6
6
  module Analyzers
7
7
  class Shodan < Base
8
8
  param :query
9
- option :title, default: proc { "Shodan search" }
10
- option :description, default: proc { "query = #{query}" }
11
- option :tags, default: proc { [] }
12
9
 
13
10
  option :interval, default: proc { 0 }
14
11
 
@@ -20,7 +17,7 @@ module Mihari
20
17
  results.map do |result|
21
18
  matches = result.matches || []
22
19
  matches.map { |match| build_artifact match }
23
- end.flatten.compact.uniq(&:data)
20
+ end.flatten.uniq(&:data)
24
21
  end
25
22
 
26
23
  private
@@ -98,6 +95,7 @@ module Mihari
98
95
  Artifact.new(
99
96
  data: match.ip_str,
100
97
  source: source,
98
+ metadata: match.metadata,
101
99
  autonomous_system: as,
102
100
  geolocation: geolocation
103
101
  )
@@ -1,16 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "spyse"
4
- require "json"
5
4
 
6
5
  module Mihari
7
6
  module Analyzers
8
7
  class Spyse < Base
9
8
  param :query
10
- option :title, default: proc { "Spyse search" }
11
- option :description, default: proc { "query = #{query}" }
9
+
12
10
  option :type, default: proc { "domain" }
13
- option :tags, default: proc { [] }
14
11
 
15
12
  def artifacts
16
13
  search || []
@@ -42,33 +39,35 @@ module Mihari
42
39
  #
43
40
  # Domain search
44
41
  #
45
- # @return [Array<String>]
42
+ # @return [Array<Mihari::Artifact>]
46
43
  #
47
44
  def domain_search
48
45
  res = api.domain.search(search_params, limit: 100)
49
46
  items = res.dig("data", "items") || []
50
47
  items.map do |item|
51
- item["name"]
52
- end.uniq.compact
48
+ data = item["name"]
49
+ Artifact.new(data: data, source: source, metadata: item)
50
+ end
53
51
  end
54
52
 
55
53
  #
56
54
  # IP search
57
55
  #
58
- # @return [Array<String>]
56
+ # @return [Array<Mihari::Artifact>]
59
57
  #
60
58
  def ip_search
61
59
  res = api.ip.search(search_params, limit: 100)
62
60
  items = res.dig("data", "items") || []
63
61
  items.map do |item|
64
- item["ip"]
65
- end.uniq.compact
62
+ data = item["ip"]
63
+ Artifact.new(data: data, source: source, metadata: item)
64
+ end
66
65
  end
67
66
 
68
67
  #
69
68
  # IP/domain search
70
69
  #
71
- # @return [Array<String>]
70
+ # @return [Array<Mihari::Artifact>]
72
71
  #
73
72
  def search
74
73
  case type
@@ -6,9 +6,7 @@ module Mihari
6
6
  module Analyzers
7
7
  class Urlscan < Base
8
8
  param :query
9
- option :title, default: proc { "urlscan search" }
10
- option :description, default: proc { "query = #{query}" }
11
- option :tags, default: proc { [] }
9
+
12
10
  option :allowed_data_types, default: proc { SUPPORTED_DATA_TYPES }
13
11
 
14
12
  option :interval, default: proc { 0 }
@@ -29,9 +27,10 @@ module Mihari
29
27
  allowed_data_types.map do |type|
30
28
  results.filter_map do |result|
31
29
  page = result.page
32
- page.send(type.to_sym)
33
- end.uniq
34
- end.flatten.compact
30
+ data = page.send(type.to_sym)
31
+ data.nil? ? nil : Artifact.new(data: data, source: source, metadata: result)
32
+ end
33
+ end.flatten
35
34
  end
36
35
 
37
36
  private
@@ -8,9 +8,6 @@ module Mihari
8
8
  include Mixins::Refang
9
9
 
10
10
  param :query
11
- option :title, default: proc { "VirusTotal search" }
12
- option :description, default: proc { "query = #{query}" }
13
- option :tags, default: proc { [] }
14
11
 
15
12
  attr_reader :type
16
13
 
@@ -47,7 +44,7 @@ module Mihari
47
44
  #
48
45
  # Search
49
46
  #
50
- # @return [Array<String>]
47
+ # @return [Array<Mihari::Artifact>]
51
48
  #
52
49
  def search
53
50
  case type
@@ -63,28 +60,30 @@ module Mihari
63
60
  #
64
61
  # Domain search
65
62
  #
66
- # @return [Array<String>]
63
+ # @return [Array<Mihari::Artifact>]
67
64
  #
68
65
  def domain_search
69
66
  res = api.domain.resolutions(query)
70
67
 
71
68
  data = res["data"] || []
72
69
  data.filter_map do |item|
73
- item.dig("attributes", "ip_address")
74
- end.uniq
70
+ data = item.dig("attributes", "ip_address")
71
+ data.nil? ? nil : Artifact.new(data: data, source: source, metadata: item)
72
+ end
75
73
  end
76
74
 
77
75
  #
78
76
  # IP search
79
77
  #
80
- # @return [Array<String>]
78
+ # @return [Array<Mihari::Artifact>]
81
79
  #
82
80
  def ip_search
83
81
  res = api.ip_address.resolutions(query)
84
82
 
85
83
  data = res["data"] || []
86
84
  data.filter_map do |item|
87
- item.dig("attributes", "host_name")
85
+ data = item.dig("attributes", "host_name")
86
+ Artifact.new(data: data, source: source, metadata: item)
88
87
  end.uniq
89
88
  end
90
89
  end
@@ -6,9 +6,6 @@ module Mihari
6
6
  module Analyzers
7
7
  class VirusTotalIntelligence < Base
8
8
  param :query
9
- option :title, default: proc { "VirusTotal Intelligence search" }
10
- option :description, default: proc { "query = #{query}" }
11
- option :tags, default: proc { [] }
12
9
 
13
10
  option :interval, default: proc { 0 }
14
11
 
@@ -21,8 +18,10 @@ module Mihari
21
18
  def artifacts
22
19
  responses = search_witgh_cursor
23
20
  responses.map do |response|
24
- response.data.map(&:value)
25
- end.flatten.compact.uniq
21
+ response.data.map do |datum|
22
+ Artifact.new(data: datum.value, source: source, metadata: datum.metadata)
23
+ end
24
+ end.flatten
26
25
  end
27
26
 
28
27
  private
@@ -6,9 +6,7 @@ module Mihari
6
6
  module Analyzers
7
7
  class ZoomEye < Base
8
8
  param :query
9
- option :title, default: proc { "ZoomEye search" }
10
- option :description, default: proc { "query = #{query}" }
11
- option :tags, default: proc { [] }
9
+
12
10
  option :type, default: proc { "host" }
13
11
 
14
12
  option :interval, default: proc { 0 }
@@ -50,13 +48,14 @@ module Mihari
50
48
  #
51
49
  # @param [Array<Hash>] responses
52
50
  #
53
- # @return [Array<String>]
51
+ # @return [Array<Mihari::Artifact>]
54
52
  #
55
53
  def convert_responses(responses)
56
54
  responses.map do |res|
57
55
  matches = res["matches"] || []
58
56
  matches.map do |match|
59
- match["ip"]
57
+ data = match["ip"]
58
+ Artifact.new(data: data, source: source, metadata: match)
60
59
  end
61
60
  end.flatten.compact.uniq
62
61
  end
@@ -1,15 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "thor"
4
-
5
- require "mihari/mixins/hash"
6
-
7
3
  require "mihari/cli/mixins/utils"
8
4
 
9
5
  module Mihari
10
6
  module CLI
11
7
  class Base < Thor
12
- include Mihari::Mixins::Hash
13
8
  include Mixins::Utils
14
9
 
15
10
  class << self
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "thor"
4
-
5
3
  require "mihari/commands/init"
6
4
 
7
5
  module Mihari
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "thor"
4
+
3
5
  # Commands
4
6
  require "mihari/commands/search"
5
7
  require "mihari/commands/web"
@@ -7,7 +9,6 @@ require "mihari/commands/web"
7
9
  # CLIs
8
10
  require "mihari/cli/base"
9
11
 
10
- require "mihari/cli/analyzer"
11
12
  require "mihari/cli/init"
12
13
  require "mihari/cli/validator"
13
14
 
@@ -17,13 +18,10 @@ module Mihari
17
18
  include Mihari::Commands::Search
18
19
  include Mihari::Commands::Web
19
20
 
20
- desc "analyze", "Sub commands to run an analyzer"
21
- subcommand "analyze", Analyzer
22
-
23
- desc "init", "Sub commands to initialize config & rule"
21
+ desc "init", "Sub commands to initialize a rule"
24
22
  subcommand "init", Initialization
25
23
 
26
- desc "validate", "Sub commands to validate format of config & rule"
24
+ desc "validate", "Sub commands to validate format of a rule"
27
25
  subcommand "validate", Validator
28
26
  end
29
27
  end