mihari 5.6.1 → 5.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -1
  3. data/README.md +1 -0
  4. data/config.ru +1 -1
  5. data/docs/analyzers/fofa.md +31 -0
  6. data/docs/analyzers/index.md +1 -0
  7. data/frontend/package-lock.json +183 -186
  8. data/frontend/package.json +10 -10
  9. data/frontend/src/components/alert/Form.vue +1 -14
  10. data/frontend/src/components/artifact/AS.vue +2 -8
  11. data/frontend/src/components/artifact/DnsRecords.vue +2 -8
  12. data/frontend/src/components/artifact/ReverseDnsNames.vue +2 -10
  13. data/frontend/src/components/artifact/WhoisRecord.vue +1 -1
  14. data/lib/mihari/{base.rb → actor.rb} +27 -3
  15. data/lib/mihari/analyzers/base.rb +16 -20
  16. data/lib/mihari/analyzers/binaryedge.rb +4 -1
  17. data/lib/mihari/analyzers/censys.rb +5 -3
  18. data/lib/mihari/analyzers/circl.rb +4 -1
  19. data/lib/mihari/analyzers/crtsh.rb +4 -1
  20. data/lib/mihari/analyzers/dnstwister.rb +4 -1
  21. data/lib/mihari/analyzers/feed.rb +3 -0
  22. data/lib/mihari/analyzers/fofa.rb +65 -0
  23. data/lib/mihari/analyzers/greynoise.rb +4 -1
  24. data/lib/mihari/analyzers/hunterhow.rb +7 -2
  25. data/lib/mihari/analyzers/onyphe.rb +4 -1
  26. data/lib/mihari/analyzers/otx.rb +4 -1
  27. data/lib/mihari/analyzers/passivetotal.rb +5 -2
  28. data/lib/mihari/analyzers/pulsedive.rb +4 -1
  29. data/lib/mihari/analyzers/securitytrails.rb +5 -2
  30. data/lib/mihari/analyzers/shodan.rb +4 -1
  31. data/lib/mihari/analyzers/urlscan.rb +5 -2
  32. data/lib/mihari/analyzers/virustotal.rb +9 -6
  33. data/lib/mihari/analyzers/virustotal_intelligence.rb +4 -1
  34. data/lib/mihari/analyzers/zoomeye.rb +8 -5
  35. data/lib/mihari/cli/alert.rb +3 -0
  36. data/lib/mihari/cli/base.rb +3 -0
  37. data/lib/mihari/cli/database.rb +3 -0
  38. data/lib/mihari/cli/main.rb +3 -0
  39. data/lib/mihari/cli/rule.rb +3 -0
  40. data/lib/mihari/clients/base.rb +3 -0
  41. data/lib/mihari/clients/binaryedge.rb +5 -2
  42. data/lib/mihari/clients/censys.rb +7 -4
  43. data/lib/mihari/clients/circl.rb +3 -0
  44. data/lib/mihari/clients/crtsh.rb +5 -2
  45. data/lib/mihari/clients/dnstwister.rb +3 -0
  46. data/lib/mihari/clients/fofa.rb +83 -0
  47. data/lib/mihari/clients/greynoise.rb +5 -2
  48. data/lib/mihari/clients/hunterhow.rb +5 -2
  49. data/lib/mihari/clients/misp.rb +3 -0
  50. data/lib/mihari/clients/onyphe.rb +5 -2
  51. data/lib/mihari/clients/otx.rb +3 -0
  52. data/lib/mihari/clients/passivetotal.rb +7 -4
  53. data/lib/mihari/clients/publsedive.rb +4 -1
  54. data/lib/mihari/clients/securitytrails.rb +6 -3
  55. data/lib/mihari/clients/shodan.rb +5 -2
  56. data/lib/mihari/clients/the_hive.rb +3 -0
  57. data/lib/mihari/clients/urlscan.rb +7 -4
  58. data/lib/mihari/clients/virustotal.rb +5 -2
  59. data/lib/mihari/clients/zoomeye.rb +3 -0
  60. data/lib/mihari/commands/alert.rb +5 -14
  61. data/lib/mihari/commands/database.rb +3 -0
  62. data/lib/mihari/commands/rule.rb +11 -11
  63. data/lib/mihari/commands/search.rb +9 -6
  64. data/lib/mihari/commands/version.rb +3 -0
  65. data/lib/mihari/commands/web.rb +4 -1
  66. data/lib/mihari/config.rb +139 -150
  67. data/lib/mihari/constants.rb +1 -1
  68. data/lib/mihari/database.rb +6 -0
  69. data/lib/mihari/emitters/base.rb +16 -25
  70. data/lib/mihari/emitters/database.rb +10 -9
  71. data/lib/mihari/emitters/misp.rb +20 -41
  72. data/lib/mihari/emitters/slack.rb +16 -13
  73. data/lib/mihari/emitters/the_hive.rb +18 -46
  74. data/lib/mihari/emitters/webhook.rb +34 -23
  75. data/lib/mihari/enrichers/base.rb +16 -15
  76. data/lib/mihari/enrichers/google_public_dns.rb +6 -5
  77. data/lib/mihari/enrichers/ipinfo.rb +10 -8
  78. data/lib/mihari/enrichers/shodan.rb +4 -6
  79. data/lib/mihari/enrichers/whois.rb +13 -10
  80. data/lib/mihari/errors.rb +6 -0
  81. data/lib/mihari/feed/parser.rb +3 -0
  82. data/lib/mihari/feed/reader.rb +3 -0
  83. data/lib/mihari/http.rb +6 -0
  84. data/lib/mihari/mixins/autonomous_system.rb +3 -0
  85. data/lib/mihari/mixins/configurable.rb +3 -0
  86. data/lib/mihari/mixins/error_notification.rb +3 -0
  87. data/lib/mihari/mixins/falsepositive.rb +3 -0
  88. data/lib/mihari/mixins/refang.rb +3 -0
  89. data/lib/mihari/mixins/retriable.rb +6 -2
  90. data/lib/mihari/models/alert.rb +78 -73
  91. data/lib/mihari/models/artifact.rb +186 -178
  92. data/lib/mihari/models/autonomous_system.rb +25 -20
  93. data/lib/mihari/models/cpe.rb +24 -19
  94. data/lib/mihari/models/dns.rb +27 -22
  95. data/lib/mihari/models/geolocation.rb +25 -20
  96. data/lib/mihari/models/port.rb +24 -19
  97. data/lib/mihari/models/reverse_dns.rb +24 -19
  98. data/lib/mihari/models/rule.rb +71 -66
  99. data/lib/mihari/models/tag.rb +8 -3
  100. data/lib/mihari/models/tagging.rb +8 -3
  101. data/lib/mihari/models/whois.rb +20 -17
  102. data/lib/mihari/rule.rb +357 -0
  103. data/lib/mihari/schemas/alert.rb +3 -0
  104. data/lib/mihari/schemas/analyzer.rb +105 -87
  105. data/lib/mihari/schemas/emitter.rb +12 -5
  106. data/lib/mihari/schemas/enricher.rb +11 -4
  107. data/lib/mihari/schemas/macros.rb +4 -0
  108. data/lib/mihari/schemas/mixins.rb +20 -0
  109. data/lib/mihari/schemas/rule.rb +6 -10
  110. data/lib/mihari/service.rb +16 -0
  111. data/lib/mihari/services/alert_builder.rb +8 -5
  112. data/lib/mihari/services/alert_proxy.rb +16 -7
  113. data/lib/mihari/services/alert_runner.rb +10 -14
  114. data/lib/mihari/services/rule_builder.rb +10 -7
  115. data/lib/mihari/services/rule_runner.rb +11 -13
  116. data/lib/mihari/structs/binaryedge.rb +14 -29
  117. data/lib/mihari/structs/censys.rb +54 -133
  118. data/lib/mihari/structs/config.rb +20 -31
  119. data/lib/mihari/structs/filters.rb +38 -0
  120. data/lib/mihari/structs/fofa.rb +44 -0
  121. data/lib/mihari/structs/google_public_dns.rb +10 -28
  122. data/lib/mihari/structs/greynoise.rb +38 -89
  123. data/lib/mihari/structs/hunterhow.rb +27 -25
  124. data/lib/mihari/structs/ipinfo.rb +14 -35
  125. data/lib/mihari/structs/onyphe.rb +36 -81
  126. data/lib/mihari/structs/shodan.rb +53 -118
  127. data/lib/mihari/structs/urlscan.rb +27 -66
  128. data/lib/mihari/structs/virustotal_intelligence.rb +23 -59
  129. data/lib/mihari/type_checker.rb +4 -0
  130. data/lib/mihari/types.rb +3 -0
  131. data/lib/mihari/version.rb +1 -1
  132. data/lib/mihari/web/api.rb +15 -10
  133. data/lib/mihari/web/app.rb +59 -54
  134. data/lib/mihari/web/endpoints/alerts.rb +94 -89
  135. data/lib/mihari/web/endpoints/artifacts.rb +115 -110
  136. data/lib/mihari/web/endpoints/configs.rb +18 -13
  137. data/lib/mihari/web/endpoints/ip_addresses.rb +21 -16
  138. data/lib/mihari/web/endpoints/rules.rb +202 -204
  139. data/lib/mihari/web/endpoints/tags.rb +41 -36
  140. data/lib/mihari/web/middleware/connection_adapter.rb +16 -9
  141. data/lib/mihari/web/middleware/error_notification_adapter.rb +17 -10
  142. data/lib/mihari/web/public/assets/{index-9cc489e6.js → index-821134e2.js} +54 -54
  143. data/lib/mihari/web/public/assets/mode-yaml-24faa242.js +8 -0
  144. data/lib/mihari/web/public/index.html +1 -1
  145. data/lib/mihari.rb +30 -13
  146. data/mihari.gemspec +9 -3
  147. data/mkdocs.yml +3 -2
  148. data/requirements.txt +1 -1
  149. metadata +44 -26
  150. data/lib/mihari/analyzers/rule.rb +0 -232
  151. data/lib/mihari/services/rule_proxy.rb +0 -182
  152. data/lib/mihari/templates/rule.yml.erb +0 -5
  153. data/lib/mihari/web/public/assets/mode-yaml-a21faa53.js +0 -8
