mihari 7.1.3 → 7.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +2 -2
  3. data/Rakefile +8 -1
  4. data/lefthook.yml +4 -1
  5. data/lib/mihari/actor.rb +16 -0
  6. data/lib/mihari/analyzers/base.rb +7 -25
  7. data/lib/mihari/analyzers/binaryedge.rb +0 -6
  8. data/lib/mihari/analyzers/censys.rb +0 -9
  9. data/lib/mihari/analyzers/circl.rb +0 -6
  10. data/lib/mihari/analyzers/fofa.rb +0 -6
  11. data/lib/mihari/analyzers/greynoise.rb +0 -6
  12. data/lib/mihari/analyzers/hunterhow.rb +0 -6
  13. data/lib/mihari/analyzers/onyphe.rb +0 -6
  14. data/lib/mihari/analyzers/otx.rb +0 -6
  15. data/lib/mihari/analyzers/passivetotal.rb +0 -4
  16. data/lib/mihari/analyzers/pulsedive.rb +0 -6
  17. data/lib/mihari/analyzers/securitytrails.rb +0 -4
  18. data/lib/mihari/analyzers/shodan.rb +0 -6
  19. data/lib/mihari/analyzers/urlscan.rb +0 -6
  20. data/lib/mihari/analyzers/virustotal.rb +0 -4
  21. data/lib/mihari/analyzers/virustotal_intelligence.rb +7 -6
  22. data/lib/mihari/analyzers/zoomeye.rb +0 -6
  23. data/lib/mihari/commands/web.rb +1 -1
  24. data/lib/mihari/concerns/falsepositive_normalizable.rb +30 -0
  25. data/lib/mihari/concerns/falsepositive_validatable.rb +1 -17
  26. data/lib/mihari/config.rb +1 -1
  27. data/lib/mihari/database.rb +18 -1
  28. data/lib/mihari/emitters/database.rb +0 -6
  29. data/lib/mihari/emitters/misp.rb +0 -6
  30. data/lib/mihari/emitters/slack.rb +5 -21
  31. data/lib/mihari/emitters/the_hive.rb +0 -6
  32. data/lib/mihari/enrichers/base.rb +54 -12
  33. data/lib/mihari/enrichers/google_public_dns.rb +28 -7
  34. data/lib/mihari/enrichers/mmdb.rb +25 -7
  35. data/lib/mihari/enrichers/shodan.rb +35 -4
  36. data/lib/mihari/enrichers/whois.rb +37 -31
  37. data/lib/mihari/entities/artifact.rb +6 -2
  38. data/lib/mihari/entities/autonomous_system.rb +1 -1
  39. data/lib/mihari/entities/cpe.rb +1 -1
  40. data/lib/mihari/entities/port.rb +1 -1
  41. data/lib/mihari/entities/vulnerability.rb +10 -0
  42. data/lib/mihari/errors.rb +2 -0
  43. data/lib/mihari/models/alert.rb +12 -0
  44. data/lib/mihari/models/artifact.rb +118 -159
  45. data/lib/mihari/models/rule.rb +21 -0
  46. data/lib/mihari/models/vulnerability.rb +12 -0
  47. data/lib/mihari/rule.rb +44 -29
  48. data/lib/mihari/schemas/alert.rb +3 -3
  49. data/lib/mihari/schemas/analyzer.rb +27 -27
  50. data/lib/mihari/schemas/emitter.rb +9 -9
  51. data/lib/mihari/schemas/macros.rb +2 -2
  52. data/lib/mihari/schemas/options.rb +2 -5
  53. data/lib/mihari/schemas/rule.rb +19 -12
  54. data/lib/mihari/services/builders.rb +0 -134
  55. data/lib/mihari/services/enrichers.rb +3 -1
  56. data/lib/mihari/services/feed.rb +2 -5
  57. data/lib/mihari/services/getters.rb +1 -1
  58. data/lib/mihari/services/proxies.rb +3 -3
  59. data/lib/mihari/structs/censys.rb +2 -2
  60. data/lib/mihari/structs/greynoise.rb +1 -1
  61. data/lib/mihari/structs/onyphe.rb +1 -1
  62. data/lib/mihari/structs/shodan.rb +59 -21
  63. data/lib/mihari/version.rb +1 -1
  64. data/lib/mihari/web/endpoints/artifacts.rb +4 -2
  65. data/lib/mihari/web/endpoints/rules.rb +1 -1
  66. data/lib/mihari/web/public/assets/{index-TOeU8PE2.js → index-JHS0L8KZ.js} +47 -47
  67. data/lib/mihari/web/public/assets/{index-dVaNxqTC.css → index-ReF8ffd-.css} +1 -1
  68. data/lib/mihari/web/public/index.html +2 -2
  69. data/lib/mihari/web/public/redoc-static.html +17 -17
  70. data/lib/mihari.rb +3 -0
  71. data/mihari.gemspec +2 -2
  72. data/requirements.txt +1 -1
  73. metadata +11 -8
