mihari 7.1.3 → 7.3.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.
- checksums.yaml +4 -4
- data/Dockerfile +2 -2
- data/Rakefile +8 -1
- data/lefthook.yml +4 -1
- data/lib/mihari/actor.rb +16 -0
- data/lib/mihari/analyzers/base.rb +7 -25
- data/lib/mihari/analyzers/binaryedge.rb +0 -6
- data/lib/mihari/analyzers/censys.rb +0 -9
- data/lib/mihari/analyzers/circl.rb +0 -6
- data/lib/mihari/analyzers/fofa.rb +0 -6
- data/lib/mihari/analyzers/greynoise.rb +0 -6
- data/lib/mihari/analyzers/hunterhow.rb +0 -6
- data/lib/mihari/analyzers/onyphe.rb +0 -6
- data/lib/mihari/analyzers/otx.rb +0 -6
- data/lib/mihari/analyzers/passivetotal.rb +0 -4
- data/lib/mihari/analyzers/pulsedive.rb +0 -6
- data/lib/mihari/analyzers/securitytrails.rb +0 -4
- data/lib/mihari/analyzers/shodan.rb +0 -6
- data/lib/mihari/analyzers/urlscan.rb +0 -6
- data/lib/mihari/analyzers/virustotal.rb +0 -4
- data/lib/mihari/analyzers/virustotal_intelligence.rb +7 -6
- data/lib/mihari/analyzers/zoomeye.rb +0 -6
- data/lib/mihari/commands/web.rb +1 -1
- data/lib/mihari/concerns/falsepositive_normalizable.rb +30 -0
- data/lib/mihari/concerns/falsepositive_validatable.rb +1 -17
- data/lib/mihari/config.rb +1 -1
- data/lib/mihari/database.rb +18 -1
- data/lib/mihari/emitters/database.rb +0 -6
- data/lib/mihari/emitters/misp.rb +0 -6
- data/lib/mihari/emitters/slack.rb +5 -21
- data/lib/mihari/emitters/the_hive.rb +0 -6
- data/lib/mihari/enrichers/base.rb +54 -12
- data/lib/mihari/enrichers/google_public_dns.rb +28 -7
- data/lib/mihari/enrichers/mmdb.rb +25 -7
- data/lib/mihari/enrichers/shodan.rb +35 -4
- data/lib/mihari/enrichers/whois.rb +37 -31
- data/lib/mihari/entities/artifact.rb +6 -2
- data/lib/mihari/entities/autonomous_system.rb +1 -1
- data/lib/mihari/entities/cpe.rb +1 -1
- data/lib/mihari/entities/port.rb +1 -1
- data/lib/mihari/entities/vulnerability.rb +10 -0
- data/lib/mihari/errors.rb +2 -0
- data/lib/mihari/models/alert.rb +12 -0
- data/lib/mihari/models/artifact.rb +118 -159
- data/lib/mihari/models/rule.rb +21 -0
- data/lib/mihari/models/vulnerability.rb +12 -0
- data/lib/mihari/rule.rb +44 -29
- data/lib/mihari/schemas/alert.rb +3 -3
- data/lib/mihari/schemas/analyzer.rb +27 -27
- data/lib/mihari/schemas/emitter.rb +9 -9
- data/lib/mihari/schemas/macros.rb +2 -2
- data/lib/mihari/schemas/options.rb +2 -5
- data/lib/mihari/schemas/rule.rb +19 -12
- data/lib/mihari/services/builders.rb +0 -134
- data/lib/mihari/services/enrichers.rb +3 -1
- data/lib/mihari/services/feed.rb +2 -5
- data/lib/mihari/services/getters.rb +1 -1
- data/lib/mihari/services/proxies.rb +3 -3
- data/lib/mihari/structs/censys.rb +2 -2
- data/lib/mihari/structs/greynoise.rb +1 -1
- data/lib/mihari/structs/onyphe.rb +1 -1
- data/lib/mihari/structs/shodan.rb +59 -21
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/endpoints/artifacts.rb +4 -2
- data/lib/mihari/web/endpoints/rules.rb +1 -1
- data/lib/mihari/web/public/assets/{index-TOeU8PE2.js → index-JHS0L8KZ.js} +47 -47
- data/lib/mihari/web/public/assets/{index-dVaNxqTC.css → index-ReF8ffd-.css} +1 -1
- data/lib/mihari/web/public/index.html +2 -2
- data/lib/mihari/web/public/redoc-static.html +17 -17
- data/lib/mihari.rb +3 -0
- data/mihari.gemspec +2 -2
- data/requirements.txt +1 -1
- 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
|
85
|
+
def autonomous_system
|
78
86
|
return nil if asn.nil?
|
79
87
|
|
80
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
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.
|
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
|
data/lib/mihari/version.rb
CHANGED
@@ -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
|
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
|
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
|