mihari 7.1.3 → 7.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|