@@ -67,17 +67,25 @@ module Mihari
67
67
  # @return [Integer]
68
68
  attribute :port, Types::Int
69
69
 
70
+ # @!attribute [r] cpe
71
+ # @return [Array<String>]
72
+ attribute :cpe, Types::Array(Types::String)
73
+
74
+ # @!attribute [r] vulns
75
+ # @return [Hash]
76
+ attribute :vulns, Types::Hash
77
+
70
78
  # @!attribute [r] metadata
71
79
  # @return [Hash]
72
80
  attribute :metadata, Types::Hash
73
81
 
74
82
  #
75
- # @return [Mihari::AutonomousSystem, nil]
83
+ # @return [Mihari::Models::AutonomousSystem, nil]
76
84
  #
77
- def _asn
85
+ def autonomous_system
78
86
  return nil if asn.nil?
79
87
 
80
- Mihari::Models::AutonomousSystem.new(asn: normalize_asn(asn))
88
+ Models::AutonomousSystem.new(number: normalize_asn(asn))
81
89
  end
82
90
 
83
91
  class << self
@@ -103,6 +111,8 @@ module Mihari
103
111
  domains: d.fetch("domains"),
104
112
  ip_str: d.fetch("ip_str"),
105
113
  port: d.fetch("port"),
114
+ cpe: d["cpe"] || [],
115
+ vulns: d["vulns"] || {},
106
116
  metadata: d
107
117
  )
108
118
  end
@@ -110,6 +120,8 @@ module Mihari
110
120
  end
111
121
 
112
122
  class Response < Dry::Struct
123
+ prepend MemoWise
124
+
113
125
  # @!attribute [r] matches
114
126
  # @return [Array<Match>]
115
127
  attribute :matches, Types.Array(Match)
@@ -118,6 +130,16 @@ module Mihari
118
130
  # @return [Integer]
119
131
  attribute :total, Types::Int
120
132
 
133
+ #
134
+ # @param [String] ip
135
+ #
136
+ # @return [Array<Mihari::Structs::Shodan::Match>]
137
+ #
138
+ def select_matches_by_ip(ip)
139
+ matches.select { |match| match.ip_str == ip }
140
+ end
141
+ memo_wise :select_matches_by_ip
142
+
121
143
  #
122
144
  # Collect metadata from matches
123
145
  #
@@ -126,7 +148,7 @@ module Mihari
126
148
  # @return [Array<Hash>]
127
149
  #
128
150
  def collect_metadata_by_ip(ip)
129
- matches.select { |match| match.ip_str == ip }.map(&:metadata)
151
+ select_matches_by_ip(ip).map(&:metadata)
130
152
  end
131
153
 
132
154
  #
@@ -137,7 +159,7 @@ module Mihari
137
159
  # @return [Array<String>]
138
160
  #
139
161
  def collect_ports_by_ip(ip)
140
- matches.select { |match| match.ip_str == ip }.map(&:port)
162
+ select_matches_by_ip(ip).map(&:port)
141
163
  end
142
164
 
143
165
  #
@@ -148,7 +170,30 @@ module Mihari
148
170
  # @return [Array<String>]
149
171
  #
150
172
  def collect_hostnames_by_ip(ip)
