mihari 5.7.2 → 6.1.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/.rubocop.yml +4 -0
- data/config.ru +2 -0
- data/lib/mihari/actor.rb +1 -1
- data/lib/mihari/analyzers/base.rb +3 -0
- data/lib/mihari/analyzers/dnstwister.rb +2 -4
- data/lib/mihari/analyzers/hunterhow.rb +1 -1
- data/lib/mihari/analyzers/urlscan.rb +1 -4
- data/lib/mihari/cli/main.rb +2 -12
- data/lib/mihari/commands/database.rb +0 -1
- data/lib/mihari/config.rb +5 -1
- data/lib/mihari/database.rb +9 -5
- data/lib/mihari/emitters/misp.rb +2 -2
- data/lib/mihari/emitters/slack.rb +8 -11
- data/lib/mihari/emitters/the_hive.rb +5 -9
- data/lib/mihari/enrichers/base.rb +2 -0
- data/lib/mihari/enrichers/google_public_dns.rb +2 -7
- data/lib/mihari/enrichers/ipinfo.rb +2 -3
- data/lib/mihari/enrichers/shodan.rb +2 -3
- data/lib/mihari/enrichers/whois.rb +11 -20
- data/lib/mihari/entities/artifact.rb +1 -0
- data/lib/mihari/mixins/falsepositive.rb +2 -2
- data/lib/mihari/mixins/refang.rb +1 -4
- data/lib/mihari/mixins/unwrap_error.rb +27 -0
- data/lib/mihari/models/alert.rb +1 -3
- data/lib/mihari/models/artifact.rb +18 -12
- data/lib/mihari/models/rule.rb +1 -2
- data/lib/mihari/rule.rb +14 -10
- data/lib/mihari/service.rb +2 -0
- data/lib/mihari/services/rule_builder.rb +2 -4
- data/lib/mihari/structs/fofa.rb +2 -0
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/app.rb +5 -3
- data/lib/mihari/web/endpoints/alerts.rb +14 -18
- data/lib/mihari/web/endpoints/artifacts.rb +17 -22
- data/lib/mihari/web/endpoints/configs.rb +0 -1
- data/lib/mihari/web/endpoints/ip_addresses.rb +1 -1
- data/lib/mihari/web/endpoints/rules.rb +27 -32
- data/lib/mihari/web/endpoints/tags.rb +7 -9
- data/lib/mihari/web/middleware/connection_adapter.rb +3 -5
- data/lib/mihari/web/middleware/error_notification_adapter.rb +10 -6
- data/lib/mihari/web/public/assets/{index-ec641cb0.js → index-216d49d1.js} +42 -42
- data/lib/mihari/web/public/assets/{index-56fc2187.css → index-4c8509ee.css} +1 -1
- data/lib/mihari/web/public/index.html +2 -2
- data/lib/mihari/web/public/redoc-static.html +29 -49
- data/lib/mihari.rb +9 -10
- data/mihari.gemspec +11 -13
- data/mkdocs.yml +1 -0
- data/requirements.txt +1 -1
- metadata +76 -34
- data/lib/mihari/services/rule_runner.rb +0 -19
data/lib/mihari/service.rb
CHANGED
@@ -20,10 +20,8 @@ module Mihari
|
|
20
20
|
# @return [Hash]
|
21
21
|
#
|
22
22
|
def data
|
23
|
-
|
24
|
-
|
25
|
-
return rule.data
|
26
|
-
end
|
23
|
+
result = Try { Mihari::Models::Rule.find path_or_id }.to_result
|
24
|
+
return result.value! if result.success?
|
27
25
|
|
28
26
|
raise ArgumentError, "#{path_or_id} does not exist" unless Pathname(path_or_id).exist?
|
29
27
|
|
data/lib/mihari/structs/fofa.rb
CHANGED
data/lib/mihari/version.rb
CHANGED
data/lib/mihari/web/app.rb
CHANGED
@@ -39,7 +39,7 @@ module Mihari
|
|
39
39
|
|
40
40
|
def call(env)
|
41
41
|
status, headers, body = API.call(env)
|
42
|
-
return [status, headers, body] unless headers["
|
42
|
+
return [status, headers, body] unless headers["x-cascade"] == "pass"
|
43
43
|
|
44
44
|
# Check if the App wants us to pass the response along to others
|
45
45
|
request_path = env["PATH_INFO"]
|
@@ -53,17 +53,19 @@ module Mihari
|
|
53
53
|
|
54
54
|
class << self
|
55
55
|
def instance
|
56
|
-
|
56
|
+
Rack::Builder.new do
|
57
57
|
use Rack::Cors do
|
58
58
|
allow do
|
59
59
|
origins "*"
|
60
60
|
resource "*", headers: :any, methods: %i[get post put delete options]
|
61
61
|
end
|
62
62
|
end
|
63
|
-
|
64
63
|
use Middleware::ConnectionAdapter
|
65
64
|
use Middleware::ErrorNotificationAdapter
|
66
65
|
|
66
|
+
use Sentry::Rack::CaptureExceptions if Sentry.initialized?
|
67
|
+
use BetterErrors::Middleware if ENV["RACK_ENV"] == "development" && defined?(BetterErrors::Middleware)
|
68
|
+
|
67
69
|
run App.new
|
68
70
|
end.to_app
|
69
71
|
end
|
@@ -77,7 +77,6 @@ module Mihari
|
|
77
77
|
desc "Search alerts", {
|
78
78
|
is_array: true,
|
79
79
|
success: Entities::AlertsWithPagination,
|
80
|
-
failure: [{ code: 404, message: "Not found", model: Entities::Message }],
|
81
80
|
summary: "Search alerts"
|
82
81
|
}
|
83
82
|
params do
|
@@ -103,31 +102,30 @@ module Mihari
|
|
103
102
|
end
|
104
103
|
|
105
104
|
desc "Delete an alert", {
|
106
|
-
success: Entities::Message,
|
107
|
-
failure: [{ code: 404,
|
105
|
+
success: { code: 204, model: Entities::Message },
|
106
|
+
failure: [{ code: 404, model: Entities::Message }],
|
108
107
|
summary: "Delete an alert"
|
109
108
|
}
|
110
109
|
params do
|
111
110
|
requires :id, type: Integer
|
112
111
|
end
|
113
112
|
delete "/:id" do
|
113
|
+
status 204
|
114
|
+
|
114
115
|
id = params["id"].to_i
|
115
116
|
result = AlertDestroyer.result(id)
|
116
|
-
if result.success?
|
117
|
-
status 204
|
118
|
-
return present({ message: "" }, with: Entities::Message)
|
119
|
-
end
|
117
|
+
return present({ message: "" }, with: Entities::Message) if result.success?
|
120
118
|
|
121
|
-
|
122
|
-
case failure
|
119
|
+
case result.failure
|
123
120
|
when ActiveRecord::RecordNotFound
|
124
121
|
error!({ message: "ID:#{id} is not found" }, 404)
|
125
122
|
end
|
126
|
-
raise failure
|
123
|
+
raise result.failure
|
127
124
|
end
|
128
125
|
|
129
126
|
desc "Create an alert", {
|
130
|
-
success: Entities::Alert,
|
127
|
+
success: { code: 201, model: Entities::Alert },
|
128
|
+
failure: [{ code: 404, model: Entities::Message }],
|
131
129
|
summary: "Create an alert"
|
132
130
|
}
|
133
131
|
params do
|
@@ -135,18 +133,16 @@ module Mihari
|
|
135
133
|
requires :artifacts, type: Array, documentation: { type: String, is_array: true, param_type: "body" }
|
136
134
|
end
|
137
135
|
post "/" do
|
136
|
+
status 201
|
137
|
+
|
138
138
|
result = AlertCreator.result(params)
|
139
|
-
if result.success?
|
140
|
-
status 201
|
141
|
-
return present(result.value!, with: Entities::Alert)
|
142
|
-
end
|
139
|
+
return present(result.value!, with: Entities::Alert) if result.success?
|
143
140
|
|
144
|
-
|
145
|
-
case failure
|
141
|
+
case result.failure
|
146
142
|
when ActiveRecord::RecordNotFound
|
147
143
|
error!({ message: "Rule:#{params["ruleId"]} is not found" }, 404)
|
148
144
|
end
|
149
|
-
raise failure
|
145
|
+
raise result.failure
|
150
146
|
end
|
151
147
|
end
|
152
148
|
end
|
@@ -64,7 +64,7 @@ module Mihari
|
|
64
64
|
namespace :artifacts do
|
65
65
|
desc "Get an artifact", {
|
66
66
|
success: Entities::Artifact,
|
67
|
-
failure: [{ code: 404,
|
67
|
+
failure: [{ code: 404, model: Entities::Message }],
|
68
68
|
summary: "Get an artifact"
|
69
69
|
}
|
70
70
|
params do
|
@@ -75,60 +75,55 @@ module Mihari
|
|
75
75
|
result = ArtifactGetter.result(id)
|
76
76
|
return present(result.value!, with: Entities::Artifact) if result.success?
|
77
77
|
|
78
|
-
|
79
|
-
case failure
|
78
|
+
case result.failure
|
80
79
|
when ActiveRecord::RecordNotFound
|
81
80
|
error!({ message: "ID:#{id} is not found" }, 404)
|
82
81
|
end
|
83
|
-
raise failure
|
82
|
+
raise result.failure
|
84
83
|
end
|
85
84
|
|
86
85
|
desc "Enrich an artifact", {
|
87
|
-
success: Entities::Message,
|
88
|
-
failure: [{ code: 404,
|
86
|
+
success: { code: 201, model: Entities::Message },
|
87
|
+
failure: [{ code: 404, model: Entities::Message }],
|
89
88
|
summary: "Enrich an artifact"
|
90
89
|
}
|
91
90
|
params do
|
92
91
|
requires :id, type: Integer
|
93
92
|
end
|
94
93
|
get "/:id/enrich" do
|
94
|
+
status 201
|
95
|
+
|
95
96
|
id = params["id"].to_i
|
96
97
|
result = ArtifactEnricher.result(id)
|
97
|
-
if result.success?
|
98
|
-
status 201
|
99
|
-
return present({ message: "" }, with: Entities::Message)
|
100
|
-
end
|
98
|
+
return present({ message: "#{id} has been enriched" }, with: Entities::Message) if result.success?
|
101
99
|
|
102
|
-
|
103
|
-
case failure
|
100
|
+
case result.failure
|
104
101
|
when ActiveRecord::RecordNotFound
|
105
102
|
error!({ message: "ID:#{id} is not found" }, 404)
|
106
103
|
end
|
107
|
-
raise failure
|
104
|
+
raise result.failure
|
108
105
|
end
|
109
106
|
|
110
107
|
desc "Delete an artifact", {
|
111
|
-
success: Entities::Message,
|
112
|
-
failure: [{ code: 404,
|
108
|
+
success: { code: 204, model: Entities::Message },
|
109
|
+
failure: [{ code: 404, model: Entities::Message }],
|
113
110
|
summary: "Delete an artifact"
|
114
111
|
}
|
115
112
|
params do
|
116
113
|
requires :id, type: Integer
|
117
114
|
end
|
118
115
|
delete "/:id" do
|
116
|
+
status 204
|
117
|
+
|
119
118
|
id = params["id"].to_i
|
120
119
|
result = ArtifactDestroyer.result(id)
|
121
|
-
if result.success?
|
122
|
-
status 204
|
123
|
-
return present({ message: "" }, with: Entities::Message)
|
124
|
-
end
|
120
|
+
return present({ message: "" }, with: Entities::Message) if result.success?
|
125
121
|
|
126
|
-
|
127
|
-
case failure
|
122
|
+
case result.failure
|
128
123
|
when ActiveRecord::RecordNotFound
|
129
124
|
error!({ message: "ID:#{id} is not found" }, 404)
|
130
125
|
end
|
131
|
-
raise failure
|
126
|
+
raise result.failure
|
132
127
|
end
|
133
128
|
end
|
134
129
|
end
|
@@ -21,7 +21,7 @@ module Mihari
|
|
21
21
|
namespace :ip_addresses do
|
22
22
|
desc "Get an IP address", {
|
23
23
|
success: Entities::IPAddress,
|
24
|
-
failure: [{ code: 404,
|
24
|
+
failure: [{ code: 404, model: Entities::Message }],
|
25
25
|
summary: "Get an IP address"
|
26
26
|
}
|
27
27
|
params do
|
@@ -128,7 +128,6 @@ module Mihari
|
|
128
128
|
desc "Search rules", {
|
129
129
|
is_array: true,
|
130
130
|
success: Entities::RulesWithPagination,
|
131
|
-
failure: [{ code: 404, message: "Not found", model: Entities::Message }],
|
132
131
|
summary: "Search rules"
|
133
132
|
}
|
134
133
|
params do
|
@@ -153,7 +152,7 @@ module Mihari
|
|
153
152
|
|
154
153
|
desc "Get a rule", {
|
155
154
|
success: Entities::Rule,
|
156
|
-
failure: [{ code: 404,
|
155
|
+
failure: [{ code: 404, model: Entities::Message }],
|
157
156
|
summary: "Get a rule"
|
158
157
|
}
|
159
158
|
params do
|
@@ -164,50 +163,48 @@ module Mihari
|
|
164
163
|
result = RuleGetter.result(params[:id].to_s)
|
165
164
|
return present(result.value!, with: Entities::Rule) if result.success?
|
166
165
|
|
167
|
-
|
168
|
-
case failure
|
166
|
+
case result.failure
|
169
167
|
when ActiveRecord::RecordNotFound
|
170
168
|
error!({ message: "ID:#{id} is not found" }, 404)
|
171
169
|
end
|
172
|
-
raise failure
|
170
|
+
raise result.failure
|
173
171
|
end
|
174
172
|
|
175
173
|
desc "Run a rule", {
|
176
|
-
success: Entities::Message,
|
174
|
+
success: { code: 201, model: Entities::Message },
|
175
|
+
failure: [{ code: 404, model: Entities::Message }],
|
177
176
|
summary: "Run a rule"
|
178
177
|
}
|
179
178
|
params do
|
180
179
|
requires :id, type: String
|
181
180
|
end
|
182
181
|
get "/:id/run" do
|
182
|
+
status 201
|
183
|
+
|
183
184
|
id = params[:id].to_s
|
184
185
|
result = RuleRunner.result(id)
|
185
|
-
if result.success?
|
186
|
-
status 201
|
187
|
-
return present({ message: "ID:#{id}} ran successfully" }, with: Entities::Message)
|
188
|
-
end
|
186
|
+
return present({ message: "ID:#{id}} has been ran" }, with: Entities::Message) if result.success?
|
189
187
|
|
190
|
-
|
191
|
-
case failure
|
188
|
+
case result.failure
|
192
189
|
when ActiveRecord::RecordNotFound
|
193
190
|
error!({ message: "ID:#{id} is not found" }, 404)
|
194
191
|
end
|
195
|
-
raise failure
|
192
|
+
raise result.failure
|
196
193
|
end
|
197
194
|
|
198
195
|
desc "Create a rule", {
|
199
|
-
success: Entities::Rule,
|
196
|
+
success: { code: 201, model: Entities::Rule },
|
197
|
+
failure: [{ code: 404, model: Entities::Message }],
|
200
198
|
summary: "Create a rule"
|
201
199
|
}
|
202
200
|
params do
|
203
201
|
requires :yaml, type: String, documentation: { param_type: "body" }
|
204
202
|
end
|
205
203
|
post "/" do
|
204
|
+
status 201
|
205
|
+
|
206
206
|
result = RuleCreator.result(params[:yaml])
|
207
|
-
if result.success?
|
208
|
-
status 201
|
209
|
-
return present(result.value!.model, with: Entities::Rule)
|
210
|
-
end
|
207
|
+
return present(result.value!.model, with: Entities::Rule) if result.success?
|
211
208
|
|
212
209
|
failure = result.failure
|
213
210
|
case failure
|
@@ -220,7 +217,8 @@ module Mihari
|
|
220
217
|
end
|
221
218
|
|
222
219
|
desc "Update a rule", {
|
223
|
-
success: Entities::Rule,
|
220
|
+
success: { code: 201, model: Entities::Rule },
|
221
|
+
failure: [{ code: 404, model: Entities::Message }],
|
224
222
|
summary: "Update a rule"
|
225
223
|
}
|
226
224
|
params do
|
@@ -228,12 +226,11 @@ module Mihari
|
|
228
226
|
requires :yaml, type: String, documentation: { param_type: "body" }
|
229
227
|
end
|
230
228
|
put "/" do
|
229
|
+
status 201
|
230
|
+
|
231
231
|
id = params[:id].to_s
|
232
232
|
result = RuleUpdater.result(id: id, yaml: params[:yaml].to_s)
|
233
|
-
if result.success?
|
234
|
-
status 201
|
235
|
-
return present(result.value!.model, with: Entities::Rule)
|
236
|
-
end
|
233
|
+
return present(result.value!.model, with: Entities::Rule) if result.success?
|
237
234
|
|
238
235
|
failure = result.failure
|
239
236
|
case failure
|
@@ -248,27 +245,25 @@ module Mihari
|
|
248
245
|
end
|
249
246
|
|
250
247
|
desc "Delete a rule", {
|
251
|
-
success: Entities::Message,
|
252
|
-
failure: [{ code: 404,
|
248
|
+
success: { code: 204, model: Entities::Message },
|
249
|
+
failure: [{ code: 404, model: Entities::Message }],
|
253
250
|
summary: "Delete a rule"
|
254
251
|
}
|
255
252
|
params do
|
256
253
|
requires :id, type: String
|
257
254
|
end
|
258
255
|
delete "/:id" do
|
256
|
+
status 204
|
257
|
+
|
259
258
|
id = params[:id].to_s
|
260
259
|
result = RuleDestroyer.result(id)
|
261
|
-
if result.success?
|
262
|
-
status 204
|
263
|
-
return present({ message: "ID:#{id} is deleted" }, with: Entities::Message)
|
264
|
-
end
|
260
|
+
return present({ message: "ID:#{id} is deleted" }, with: Entities::Message) if result.success?
|
265
261
|
|
266
|
-
|
267
|
-
case failure
|
262
|
+
case result.failure
|
268
263
|
when ActiveRecord::RecordNotFound
|
269
264
|
error!({ message: "ID:#{id} is not found" }, 404)
|
270
265
|
end
|
271
|
-
raise failure
|
266
|
+
raise result.failure
|
272
267
|
end
|
273
268
|
end
|
274
269
|
end
|
@@ -28,27 +28,25 @@ module Mihari
|
|
28
28
|
end
|
29
29
|
|
30
30
|
desc "Delete a tag", {
|
31
|
-
success: Entities::Message,
|
32
|
-
failure: [{ code: 404,
|
31
|
+
success: { code: 204, model: Entities::Message },
|
32
|
+
failure: [{ code: 404, model: Entities::Message }],
|
33
33
|
summary: "Delete a tag"
|
34
34
|
}
|
35
35
|
params do
|
36
36
|
requires :id, type: Integer
|
37
37
|
end
|
38
38
|
delete "/:id" do
|
39
|
+
status 204
|
40
|
+
|
39
41
|
id = params[:id].to_i
|
40
42
|
result = TagDestroyer.result(id)
|
41
|
-
if result.success?
|
42
|
-
status 204
|
43
|
-
return present({ message: "" }, with: Entities::Message)
|
44
|
-
end
|
43
|
+
return present({ message: "" }, with: Entities::Message) if result.success?
|
45
44
|
|
46
|
-
|
47
|
-
case failure
|
45
|
+
case result.failure
|
48
46
|
when ActiveRecord::RecordNotFound
|
49
47
|
error!({ message: "ID:#{id} is not found" }, 404)
|
50
48
|
end
|
51
|
-
raise failure
|
49
|
+
raise result.failure
|
52
50
|
end
|
53
51
|
end
|
54
52
|
end
|
@@ -7,16 +7,14 @@ module Mihari
|
|
7
7
|
# DB connection adapter for Rack app
|
8
8
|
#
|
9
9
|
class ConnectionAdapter
|
10
|
+
attr_reader :app
|
11
|
+
|
10
12
|
def initialize(app)
|
11
13
|
@app = app
|
12
14
|
end
|
13
15
|
|
14
16
|
def call(env)
|
15
|
-
Mihari::Database.with_db_connection
|
16
|
-
status, headers, body = @app.call(env)
|
17
|
-
|
18
|
-
[status, headers, body]
|
19
|
-
end
|
17
|
+
Mihari::Database.with_db_connection { app.call env }
|
20
18
|
end
|
21
19
|
end
|
22
20
|
end
|
@@ -7,6 +7,10 @@ module Mihari
|
|
7
7
|
# Error notification adapter for Rack app
|
8
8
|
#
|
9
9
|
class ErrorNotificationAdapter
|
10
|
+
include Mihari::Mixins::UnwrapError
|
11
|
+
|
12
|
+
attr_reader :app
|
13
|
+
|
10
14
|
def initialize(app)
|
11
15
|
@app = app
|
12
16
|
end
|
@@ -14,16 +18,16 @@ module Mihari
|
|
14
18
|
def with_error_notification
|
15
19
|
yield
|
16
20
|
rescue StandardError => e
|
17
|
-
|
21
|
+
unwrapped = unwrap_error(e)
|
22
|
+
|
23
|
+
Mihari.logger.error unwrapped
|
24
|
+
Sentry.capture_exception(unwrapped) if Sentry.initialized?
|
18
25
|
|
19
|
-
|
26
|
+
raise unwrapped
|
20
27
|
end
|
21
28
|
|
22
29
|
def call(env)
|
23
|
-
with_error_notification
|
24
|
-
status, headers, body = @app.call(env)
|
25
|
-
[status, headers, body]
|
26
|
-
end
|
30
|
+
with_error_notification { app.call(env) }
|
27
31
|
end
|
28
32
|
end
|
29
33
|
end
|