mihari 5.5.0 → 5.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/docs/analyzers/passivetotal.md +4 -0
- data/docs/analyzers/securitytrails.md +4 -0
- data/docs/analyzers/virustotal.md +4 -0
- data/docs/analyzers/virustotal_intelligence.md +4 -0
- data/docs/emitters/hive.md +1 -1
- data/docs/emitters/slack.md +0 -5
- data/docs/rule.md +1 -4
- data/docs/usage.md +5 -2
- data/frontend/src/components/ErrorMessage.vue +0 -1
- data/frontend/src/components/alert/Alerts.vue +0 -1
- data/frontend/src/components/alert/AlertsWithPagination.vue +0 -1
- data/frontend/src/components/alert/AlertsWrapper.vue +0 -6
- data/frontend/src/components/alert/Form.vue +1 -3
- data/frontend/src/components/artifact/Artifact.vue +0 -17
- data/frontend/src/components/artifact/ArtifactWrapper.vue +0 -2
- data/frontend/src/components/artifact/WhoisRecord.vue +0 -3
- data/frontend/src/components/config/ConfigsWrapper.vue +0 -2
- data/frontend/src/components/rule/EditRule.vue +0 -3
- data/frontend/src/components/rule/EditRuleWrapper.vue +0 -2
- data/frontend/src/components/rule/Form.vue +1 -3
- data/frontend/src/components/rule/NewRule.vue +0 -3
- data/frontend/src/components/rule/Rule.vue +1 -7
- data/frontend/src/components/rule/RuleWrapper.vue +0 -2
- data/frontend/src/components/rule/RulesWrapper.vue +0 -6
- data/frontend/src/swagger.yaml +254 -254
- data/lib/mihari/analyzers/base.rb +4 -41
- data/lib/mihari/analyzers/passivetotal.rb +9 -0
- data/lib/mihari/analyzers/pulsedive.rb +1 -1
- data/lib/mihari/analyzers/rule.rb +24 -59
- data/lib/mihari/analyzers/securitytrails.rb +9 -0
- data/lib/mihari/analyzers/virustotal.rb +11 -2
- data/lib/mihari/analyzers/virustotal_intelligence.rb +16 -0
- data/lib/mihari/analyzers/zoomeye.rb +2 -2
- data/lib/mihari/base.rb +69 -0
- data/lib/mihari/cli/main.rb +36 -0
- data/lib/mihari/commands/alert.rb +6 -33
- data/lib/mihari/commands/rule.rb +7 -12
- data/lib/mihari/commands/search.rb +10 -38
- data/lib/mihari/constants.rb +3 -3
- data/lib/mihari/emitters/base.rb +3 -33
- data/lib/mihari/emitters/database.rb +1 -1
- data/lib/mihari/enrichers/base.rb +2 -33
- data/lib/mihari/enrichers/google_public_dns.rb +9 -0
- data/lib/mihari/schemas/analyzer.rb +24 -24
- data/lib/mihari/schemas/emitter.rb +6 -13
- data/lib/mihari/schemas/enricher.rb +4 -11
- data/lib/mihari/schemas/options.rb +27 -0
- data/lib/mihari/schemas/rule.rb +2 -2
- data/lib/mihari/services/alert_runner.rb +1 -1
- data/lib/mihari/services/rule_runner.rb +1 -11
- data/lib/mihari/types.rb +1 -14
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/public/assets/{index-33165282.css → index-56fc2187.css} +1 -1
- data/lib/mihari/web/public/assets/{index-b5d817a3.js → index-9cc489e6.js} +2 -2
- data/lib/mihari/web/public/index.html +2 -2
- data/lib/mihari.rb +67 -37
- data/mihari.gemspec +1 -0
- metadata +20 -4
data/lib/mihari/emitters/base.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Mihari
|
4
4
|
module Emitters
|
5
|
-
class Base
|
5
|
+
class Base < Mihari::Base
|
6
6
|
include Dry::Monads[:result, :try]
|
7
7
|
|
8
8
|
include Mixins::Configurable
|
@@ -14,9 +14,6 @@ module Mihari
|
|
14
14
|
# @return [Mihari::Services::Rule]
|
15
15
|
attr_reader :rule
|
16
16
|
|
17
|
-
# @return [Hash]
|
18
|
-
attr_reader :options
|
19
|
-
|
20
17
|
#
|
21
18
|
# @param [Array<Mihari::Artifact>] artifacts
|
22
19
|
# @param [Mihari::Services::RuleProxy] rule
|
@@ -24,37 +21,10 @@ module Mihari
|
|
24
21
|
# @param [Hash] **_params
|
25
22
|
#
|
26
23
|
def initialize(artifacts:, rule:, options: nil, **_params)
|
24
|
+
super(options: options)
|
25
|
+
|
27
26
|
@artifacts = artifacts
|
28
27
|
@rule = rule
|
29
|
-
@options = options || {}
|
30
|
-
end
|
31
|
-
|
32
|
-
#
|
33
|
-
# @return [Integer]
|
34
|
-
#
|
35
|
-
def retry_interval
|
36
|
-
options[:retry_interval] || Mihari.config.retry_interval
|
37
|
-
end
|
38
|
-
|
39
|
-
#
|
40
|
-
# @return [Boolean]
|
41
|
-
#
|
42
|
-
def retry_exponential_backoff
|
43
|
-
options[:retry_exponential_backoff] || Mihari.config.retry_exponential_backoff
|
44
|
-
end
|
45
|
-
|
46
|
-
#
|
47
|
-
# @return [Integer]
|
48
|
-
#
|
49
|
-
def retry_times
|
50
|
-
options[:retry_times] || Mihari.config.retry_times
|
51
|
-
end
|
52
|
-
|
53
|
-
#
|
54
|
-
# @return [Integer, nil]
|
55
|
-
#
|
56
|
-
def timeout
|
57
|
-
options[:timeout]
|
58
28
|
end
|
59
29
|
|
60
30
|
# @return [Boolean]
|
@@ -13,7 +13,7 @@ module Mihari
|
|
13
13
|
# @return [Mihari::Alert, nil]
|
14
14
|
#
|
15
15
|
def emit
|
16
|
-
return
|
16
|
+
return if artifacts.empty?
|
17
17
|
|
18
18
|
tags = rule.tags.filter_map { |name| Tag.find_or_create_by(name: name) }.uniq
|
19
19
|
taggings = tags.map { |tag| Tagging.new(tag_id: tag.id) }
|
@@ -2,45 +2,14 @@
|
|
2
2
|
|
3
3
|
module Mihari
|
4
4
|
module Enrichers
|
5
|
-
class Base
|
5
|
+
class Base < Mihari::Base
|
6
6
|
include Mixins::Configurable
|
7
7
|
include Mixins::Retriable
|
8
8
|
|
9
9
|
include Dry::Monads[:result, :try]
|
10
10
|
|
11
|
-
# @return [Hash]
|
12
|
-
attr_reader :options
|
13
|
-
|
14
11
|
def initialize(options: nil)
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
#
|
19
|
-
# @return [Integer]
|
20
|
-
#
|
21
|
-
def retry_interval
|
22
|
-
options[:retry_interval] || Mihari.config.retry_interval
|
23
|
-
end
|
24
|
-
|
25
|
-
#
|
26
|
-
# @return [Boolean]
|
27
|
-
#
|
28
|
-
def retry_exponential_backoff
|
29
|
-
options[:retry_exponential_backoff] || Mihari.config.retry_exponential_backoff
|
30
|
-
end
|
31
|
-
|
32
|
-
#
|
33
|
-
# @return [Integer]
|
34
|
-
#
|
35
|
-
def retry_times
|
36
|
-
options[:retry_times] || Mihari.config.retry_times
|
37
|
-
end
|
38
|
-
|
39
|
-
#
|
40
|
-
# @return [Integer, nil]
|
41
|
-
#
|
42
|
-
def timeout
|
43
|
-
options[:timeout]
|
12
|
+
super(options: options)
|
44
13
|
end
|
45
14
|
|
46
15
|
def query_result(value)
|
@@ -2,37 +2,31 @@
|
|
2
2
|
|
3
3
|
module Mihari
|
4
4
|
module Schemas
|
5
|
-
|
6
|
-
optional(:pagination_interval).value(:integer).default(Mihari.config.pagination_interval)
|
7
|
-
optional(:pagination_limit).value(:integer).default(Mihari.config.pagination_limit)
|
8
|
-
optional(:retry_times).value(:integer).default(Mihari.config.retry_times)
|
9
|
-
optional(:retry_interval).value(:integer).default(Mihari.config.retry_interval)
|
10
|
-
optional(:retry_exponential_backoff).value(:bool).default(Mihari.config.retry_exponential_backoff)
|
11
|
-
optional(:ignore_error).value(:bool).default(Mihari.config.ignore_error)
|
12
|
-
optional(:timeout).value(:integer)
|
13
|
-
end
|
14
|
-
|
15
|
-
AnalyzerWithoutAPIKey = Dry::Schema.Params do
|
16
|
-
required(:analyzer).value(Types::String.enum("dnstwister"))
|
17
|
-
required(:query).value(:string)
|
18
|
-
optional(:options).hash(AnalyzerOptions)
|
19
|
-
end
|
20
|
-
|
21
|
-
AnalyzerWithAPIKey = Dry::Schema.Params do
|
5
|
+
AnalyzerAPIKeyPagination = Dry::Schema.Params do
|
22
6
|
required(:analyzer).value(
|
23
7
|
Types::String.enum(
|
24
8
|
"binaryedge",
|
25
9
|
"greynoise",
|
26
10
|
"onyphe",
|
11
|
+
"shodan",
|
12
|
+
"urlscan",
|
13
|
+
"virustotal_intelligence",
|
14
|
+
"vt_intel"
|
15
|
+
)
|
16
|
+
)
|
17
|
+
required(:query).value(:string)
|
18
|
+
optional(:api_key).value(:string)
|
19
|
+
optional(:options).hash(AnalyzerPaginationOptions)
|
20
|
+
end
|
21
|
+
|
22
|
+
AnalyzerAPIKey = Dry::Schema.Params do
|
23
|
+
required(:analyzer).value(
|
24
|
+
Types::String.enum(
|
27
25
|
"otx",
|
28
26
|
"pulsedive",
|
29
27
|
"securitytrails",
|
30
|
-
"shodan",
|
31
28
|
"st",
|
32
|
-
"urlscan",
|
33
|
-
"virustotal_intelligence",
|
34
29
|
"virustotal",
|
35
|
-
"vt_intel",
|
36
30
|
"vt"
|
37
31
|
)
|
38
32
|
)
|
@@ -41,12 +35,18 @@ module Mihari
|
|
41
35
|
optional(:options).hash(AnalyzerOptions)
|
42
36
|
end
|
43
37
|
|
38
|
+
DNSTwister = Dry::Schema.Params do
|
39
|
+
required(:analyzer).value(Types::String.enum("dnstwister"))
|
40
|
+
required(:query).value(:string)
|
41
|
+
optional(:options).hash(AnalyzerOptions)
|
42
|
+
end
|
43
|
+
|
44
44
|
Censys = Dry::Schema.Params do
|
45
45
|
required(:analyzer).value(Types::String.enum("censys"))
|
46
46
|
required(:query).value(:string)
|
47
47
|
optional(:id).value(:string)
|
48
48
|
optional(:secret).value(:string)
|
49
|
-
optional(:options).hash(
|
49
|
+
optional(:options).hash(AnalyzerPaginationOptions)
|
50
50
|
end
|
51
51
|
|
52
52
|
CIRCL = Dry::Schema.Params do
|
@@ -69,7 +69,7 @@ module Mihari
|
|
69
69
|
required(:analyzer).value(Types::String.enum("zoomeye"))
|
70
70
|
required(:query).value(:string)
|
71
71
|
required(:type).value(Types::String.enum("host", "web"))
|
72
|
-
optional(:options).hash(
|
72
|
+
optional(:options).hash(AnalyzerPaginationOptions)
|
73
73
|
end
|
74
74
|
|
75
75
|
Crtsh = Dry::Schema.Params do
|
@@ -85,7 +85,7 @@ module Mihari
|
|
85
85
|
required(:start_time).value(:date)
|
86
86
|
required(:end_time).value(:date)
|
87
87
|
optional(:api_key).value(:string)
|
88
|
-
optional(:options).hash(
|
88
|
+
optional(:options).hash(AnalyzerPaginationOptions)
|
89
89
|
end
|
90
90
|
|
91
91
|
Feed = Dry::Schema.Params do
|
@@ -3,38 +3,31 @@
|
|
3
3
|
module Mihari
|
4
4
|
module Schemas
|
5
5
|
module Emitters
|
6
|
-
EmitterOptions = Dry::Schema.Params do
|
7
|
-
optional(:retry_times).value(:integer).default(Mihari.config.retry_times)
|
8
|
-
optional(:retry_interval).value(:integer).default(Mihari.config.retry_interval)
|
9
|
-
optional(:retry_exponential_backoff).value(:bool).default(Mihari.config.retry_exponential_backoff)
|
10
|
-
optional(:timeout).value(:integer)
|
11
|
-
end
|
12
|
-
|
13
6
|
Database = Dry::Schema.Params do
|
14
7
|
required(:emitter).value(Types::String.enum("database"))
|
15
|
-
optional(:options).hash(
|
8
|
+
optional(:options).hash(Options)
|
16
9
|
end
|
17
10
|
|
18
11
|
MISP = Dry::Schema.Params do
|
19
12
|
required(:emitter).value(Types::String.enum("misp"))
|
20
13
|
optional(:url).value(:string)
|
21
14
|
optional(:api_key).value(:string)
|
22
|
-
optional(:options).hash(
|
15
|
+
optional(:options).hash(Options)
|
23
16
|
end
|
24
17
|
|
25
18
|
TheHive = Dry::Schema.Params do
|
26
|
-
required(:emitter).value(Types::String.enum("
|
19
|
+
required(:emitter).value(Types::String.enum("thehive"))
|
27
20
|
optional(:url).value(:string)
|
28
21
|
optional(:api_key).value(:string)
|
29
22
|
optional(:api_version).value(Types::String.enum("v4", "v5")).default("v4")
|
30
|
-
optional(:options).hash(
|
23
|
+
optional(:options).hash(Options)
|
31
24
|
end
|
32
25
|
|
33
26
|
Slack = Dry::Schema.Params do
|
34
27
|
required(:emitter).value(Types::String.enum("slack"))
|
35
28
|
optional(:webhook_url).value(:string)
|
36
29
|
optional(:channel).value(:string)
|
37
|
-
optional(:options).hash(
|
30
|
+
optional(:options).hash(Options)
|
38
31
|
end
|
39
32
|
|
40
33
|
Webhook = Dry::Schema.Params do
|
@@ -43,7 +36,7 @@ module Mihari
|
|
43
36
|
optional(:method).value(Types::HTTPRequestMethods).default("POST")
|
44
37
|
optional(:headers).value(:hash).default({})
|
45
38
|
optional(:template).value(:string)
|
46
|
-
optional(:options).hash(
|
39
|
+
optional(:options).hash(Options)
|
47
40
|
end
|
48
41
|
end
|
49
42
|
end
|
@@ -3,32 +3,25 @@
|
|
3
3
|
module Mihari
|
4
4
|
module Schemas
|
5
5
|
module Enrichers
|
6
|
-
EnricherOptions = Dry::Schema.Params do
|
7
|
-
optional(:retry_times).value(:integer).default(Mihari.config.retry_times)
|
8
|
-
optional(:retry_interval).value(:integer).default(Mihari.config.retry_interval)
|
9
|
-
optional(:retry_exponential_backoff).value(:bool).default(Mihari.config.retry_exponential_backoff)
|
10
|
-
optional(:timeout).value(:integer)
|
11
|
-
end
|
12
|
-
|
13
6
|
IPInfo = Dry::Schema.Params do
|
14
7
|
required(:enricher).value(Types::String.enum("ipinfo"))
|
15
8
|
optional(:api_key).value(:string)
|
16
|
-
optional(:options).hash(
|
9
|
+
optional(:options).hash(Options)
|
17
10
|
end
|
18
11
|
|
19
12
|
Whois = Dry::Schema.Params do
|
20
13
|
required(:enricher).value(Types::String.enum("whois"))
|
21
|
-
optional(:options).hash(
|
14
|
+
optional(:options).hash(Options)
|
22
15
|
end
|
23
16
|
|
24
17
|
Shodan = Dry::Schema.Params do
|
25
18
|
required(:enricher).value(Types::String.enum("shodan"))
|
26
|
-
optional(:options).hash(
|
19
|
+
optional(:options).hash(Options)
|
27
20
|
end
|
28
21
|
|
29
22
|
GooglePublicDNS = Dry::Schema.Params do
|
30
23
|
required(:enricher).value(Types::String.enum("google_public_dns"))
|
31
|
-
optional(:options).hash(
|
24
|
+
optional(:options).hash(Options)
|
32
25
|
end
|
33
26
|
end
|
34
27
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/schema"
|
4
|
+
|
5
|
+
module Mihari
|
6
|
+
module Schemas
|
7
|
+
Options = Dry::Schema.Params do
|
8
|
+
optional(:retry_times).value(:integer).default(Mihari.config.retry_times)
|
9
|
+
optional(:retry_interval).value(:integer).default(Mihari.config.retry_interval)
|
10
|
+
optional(:retry_exponential_backoff).value(:bool).default(Mihari.config.retry_exponential_backoff)
|
11
|
+
optional(:timeout).value(:integer)
|
12
|
+
end
|
13
|
+
|
14
|
+
IgnoreErrorOptions = Dry::Schema.Params do
|
15
|
+
optional(:ignore_error).value(:bool).default(Mihari.config.ignore_error)
|
16
|
+
end
|
17
|
+
|
18
|
+
AnalyzerOptions = Options | IgnoreErrorOptions
|
19
|
+
|
20
|
+
PaginationOptions = Dry::Schema.Params do
|
21
|
+
optional(:pagination_interval).value(:integer).default(Mihari.config.pagination_interval)
|
22
|
+
optional(:pagination_limit).value(:integer).default(Mihari.config.pagination_limit)
|
23
|
+
end
|
24
|
+
|
25
|
+
AnalyzerPaginationOptions = AnalyzerOptions | PaginationOptions
|
26
|
+
end
|
27
|
+
end
|
data/lib/mihari/schemas/rule.rb
CHANGED
@@ -22,7 +22,7 @@ module Mihari
|
|
22
22
|
optional(:updated_on).value(:date)
|
23
23
|
|
24
24
|
required(:queries).value(:array).each do
|
25
|
-
|
25
|
+
AnalyzerAPIKey | AnalyzerAPIKeyPagination | Censys | CIRCL | PassiveTotal | ZoomEye | Crtsh | Feed | HunterHow | DNSTwister
|
26
26
|
end
|
27
27
|
|
28
28
|
optional(:emitters).value(:array).each do
|
@@ -33,7 +33,7 @@ module Mihari
|
|
33
33
|
Enrichers::Whois | Enrichers::IPInfo | Enrichers::Shodan | Enrichers::GooglePublicDNS
|
34
34
|
end.default(DEFAULT_ENRICHERS)
|
35
35
|
|
36
|
-
optional(:data_types).value(array[Types::DataTypes]).default(
|
36
|
+
optional(:data_types).value(array[Types::DataTypes]).default(Mihari::Types::DataTypes.values)
|
37
37
|
optional(:falsepositives).value(array[:string]).default([])
|
38
38
|
|
39
39
|
optional(:artifact_lifetime).value(:integer)
|
@@ -5,21 +5,11 @@ module Mihari
|
|
5
5
|
class RuleRunner
|
6
6
|
include Dry::Monads[:result, :try]
|
7
7
|
|
8
|
-
include Mixins::ErrorNotification
|
9
|
-
|
10
8
|
# @return [Mihari::Services::RuleProxy]
|
11
9
|
attr_reader :rule
|
12
10
|
|
13
|
-
|
14
|
-
attr_reader :force_overwrite
|
15
|
-
|
16
|
-
def initialize(rule, force_overwrite:)
|
11
|
+
def initialize(rule)
|
17
12
|
@rule = rule
|
18
|
-
@force_overwrite = force_overwrite
|
19
|
-
end
|
20
|
-
|
21
|
-
def force_overwrite?
|
22
|
-
force_overwrite
|
23
13
|
end
|
24
14
|
|
25
15
|
#
|
data/lib/mihari/types.rb
CHANGED
@@ -12,21 +12,8 @@ module Mihari
|
|
12
12
|
Double = Strict::Float | Strict::Integer
|
13
13
|
DateTime = Strict::DateTime
|
14
14
|
|
15
|
-
DataTypes = Types::String.enum(
|
15
|
+
DataTypes = Types::String.enum("hash", "ip", "domain", "url", "mail")
|
16
16
|
|
17
17
|
HTTPRequestMethods = Types::String.enum("GET", "POST")
|
18
|
-
HTTPRequestPayloadTypes = Types::String.enum("application/json", "application/x-www-form-urlencoded")
|
19
|
-
|
20
|
-
EmitterTypes = Types::String.enum(
|
21
|
-
"database",
|
22
|
-
"webhook"
|
23
|
-
)
|
24
|
-
|
25
|
-
EnricherTypes = Types::String.enum(
|
26
|
-
"whois",
|
27
|
-
"ipinfo",
|
28
|
-
"shodan",
|
29
|
-
"google_public_dns"
|
30
|
-
)
|
31
18
|
end
|
32
19
|
end
|
data/lib/mihari/version.rb
CHANGED