151
- matches.select { |match| match.ip_str == ip }.map(&:hostnames).flatten.uniq
173
+ select_matches_by_ip(ip).map(&:hostnames).flatten.uniq
174
+ end
175
+
176
+ #
177
+ # Collect CPE from matches
178
+ #
179
+ # @param [String] ip
180
+ #
181
+ # @return [Array<String>]
182
+ #
183
+ def collect_cpes_by_ip(ip)
184
+ select_matches_by_ip(ip).map(&:cpe).flatten.uniq
185
+ end
186
+
187
+ #
188
+ # Collect vulnerabilities from matches
189
+ #
190
+ # @param [String] ip
191
+ #
192
+ # @return [Array<String>]
193
+ #
194
+ def collect_vulns_by_ip(ip)
195
+ # NOTE: vuln keys = CVE IDs
196
+ select_matches_by_ip(ip).map { |match| match.vulns.keys }.flatten.uniq
152
197
  end
153
198
 
154
199
  #
@@ -158,20 +203,22 @@ module Mihari
158
203
  matches.map do |match|
159
204
  metadata = collect_metadata_by_ip(match.ip_str)
160
205
 
161
- ports = collect_ports_by_ip(match.ip_str).map do |port|
162
- Mihari::Models::Port.new(port: port)
163
- end
206
+ ports = collect_ports_by_ip(match.ip_str).map { |port| Models::Port.new(number: port) }
164
207
  reverse_dns_names = collect_hostnames_by_ip(match.ip_str).map do |name|
165
- Mihari::Models::ReverseDnsName.new(name: name)
208
+ Models::ReverseDnsName.new(name: name)
166
209
  end
210
+ cpes = collect_cpes_by_ip(match.ip_str).map { |name| Models::CPE.new(name: name) }
211
+ vulnerabilities = collect_vulns_by_ip(match.ip_str).map { |name| Models::Vulnerability.new(name: name) }
167
212
 
168
213
  Mihari::Models::Artifact.new(
169
214
  data: match.ip_str,
170
215
  metadata: metadata,
171
- autonomous_system: match._asn,
216
+ autonomous_system: match.autonomous_system,
172
217
  geolocation: match.location.geolocation,
173
218
  ports: ports,
174
- reverse_dns_names: reverse_dns_names
219
+ reverse_dns_names: reverse_dns_names,
220
+ cpes: cpes,
221
+ vulnerabilities: vulnerabilities
175
222
  )
176
223
  end
177
224
  end
@@ -232,15 +279,6 @@ module Mihari
232
279
  vulns: d.fetch("vulns")
233
280
  )
234
281
  end
235
-
236
- #
237
- # @param [String] json
238
- #
239
- # @return [InternetDBResponse]
240
- #
241
- def from_json!(json)
242
- from_dynamic!(JSON.parse(json))
243
- end
244
282
  end
245
283
  end
246
284
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- VERSION = "7.1.3"
4
+ VERSION = "7.3.0"
5
5
  end
@@ -53,7 +53,7 @@ module Mihari
53
53
 
54
54
  desc "Enrich an artifact", {
55
55
  success: { code: 201, model: Entities::Message },
56
- failure: [{ code: 404, model: Entities::ErrorMessage }],
56
+ failure: [{ code: 400, model: Entities::ErrorMessage }, { code: 404, model: Entities::ErrorMessage }],
57
57
  summary: "Enrich an artifact"
58
58
  }
59
59
  params do
@@ -74,10 +74,12 @@ module Mihari
74
74
  end
75
75
  end.to_result
76
76
 
77
- message = queued ? "ID:#{id}'s enrichment has been queued" : "ID:#{id}'s enrichment has been succeeded"
77
+ message = queued ? "ID:#{id}'s enrichment is queued" : "ID:#{id}'s enrichment is successful"
78
78
  return present({ message: message, queued: queued }, with: Entities::QueueMessage) if result.success?
79
79
 
80
80
  case result.failure
81
+ when UnenrichableError
82
+ error!({ message: result.failure.message }, 400)
81
83
  when ActiveRecord::RecordNotFound
82
84
  error!({ message: "ID:#{id} not found" }, 404)
83
85
  end
@@ -94,7 +94,7 @@ module Mihari
94
94
  end
95
95
  end.to_result
96
96
 
97
- message = queued ? "ID:#{id}'s search has been queued" : "ID:#{id}'s search has been succeed"
97
+ message = queued ? "ID:#{id}'s search is queued" : "ID:#{id}'s search is successful"
98
98
  return present({ message: message, queued: queued }, with: Entities::QueueMessage) if result.success?
99
99
 
100
100
  case result.failure