@@ -19,8 +19,8 @@
19
19
  "@fortawesome/vue-fontawesome": "^3.0.3",
20
20
  "@vueuse/core": "^10.5.0",
21
21
  "@vueuse/router": "^10.5.0",
22
- "ace-builds": "^1.30.0",
23
- "axios": "^1.5.1",
22
+ "ace-builds": "^1.31.1",
23
+ "axios": "^1.6.0",
24
24
  "bulma": "^0.9.4",
25
25
  "bulma-helpers": "^0.4.3",
26
26
  "dayjs": "^1.11.10",
@@ -30,21 +30,21 @@
30
30
  "ts-dedent": "^2.2.0",
31
31
  "url-parse": "^1.5.10",
32
32
  "uuidv4": "^6.2.13",
33
- "vue": "^3.3.6",
33
+ "vue": "^3.3.7",
34
34
  "vue-concurrency": "4.0.1",
35
35
  "vue-json-pretty": "^2.2.4",
36
36
  "vue-router": "^4.2.5",
37
- "vue3-ace-editor": "^2.2.3"
37
+ "vue3-ace-editor": "^2.2.4"
38
38
  },
39
39
  "devDependencies": {
40
- "@redocly/cli": "1.3.0",
40
+ "@redocly/cli": "1.4.0",
41
41
  "@rushstack/eslint-patch": "^1.5.1",
42
42
  "@tsconfig/node20": "^20.1.2",
43
43
  "@types/jsdom": "^21.1.4",
44
- "@types/node": "^20.8.7",
44
+ "@types/node": "^20.8.10",
45
45
  "@types/url-parse": "^1.4.10",
46
- "@typescript-eslint/eslint-plugin": "^6.8.0",
47
- "@typescript-eslint/parser": "^6.8.0",
46
+ "@typescript-eslint/eslint-plugin": "^6.9.1",
47
+ "@typescript-eslint/parser": "^6.9.1",
48
48
  "@vitejs/plugin-vue": "^4.4.0",
49
49
  "@vue/eslint-config-prettier": "^8.0.0",
50
50
  "@vue/eslint-config-typescript": "^12.0.0",
@@ -54,7 +54,7 @@
54
54
  "eslint-config-prettier": "^9.0.0",
55
55
  "eslint-plugin-prettier": "^5.0.1",
56
56
  "eslint-plugin-simple-import-sort": "^10.0.0",
57
- "eslint-plugin-vue": "^9.17.0",
57
+ "eslint-plugin-vue": "^9.18.1",
58
58
  "husky": "^8.0.3",
59
59
  "jsdom": "^22.1.0",
60
60
  "npm-run-all": "^4.1.5",
@@ -62,6 +62,6 @@
62
62
  "typescript": "~5.2.2",
63
63
  "vite": "^4.5.0",
64
64
  "vitest": "^0.34.6",
65
- "vue-tsc": "^1.8.19"
65
+ "vue-tsc": "^1.8.22"
66
66
  }
67
67
  }
@@ -124,24 +124,11 @@ export default defineComponent({
124
124
 
125
125
  const artifact = ref<string | undefined>(undefined)
126
126
  const fromAt = ref<string | undefined>(undefined)
127
- const tagInput = toRef(props, "tag")
127
+ const tagInput = ref<string | undefined>(props.tag)
128
128
  const ruleId = ref<string | undefined>(undefined)
129
129
  const toAt = ref<string | undefined>(undefined)
130
- const asn = ref<number | undefined>(undefined)
131
- const dnsRecord = ref<string | undefined>(undefined)
132
- const reverseDnsName = ref<string | undefined>(undefined)
133
130
 
134
131
  const updateByQueryParams = () => {
135
- const asn_ = route.query["asn"]
136
- const normalizedAsn = normalizeQueryParam(asn_)
137
- asn.value = normalizedAsn === undefined ? undefined : parseInt(normalizedAsn)
138
-
139
- const dnsRecord_ = route.query["dnsRecord"]
140
- dnsRecord.value = normalizeQueryParam(dnsRecord_)
141
-
142
- const reverseDnsName_ = route.query["reverseDnsName"]
143
- reverseDnsName.value = normalizeQueryParam(reverseDnsName_)
144
-
145
132
  const tag_ = route.query["tag"]
146
133
  if (tagInput.value === undefined) {
147
134
  tagInput.value = normalizeQueryParam(tag_)
@@ -1,14 +1,8 @@
1
1
  <template>
2
2
  <div class="tags are-medium">
3
- <router-link
4
- class="tag"
5
- :to="{
6
- name: 'Alerts',
7
- query: { asn: autonomousSystem.asn }
8
- }"
9
- >
3
+ <span class="tag">
10
4
  {{ autonomousSystem.asn }}
11
- </router-link>
5
+ </span>
12
6
  </div>
13
7
  </template>
14
8
 
@@ -3,15 +3,9 @@
3
3
  <div class="control" v-for="(dnsRecord, index) in dnsRecords" :key="index">
4
4
  <div class="tags has-addons are-medium">
5
5
  <span class="tag is-dark"> {{ dnsRecord.resource }}</span>
6
- <router-link
7
- class="tag"
8
- :to="{
9
- name: 'Alerts',
10
- query: { dnsRecord: dnsRecord.value }
11
- }"
12
- >
6
+ <span class="tag">
13
7
  {{ truncate(dnsRecord.value, 50) }}
14
- </router-link>
8
+ </span>
15
9
  </div>
16
10
  </div>
17
11
  </div>
@@ -1,16 +1,8 @@
1
1
  <template>
2
2
  <div class="tags are-medium">
3
- <router-link
4
- class="tag"
5
- v-for="reverseDnsName in reverseDnsNames"
6
- :key="reverseDnsName.name"
7
- :to="{
8
- name: 'Alerts',
9
- query: { reverseDnsName: reverseDnsName.name }
10
- }"
11
- >
3
+ <span class="tag" v-for="reverseDnsName in reverseDnsNames" :key="reverseDnsName.name">
12
4
  {{ reverseDnsName.name }}
13
- </router-link>
5
+ </span>
14
6
  </div>
15
7
  </template>
16
8
 
@@ -20,7 +20,7 @@
20
20
  </div>
21
21
  <div class="control">
22
22
  <div class="tags has-addons are-medium">
23
- <span class="tag is-dark">Exipres on</span>
23
+ <span class="tag is-dark">Expires on</span>
24
24
  <span class="tag is-light">{{ whoisRecord.expiresOn || "N/A" }}</span>
25
25
  </div>
26
26
  </div>
@@ -4,14 +4,19 @@ module Mihari
4
4
  #
5
5
  # Base class for Analyzer, Emitter and Enricher
6
6
  #
7
- class Base
7
+ class Actor < Service
8
+ include Mixins::Configurable
9
+ include Mixins::Retriable
10
+
8
11
  # @return [Hash]
9
12
  attr_reader :options
10
13
 
11
14
  #
12
15
  # @param [Hash, nil] options
13
16
  #
14
- def initialize(*_args, options: nil, **_kwargs)
17
+ def initialize(options: nil)
18
+ super()
19
+
15
20
  @options = options || {}
16
21
  end
17
22
 
@@ -43,6 +48,25 @@ module Mihari
43
48
  options[:timeout]
44
49
  end
45
50
 
51
+ def validate_configuration!
52
+ return if configured?
53
+
54
+ joined = configuration_keys.join(", ")
55
+ be = (configuration_keys.length > 1) ? "are" : "is"
56
+ message = "#{self.class.class_key} is not configured correctly. #{joined} #{be} missing."
57
+ raise ConfigurationError, message
58
+ end
59
+
60
+ def result
61
+ Try[StandardError] do
62
+ retry_on_error(
63
+ times: retry_times,
64
+ interval: retry_interval,
65
+ exponential_backoff: retry_exponential_backoff
66
+ ) { call }
67
+ end.to_result
68
+ end
69
+
46
70
  class << self
47
71
  #
48
72
  # @return [String]
@@ -62,7 +86,7 @@ module Mihari
62
86
  # @return [Array<String>]
63
87
  #
64
88
  def class_keys
65
- ([class_key] + [class_key_aliases]).flatten.compact
89
+ ([class_key] + [class_key_aliases]).flatten.compact.map(&:downcase)
66
90
  end
67
91
  end
68
92
  end
@@ -2,12 +2,10 @@
2
2
 
3
3
  module Mihari
4
4
  module Analyzers
5
- class Base < Mihari::Base
6
- include Dry::Monads[:result, :try]
7
-
8
- include Mixins::Configurable
9
- include Mixins::Retriable
10
-
5
+ #
6
+ # Base class for analyzers
7
+ #
8
+ class Base < Actor
11
9
  # @return [String]
12
10
  attr_reader :query
13
11
 
@@ -45,7 +43,7 @@ module Mihari
45
43
  Mihari.config.ignore_error
46
44
  end
47
45
 
48
- # @return [Array<String>, Array<Mihari::Artifact>]
46
+ # @return [Array<String>, Array<Mihari::Models::Artifact>]
49
47
  def artifacts
50
48
  raise NotImplementedError, "You must implement #{self.class}##{__method__}"
51
49
  end
@@ -55,25 +53,23 @@ module Mihari
55
53
  # - Convert data (string) into an artifact
56
54
  # - Reject an invalid artifact
57
55
  #
58
- # @return [Array<Mihari::Artifact>]
56
+ # @return [Array<Mihari::Models::Artifact>]
59
57
  #
60
58
  def normalized_artifacts
61
- retry_on_error(times: retry_times, interval: retry_interval, exponential_backoff: retry_exponential_backoff) do
62
- artifacts.compact.sort.map do |artifact|
63
- # No need to set data_type manually
64
- # It is set automatically in #initialize
65
- artifact = artifact.is_a?(Artifact) ? artifact : Artifact.new(data: artifact)
66
- artifact.source = self.class.class_key
67
- artifact
68
- end.select(&:valid?).uniq(&:data)
69
- end
59
+ artifacts.compact.sort.map do |artifact|
60
+ # No need to set data_type manually
61
+ # It is set automatically in #initialize
62
+ artifact = artifact.is_a?(Models::Artifact) ? artifact : Models::Artifact.new(data: artifact)
63
+ artifact.source = self.class.class_key
64
+ artifact
65
+ end.select(&:valid?).uniq(&:data)
70
66
  end
71
67
 
72
68
  #
73
- # @return [Dry::Monads::Result::Success<Array<Mihari::Artifact>>, Dry::Monads::Result::Failure]
69
+ # @return [Array<Mihari::Models::Artifact>]
74
70
  #
75
- def result
76
- Try[StandardError] { normalized_artifacts }.to_result
71
+ def call
72
+ normalized_artifacts
77
73
  end
78
74
 
79
75
  class << self
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Analyzers
5
+ #
6
+ # BinaryEdge analyzer
7
+ #
5
8
  class BinaryEdge < Base
6
9
  # @return [String, nil]
7
10
  attr_reader :api_key
@@ -32,7 +35,7 @@ module Mihari
32
35
  # @return [Mihari::Clients::BinaryEdge]
33
36
  #
34
37
  def client
35
- @client ||= Clients::BinaryEdge.new(
38
+ Clients::BinaryEdge.new(
36
39
  api_key: api_key,
37
40
  pagination_interval: pagination_interval,
38
41
  timeout: timeout
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Analyzers
5
+ #
6
+ # Censys analyzer
7
+ #
5
8
  class Censys < Base
6
9
  # @return [String, nil]
7
10
  attr_reader :id
@@ -12,7 +15,6 @@ module Mihari
12
15
  #
13
16
  # @param [String] query
14
17
  # @param [hash, nil] options
15
- # @param [String, nil] api_key
16
18
  # @param [String, nil] id
17
19
  # @param [String, nil] secret
18
20
  #
@@ -24,7 +26,7 @@ module Mihari
24
26
  end
25
27
 
26
28
  #
27
- # @return [Array<Mihari::Artifact>]
29
+ # @return [Array<Mihari::Models::Artifact>]
28
30
  #
29
31
  def artifacts
30
32
  client.search_with_pagination(query, pagination_limit: pagination_limit).map do |res|
@@ -52,7 +54,7 @@ module Mihari
52
54
  # @return [Mihari::Clients::Censys]
53
55
  #
54
56
  def client
55
- @client ||= Clients::Censys.new(
57
+ Clients::Censys.new(
56
58
  id: id,
57
59
  secret: secret,
58
60
  pagination_interval: pagination_interval,
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Analyzers
5
+ #
6
+ # CIRCL passive DNS/SSL analyzer
7
+ #
5
8
  class CIRCL < Base
6
9
  include Mixins::Refang
7
10
 
@@ -51,7 +54,7 @@ module Mihari
51
54
  private
52
55
 
53
56
  def client
54
- @client ||= Clients::CIRCL.new(username: username, password: password, timeout: timeout)
57
+ Clients::CIRCL.new(username: username, password: password, timeout: timeout)
55
58
  end
56
59
 
57
60
  def username?
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Analyzers
5
+ #
6
+ # crt.sh analyzer
7
+ #
5
8
  class Crtsh < Base
6
9
  # @return [Boolean]
7
10
  attr_reader :exclude_expired
@@ -28,7 +31,7 @@ module Mihari
28
31
  # @return [Mihari::Clients::Crtsh]
29
32
  #
30
33
  def client
31
- @client ||= Mihari::Clients::Crtsh.new(timeout: timeout)
34
+ Mihari::Clients::Crtsh.new(timeout: timeout)
32
35
  end
33
36
  end
34
37
  end
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Analyzers
5
+ #
6
+ # DNSTwister analyzer
7
+ #
5
8
  class DNSTwister < Base
6
9
  include Mixins::Refang
7
10
 
@@ -39,7 +42,7 @@ module Mihari
39
42
  end
40
43
 
41
44
  def client
42
- @client ||= Clients::DNSTwister.new(timeout: timeout)
45
+ Clients::DNSTwister.new(timeout: timeout)
43
46
  end
44
47
 
45
48
  #
@@ -5,6 +5,9 @@ require "mihari/feed/parser"
5
5
 
6
6
  module Mihari
7
7
  module Analyzers
8
+ #
9
+ # Feed analyzer
10
+ #
8
11
  class Feed < Base
9
12
  # @return [Hash, nil]
10
13
  attr_reader :data
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Analyzers
5
+ #
6
+ # Fofa analyzer
7
+ #
8
+ class Fofa < Base
9
+ # @return [String, nil]
10
+ attr_reader :api_key
11
+
12
+ # @return [String, nil]
13
+ attr_reader :email
14
+
15
+ #
16
+ # @param [String] query
17
+ # @param [Hash, nil] options
18
+ # @param [String, nil] api_key
19
+ # @param [String, nil] email
20
+ #
21
+ def initialize(query, options: nil, api_key: nil, email: nil)
22
+ super(query, options: options)
23
+
24
+ @api_key = api_key || Mihari.config.fofa_api_key
25
+ @email = email || Mihari.config.fofa_email
26
+ end
27
+
28
+ def artifacts
29
+ client.search_with_pagination(query, pagination_limit: pagination_limit).map do |res|
30
+ (res.results || []).map { |result| result[1] }
31
+ end.flatten.compact
32
+ end
33
+
34
+ def configuration_keys
35
+ %w[fofa_api_key fofa_email]
36
+ end
37
+
38
+ def configured?
39
+ api_key? && email?
40
+ end
41
+
42
+ private
43
+
44
+ def api_key?
45
+ !api_key.nil?
46
+ end
47
+
48
+ def email?
49
+ !email.nil?
50
+ end
51
+
52
+ #
53
+ # @return [Mihari::Clients::Fofa]
54
+ #
55
+ def client
56
+ Clients::Fofa.new(
57
+ api_key: api_key,
58
+ email: email,
59
+ pagination_interval: pagination_interval,
60
+ timeout: timeout
61
+ )
62
+ end
63
+ end
64
+ end
65
+ end
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Analyzers
5
+ #
6
+ # GreyNoise analyzer
7
+ #
5
8
  class GreyNoise < Base
6
9
  # @return [String, nil]
7
10
  attr_reader :api_key
@@ -31,7 +34,7 @@ module Mihari
31
34
  private
32
35
 
33
36
  def client
34
- @client ||= Clients::GreyNoise.new(
37
+ Clients::GreyNoise.new(
35
38
  api_key: api_key,
36
39
  pagination_interval: pagination_interval,
37
40
  timeout: timeout
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Analyzers
5
+ #
6
+ # hunter.how analyzer
7
+ #
5
8
  class HunterHow < Base
6
9
  # @return [String, nil]
7
10
  attr_reader :api_key
@@ -14,6 +17,8 @@ module Mihari
14
17
 
15
18
  #
16
19
  # @param [String] query
20
+ # @param [Date] start_time
21
+ # @param [Date] end_time
17
22
  # @param [Hash, nil] options
18
23
  # @param [String, nil] api_key
19
24
  #
@@ -27,7 +32,7 @@ module Mihari
27
32
  end
28
33
 
29
34
  #
30
- # @return [Array<Mihari::Artifact>]
35
+ # @return [Array<Mihari::Models::Artifact>]
31
36
  #
32
37
  def artifacts
33
38
  client.search_with_pagination(
@@ -46,7 +51,7 @@ module Mihari
46
51
  private
47
52
 
48
53
  def client
49
- @client ||= Clients::HunterHow.new(
54
+ Clients::HunterHow.new(
50
55
  api_key: api_key,
51
56
  pagination_interval: pagination_interval,
52
57
  timeout: timeout
@@ -4,6 +4,9 @@ require "normalize_country"
4
4
 
5
5
  module Mihari
6
6
  module Analyzers
7
+ #
8
+ # Onyphe analyzer
9
+ #
7
10
  class Onyphe < Base
8
11
  # @return [String, nil]
9
12
  attr_reader :api_key
@@ -33,7 +36,7 @@ module Mihari
33
36
  private
34
37
 
35
38
  def client
36
- @client ||= Clients::Onyphe.new(
39
+ Clients::Onyphe.new(
37
40
  api_key: api_key,
38
41
  pagination_interval: pagination_interval,
39
42
  timeout: timeout
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Analyzers
5
+ #
6
+ # OTX analyzer
7
+ #
5
8
  class OTX < Base
6
9
  include Mixins::Refang
7
10
 
@@ -42,7 +45,7 @@ module Mihari
42
45
  private
43
46
 
44
47
  def client
45
- @client ||= Mihari::Clients::OTX.new(api_key: api_key, timeout: timeout)
48
+ Mihari::Clients::OTX.new(api_key: api_key, timeout: timeout)
46
49
  end
47
50
 
48
51
  #
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Analyzers
5
+ #
6
+ # PassiveTotal analyzer
7
+ #
5
8
  class PassiveTotal < Base
6
9
  include Mixins::Refang
7
10
 
@@ -54,7 +57,7 @@ module Mihari
54
57
  #
55
58
  # @return [Array<String>, nil]
56
59
  #
57
- def key_aliases
60
+ def class_key_aliases
58
61
  ["pt"]
59
62
  end
60
63
  end
@@ -62,7 +65,7 @@ module Mihari
62
65
  private
63
66
 
64
67
  def client
65
- @client ||= Clients::PassiveTotal.new(username: username, api_key: api_key, timeout: timeout)
68
+ Clients::PassiveTotal.new(username: username, api_key: api_key, timeout: timeout)
66
69
  end
67
70
 
68
71
  #
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Analyzers
5
+ #
6
+ # Pulsedive analyzer
7
+ #
5
8
  class Pulsedive < Base
6
9
  include Mixins::Refang
7
10
 
@@ -35,7 +38,7 @@ module Mihari
35
38
  nil
36
39
  else
37
40
  data = property["value"]
38
- Artifact.new(data: data, metadata: property)
41
+ Models::Artifact.new(data: data, metadata: property)
39
42
  end
40
43
  end
41
44
  end
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Analyzers
5
+ #
6
+ # SecurityTrails
7
+ #
5
8
  class SecurityTrails < Base
6
9
  include Mixins::Refang
7
10
 
@@ -48,7 +51,7 @@ module Mihari
48
51
  #
49
52
  # @return [Array<String>, nil]
50
53
  #
51
- def key_aliases
54
+ def class_key_aliases
52
55
  ["st"]
53
56
  end
54
57
  end
@@ -56,7 +59,7 @@ module Mihari
56
59
  private
57
60
 
58
61
  def client
59
- @client ||= Clients::SecurityTrails.new(api_key: api_key, timeout: timeout)
62
+ Clients::SecurityTrails.new(api_key: api_key, timeout: timeout)
60
63
  end
61
64
 
62
65
  #
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Analyzers
5
+ #
6
+ # Shodan analyzer
7
+ #
5
8
  class Shodan < Base
6
9
  # @return [String, nil]
7
10
  attr_reader :api_key
@@ -34,7 +37,7 @@ module Mihari
34
37
  # @return [Clients::Shodan]
35
38
  #
36
39
  def client
37
- @client ||= Clients::Shodan.new(
40
+ Clients::Shodan.new(
38
41
  api_key: api_key,
39
42
  pagination_interval: pagination_interval,
40
43
  timeout: timeout
@@ -2,6 +2,9 @@
2
2
 
3
3
  module Mihari
4
4
  module Analyzers
5
+ #
6
+ # urlscan.io analyzer
7
+ #
5
8
  class Urlscan < Base
6
9
  SUPPORTED_DATA_TYPES = %w[url domain ip].freeze
7
10
 
@@ -29,7 +32,7 @@ module Mihari
29
32
  end
30
33
 
31
34
  def artifacts
32
- # @type [Array<Mihari::Artifact>]
35
+ # @type [Array<Mihari::Models::Artifact>]
33
36
  artifacts = client.search_with_pagination(query, pagination_limit: pagination_limit).map(&:artifacts).flatten
34
37
 
35
38
  artifacts.select do |artifact|
@@ -44,7 +47,7 @@ module Mihari
44
47
  private
45
48
 
46
49
  def client
47
- @client ||= Clients::UrlScan.new(
50
+ Clients::Urlscan.new(
48
51
  api_key: api_key,
49
52
  pagination_interval: pagination_interval,
50
53
  timeout: timeout