mihari 3.12.0 → 4.0.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/lib/mihari/analyzers/base.rb +6 -6
- data/lib/mihari/analyzers/binaryedge.rb +3 -5
- data/lib/mihari/analyzers/censys.rb +1 -3
- data/lib/mihari/analyzers/circl.rb +0 -3
- data/lib/mihari/analyzers/crtsh.rb +7 -5
- data/lib/mihari/analyzers/dnpedia.rb +4 -4
- data/lib/mihari/analyzers/dnstwister.rb +1 -4
- data/lib/mihari/analyzers/feed.rb +0 -3
- data/lib/mihari/analyzers/greynoise.rb +1 -3
- data/lib/mihari/analyzers/onyphe.rb +1 -3
- data/lib/mihari/analyzers/otx.rb +0 -3
- data/lib/mihari/analyzers/passivetotal.rb +8 -9
- data/lib/mihari/analyzers/pulsedive.rb +7 -5
- data/lib/mihari/analyzers/rule.rb +5 -6
- data/lib/mihari/analyzers/securitytrails.rb +10 -7
- data/lib/mihari/analyzers/shodan.rb +2 -4
- data/lib/mihari/analyzers/spyse.rb +10 -11
- data/lib/mihari/analyzers/urlscan.rb +5 -6
- data/lib/mihari/analyzers/virustotal.rb +8 -9
- data/lib/mihari/analyzers/virustotal_intelligence.rb +4 -5
- data/lib/mihari/analyzers/zoomeye.rb +4 -5
- data/lib/mihari/cli/base.rb +0 -5
- data/lib/mihari/cli/init.rb +0 -2
- data/lib/mihari/cli/main.rb +4 -6
- data/lib/mihari/cli/mixins/utils.rb +2 -18
- data/lib/mihari/commands/init.rb +0 -18
- data/lib/mihari/commands/search.rb +20 -15
- data/lib/mihari/commands/validator.rb +7 -19
- data/lib/mihari/commands/web.rb +0 -3
- data/lib/mihari/database.rb +67 -15
- data/lib/mihari/emitters/misp.rb +0 -1
- data/lib/mihari/emitters/slack.rb +3 -4
- data/lib/mihari/emitters/stdout.rb +0 -2
- data/lib/mihari/emitters/the_hive.rb +0 -1
- data/lib/mihari/emitters/webhook.rb +1 -5
- data/lib/mihari/enrichers/ipinfo.rb +0 -2
- data/lib/mihari/errors.rb +2 -0
- data/lib/mihari/feed/reader.rb +22 -8
- data/lib/mihari/mixins/database.rb +14 -0
- data/lib/mihari/mixins/disallowed_data_value.rb +1 -4
- data/lib/mihari/mixins/rule.rb +34 -31
- data/lib/mihari/models/alert.rb +3 -3
- data/lib/mihari/models/artifact.rb +0 -5
- data/lib/mihari/models/autonomous_system.rb +0 -2
- data/lib/mihari/models/dns.rb +0 -3
- data/lib/mihari/models/geolocation.rb +0 -1
- data/lib/mihari/models/reverse_dns.rb +0 -3
- data/lib/mihari/models/rule.rb +73 -0
- data/lib/mihari/models/tag.rb +0 -2
- data/lib/mihari/models/tagging.rb +0 -2
- data/lib/mihari/models/whois.rb +0 -2
- data/lib/mihari/notifiers/exception_notifier.rb +0 -2
- data/lib/mihari/schemas/analyzer.rb +0 -5
- data/lib/mihari/schemas/macros.rb +0 -2
- data/lib/mihari/schemas/rule.rb +0 -5
- data/lib/mihari/structs/alert.rb +0 -3
- data/lib/mihari/structs/censys.rb +3 -4
- data/lib/mihari/structs/greynoise.rb +3 -4
- data/lib/mihari/structs/ipinfo.rb +0 -3
- data/lib/mihari/structs/onyphe.rb +5 -6
- data/lib/mihari/structs/rule.rb +121 -0
- data/lib/mihari/structs/shodan.rb +3 -4
- data/lib/mihari/structs/urlscan.rb +0 -3
- data/lib/mihari/structs/virustotal_intelligence.rb +3 -4
- data/lib/mihari/type_checker.rb +2 -6
- data/lib/mihari/types.rb +0 -2
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/api.rb +4 -0
- data/lib/mihari/web/app.rb +5 -7
- data/lib/mihari/web/endpoints/alerts.rb +7 -3
- data/lib/mihari/web/endpoints/artifacts.rb +6 -3
- data/lib/mihari/web/endpoints/command.rb +2 -1
- data/lib/mihari/web/endpoints/configs.rb +2 -1
- data/lib/mihari/web/endpoints/ip_addresses.rb +2 -1
- data/lib/mihari/web/endpoints/rules.rb +140 -0
- data/lib/mihari/web/endpoints/sources.rb +2 -1
- data/lib/mihari/web/endpoints/tags.rb +4 -2
- data/lib/mihari/web/entities/artifact.rb +2 -0
- data/lib/mihari/web/entities/rule.rb +35 -0
- data/lib/mihari/web/middleware/connection_adapter.rb +19 -0
- data/lib/mihari/web/public/index.html +1 -1
- data/lib/mihari/web/public/redoc-static.html +35 -21
- data/lib/mihari/web/public/static/js/app.49ab738a.js +21 -0
- data/lib/mihari/web/public/static/js/app.49ab738a.js.map +1 -0
- data/lib/mihari.rb +40 -34
- data/mihari.gemspec +3 -5
- data/sig/lib/mihari/analyzers/binaryedge.rbs +0 -3
- data/sig/lib/mihari/analyzers/censys.rbs +0 -3
- data/sig/lib/mihari/analyzers/circl.rbs +1 -3
- data/sig/lib/mihari/analyzers/crtsh.rbs +1 -3
- data/sig/lib/mihari/analyzers/dnpedia.rbs +1 -4
- data/sig/lib/mihari/analyzers/dnstwister.rbs +1 -3
- data/sig/lib/mihari/analyzers/feed.rbs +0 -3
- data/sig/lib/mihari/analyzers/onyphe.rbs +0 -3
- data/sig/lib/mihari/analyzers/otx.rbs +1 -3
- data/sig/lib/mihari/analyzers/passivetotal.rbs +3 -5
- data/sig/lib/mihari/analyzers/pulsedive.rbs +2 -4
- data/sig/lib/mihari/analyzers/securitytrails.rbs +3 -5
- data/sig/lib/mihari/analyzers/shodan.rbs +0 -3
- data/sig/lib/mihari/analyzers/spyse.rbs +4 -6
- data/sig/lib/mihari/analyzers/urlscan.rbs +1 -3
- data/sig/lib/mihari/analyzers/virustotal.rbs +4 -6
- data/sig/lib/mihari/analyzers/virustotal_intelligence.rbs +0 -3
- data/sig/lib/mihari/analyzers/zoomeye.rbs +2 -4
- data/sig/lib/mihari/commands/init.rbs +0 -2
- data/sig/lib/mihari/commands/validator.rbs +0 -2
- data/sig/lib/mihari/emitters/slack.rbs +0 -1
- data/sig/lib/mihari/feed/reader.rbs +1 -1
- data/sig/lib/mihari/mixins/disallowed_data_value.rbs +0 -2
- data/sig/lib/mihari/mixins/rule.rbs +5 -12
- data/sig/lib/mihari/models/alert.rbs +1 -1
- data/sig/lib/mihari/models/artifact.rbs +2 -0
- data/sig/lib/mihari/models/rule.rbs +14 -0
- data/sig/lib/mihari/structs/rule.rbs +56 -0
- data/sig/lib/mihari.rbs +0 -2
- metadata +18 -79
- data/lib/mihari/cli/analyzer.rb +0 -55
- data/lib/mihari/commands/binaryedge.rb +0 -21
- data/lib/mihari/commands/censys.rb +0 -22
- data/lib/mihari/commands/circl.rb +0 -21
- data/lib/mihari/commands/crtsh.rb +0 -22
- data/lib/mihari/commands/dnpedia.rb +0 -21
- data/lib/mihari/commands/dnstwister.rb +0 -21
- data/lib/mihari/commands/feed.rb +0 -26
- data/lib/mihari/commands/greynoise.rb +0 -21
- data/lib/mihari/commands/json.rb +0 -42
- data/lib/mihari/commands/onyphe.rb +0 -21
- data/lib/mihari/commands/otx.rb +0 -21
- data/lib/mihari/commands/passivetotal.rb +0 -22
- data/lib/mihari/commands/pulsedive.rb +0 -21
- data/lib/mihari/commands/securitytrails.rb +0 -22
- data/lib/mihari/commands/shodan.rb +0 -21
- data/lib/mihari/commands/spyse.rb +0 -22
- data/lib/mihari/commands/urlscan.rb +0 -22
- data/lib/mihari/commands/virustotal.rb +0 -22
- data/lib/mihari/commands/virustotal_intelligence.rb +0 -22
- data/lib/mihari/commands/zoomeye.rb +0 -22
- data/lib/mihari/mixins/configuration.rb +0 -100
- data/lib/mihari/mixins/hash.rb +0 -20
- data/lib/mihari/schemas/configuration.rb +0 -44
- data/lib/mihari/web/public/grape.rb +0 -73
- data/sig/lib/mihari/cli/analyzer.rbs +0 -43
- data/sig/lib/mihari/commands/binaryedge.rbs +0 -7
- data/sig/lib/mihari/commands/censys.rbs +0 -7
- data/sig/lib/mihari/commands/circl.rbs +0 -7
- data/sig/lib/mihari/commands/crtsh.rbs +0 -7
- data/sig/lib/mihari/commands/dnpedia.rbs +0 -7
- data/sig/lib/mihari/commands/dnstwister.rbs +0 -7
- data/sig/lib/mihari/commands/feed.rbs +0 -7
- data/sig/lib/mihari/commands/onyphe.rbs +0 -7
- data/sig/lib/mihari/commands/otx.rbs +0 -7
- data/sig/lib/mihari/commands/passivetotal.rbs +0 -7
- data/sig/lib/mihari/commands/pulsedive.rbs +0 -7
- data/sig/lib/mihari/commands/securitytrails.rbs +0 -7
- data/sig/lib/mihari/commands/shodan.rbs +0 -7
- data/sig/lib/mihari/commands/spyse.rbs +0 -7
- data/sig/lib/mihari/commands/urlscan.rbs +0 -7
- data/sig/lib/mihari/commands/virustotal.rbs +0 -7
- data/sig/lib/mihari/commands/zoomeye.rbs +0 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1a42a8897840d2f2268f88c6734c1633642256ef08667c39f45f5d03ac13874f
|
|
4
|
+
data.tar.gz: 89bdd5aa38f833e3158464915ec46c05e8c0bb6f17d34fe397d1590c59a57d7c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f62927fdb96eabffd99106bf03178e6eb573ee5e58b8fa2bb94b6b6b2ea898324fd65656bbb128aab67196ad03da959603dd73108c8840e883560d673c8afa5f
|
|
7
|
+
data.tar.gz: 2e752fa7ab93691ad6c38ec534af3bab14e27f2b66127dc00fc016f26554ea29fc2c743d2bdaef93d85e816d8a47e54d2d41bb6dafaabf711cfb2c833c3ff0ff
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "dry-initializer"
|
|
4
|
-
require "parallel"
|
|
5
|
-
|
|
6
3
|
module Mihari
|
|
7
4
|
module Analyzers
|
|
8
5
|
class Base
|
|
@@ -10,6 +7,7 @@ module Mihari
|
|
|
10
7
|
|
|
11
8
|
include Mixins::AutonomousSystem
|
|
12
9
|
include Mixins::Configurable
|
|
10
|
+
include Mixins::Database
|
|
13
11
|
include Mixins::Retriable
|
|
14
12
|
|
|
15
13
|
attr_accessor :ignore_old_artifacts, :ignore_threshold
|
|
@@ -52,10 +50,12 @@ module Mihari
|
|
|
52
50
|
# @return [nil]
|
|
53
51
|
#
|
|
54
52
|
def run
|
|
55
|
-
|
|
53
|
+
with_db_connection do
|
|
54
|
+
set_enriched_artifacts
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
Parallel.each(valid_emitters) do |emitter|
|
|
57
|
+
run_emitter emitter
|
|
58
|
+
end
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
|
|
@@ -6,9 +6,6 @@ module Mihari
|
|
|
6
6
|
module Analyzers
|
|
7
7
|
class BinaryEdge < Base
|
|
8
8
|
param :query
|
|
9
|
-
option :title, default: proc { "BinaryEdge search" }
|
|
10
|
-
option :description, default: proc { "query = #{query}" }
|
|
11
|
-
option :tags, default: proc { [] }
|
|
12
9
|
|
|
13
10
|
option :interval, default: proc { 0 }
|
|
14
11
|
|
|
@@ -19,9 +16,10 @@ module Mihari
|
|
|
19
16
|
results.map do |result|
|
|
20
17
|
events = result["events"] || []
|
|
21
18
|
events.filter_map do |event|
|
|
22
|
-
event.dig
|
|
19
|
+
data = event.dig("target", "ip")
|
|
20
|
+
data.nil? ? nil : Artifact.new(data: data, source: source, metadata: event)
|
|
23
21
|
end
|
|
24
|
-
end.flatten
|
|
22
|
+
end.flatten
|
|
25
23
|
end
|
|
26
24
|
|
|
27
25
|
private
|
|
@@ -6,9 +6,6 @@ module Mihari
|
|
|
6
6
|
module Analyzers
|
|
7
7
|
class Censys < Base
|
|
8
8
|
param :query
|
|
9
|
-
option :title, default: proc { "Censys search" }
|
|
10
|
-
option :description, default: proc { "query = #{query}" }
|
|
11
|
-
option :tags, default: proc { [] }
|
|
12
9
|
|
|
13
10
|
option :interval, default: proc { 0 }
|
|
14
11
|
|
|
@@ -77,6 +74,7 @@ module Mihari
|
|
|
77
74
|
Artifact.new(
|
|
78
75
|
data: hit.ip,
|
|
79
76
|
source: source,
|
|
77
|
+
metadata: hit.metadata,
|
|
80
78
|
autonomous_system: as,
|
|
81
79
|
geolocation: geolocation
|
|
82
80
|
)
|
|
@@ -6,15 +6,17 @@ module Mihari
|
|
|
6
6
|
module Analyzers
|
|
7
7
|
class Crtsh < Base
|
|
8
8
|
param :query
|
|
9
|
-
|
|
10
|
-
option :description, default: proc { "query = #{query}" }
|
|
11
|
-
option :tags, default: proc { [] }
|
|
9
|
+
|
|
12
10
|
option :exclude_expired, default: proc { true }
|
|
13
11
|
|
|
14
12
|
def artifacts
|
|
15
13
|
results = search
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
results.map do |result|
|
|
15
|
+
values = result["name_value"].to_s.lines.map(&:chomp)
|
|
16
|
+
values.map do |value|
|
|
17
|
+
Artifact.new(data: value, source: source, metadata: result)
|
|
18
|
+
end
|
|
19
|
+
end.flatten
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
private
|
|
@@ -6,8 +6,7 @@ module Mihari
|
|
|
6
6
|
module Analyzers
|
|
7
7
|
class DNPedia < Base
|
|
8
8
|
param :query
|
|
9
|
-
|
|
10
|
-
option :description, default: proc { "query = #{query}" }
|
|
9
|
+
|
|
11
10
|
option :tags, default: proc { [] }
|
|
12
11
|
|
|
13
12
|
def artifacts
|
|
@@ -23,13 +22,14 @@ module Mihari
|
|
|
23
22
|
#
|
|
24
23
|
# Search
|
|
25
24
|
#
|
|
26
|
-
# @return [Array<
|
|
25
|
+
# @return [Array<Mihari::Artifact>]
|
|
27
26
|
#
|
|
28
27
|
def search
|
|
29
28
|
res = api.search(query)
|
|
30
29
|
rows = res["rows"] || []
|
|
31
30
|
rows.map do |row|
|
|
32
|
-
[row["name"], row["zoneid"]].join(".")
|
|
31
|
+
data = [row["name"], row["zoneid"]].join(".")
|
|
32
|
+
Artifact.new(data: data, source: source, metadata: row)
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
end
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "dnstwister"
|
|
4
|
-
require "resolv"
|
|
5
|
-
require "parallel"
|
|
6
4
|
|
|
7
5
|
module Mihari
|
|
8
6
|
module Analyzers
|
|
@@ -10,8 +8,7 @@ module Mihari
|
|
|
10
8
|
include Mixins::Refang
|
|
11
9
|
|
|
12
10
|
param :query
|
|
13
|
-
|
|
14
|
-
option :description, default: proc { "query = #{query}" }
|
|
11
|
+
|
|
15
12
|
option :tags, default: proc { [] }
|
|
16
13
|
|
|
17
14
|
attr_reader :type
|
|
@@ -7,9 +7,6 @@ module Mihari
|
|
|
7
7
|
module Analyzers
|
|
8
8
|
class Feed < Base
|
|
9
9
|
param :query
|
|
10
|
-
option :title, default: proc { "Feed" }
|
|
11
|
-
option :description, default: proc { "query = #{query}" }
|
|
12
|
-
option :tags, default: proc { [] }
|
|
13
10
|
|
|
14
11
|
option :http_request_method, default: proc { "GET" }
|
|
15
12
|
option :http_request_headers, default: proc { {} }
|
|
@@ -6,9 +6,6 @@ module Mihari
|
|
|
6
6
|
module Analyzers
|
|
7
7
|
class GreyNoise < Base
|
|
8
8
|
param :query
|
|
9
|
-
option :title, default: proc { "GreyNoise search" }
|
|
10
|
-
option :description, default: proc { "query = #{query}" }
|
|
11
|
-
option :tags, default: proc { [] }
|
|
12
9
|
|
|
13
10
|
def artifacts
|
|
14
11
|
res = Structs::GreyNoise::Response.from_dynamic!(search)
|
|
@@ -56,6 +53,7 @@ module Mihari
|
|
|
56
53
|
Artifact.new(
|
|
57
54
|
data: datum.ip,
|
|
58
55
|
source: source,
|
|
56
|
+
metadata: datum.metadata_,
|
|
59
57
|
autonomous_system: as,
|
|
60
58
|
geolocation: geolocation
|
|
61
59
|
)
|
|
@@ -7,9 +7,6 @@ module Mihari
|
|
|
7
7
|
module Analyzers
|
|
8
8
|
class Onyphe < Base
|
|
9
9
|
param :query
|
|
10
|
-
option :title, default: proc { "Onyphe search" }
|
|
11
|
-
option :description, default: proc { "query = #{query}" }
|
|
12
|
-
option :tags, default: proc { [] }
|
|
13
10
|
|
|
14
11
|
option :interval, default: proc { 0 }
|
|
15
12
|
|
|
@@ -89,6 +86,7 @@ module Mihari
|
|
|
89
86
|
Artifact.new(
|
|
90
87
|
data: result.ip,
|
|
91
88
|
source: source,
|
|
89
|
+
metadata: result.metadata,
|
|
92
90
|
autonomous_system: as,
|
|
93
91
|
geolocation: geolocation
|
|
94
92
|
)
|
data/lib/mihari/analyzers/otx.rb
CHANGED
|
@@ -8,9 +8,6 @@ module Mihari
|
|
|
8
8
|
include Mixins::Refang
|
|
9
9
|
|
|
10
10
|
param :query
|
|
11
|
-
option :title, default: proc { "PassiveTotal search" }
|
|
12
|
-
option :description, default: proc { "query = #{query}" }
|
|
13
|
-
option :tags, default: proc { [] }
|
|
14
11
|
|
|
15
12
|
attr_reader :type
|
|
16
13
|
|
|
@@ -75,27 +72,29 @@ module Mihari
|
|
|
75
72
|
#
|
|
76
73
|
# Reverse whois search
|
|
77
74
|
#
|
|
78
|
-
# @return [Array<
|
|
75
|
+
# @return [Array<Mihari::Artifact>]
|
|
79
76
|
#
|
|
80
77
|
def reverse_whois_search
|
|
81
78
|
res = api.whois.search(query: query, field: "email")
|
|
82
79
|
results = res["results"] || []
|
|
83
80
|
results.map do |result|
|
|
84
|
-
result["domain"]
|
|
85
|
-
|
|
81
|
+
data = result["domain"]
|
|
82
|
+
Artifact.new(data: data, source: source, metadata: result)
|
|
83
|
+
end.flatten
|
|
86
84
|
end
|
|
87
85
|
|
|
88
86
|
#
|
|
89
87
|
# Passive SSL search
|
|
90
88
|
#
|
|
91
|
-
# @return [Array<
|
|
89
|
+
# @return [Array<Mihari::Artifact>]
|
|
92
90
|
#
|
|
93
91
|
def ssl_search
|
|
94
92
|
res = api.ssl.history(query)
|
|
95
93
|
results = res["results"] || []
|
|
96
94
|
results.map do |result|
|
|
97
|
-
result["ipAddresses"]
|
|
98
|
-
|
|
95
|
+
data = result["ipAddresses"]
|
|
96
|
+
Artifact.new(data: data, source: source, metadata: result)
|
|
97
|
+
end.flatten
|
|
99
98
|
end
|
|
100
99
|
end
|
|
101
100
|
end
|
|
@@ -8,9 +8,6 @@ module Mihari
|
|
|
8
8
|
include Mixins::Refang
|
|
9
9
|
|
|
10
10
|
param :query
|
|
11
|
-
option :title, default: proc { "Pulsedive search" }
|
|
12
|
-
option :description, default: proc { "query = #{query}" }
|
|
13
|
-
option :tags, default: proc { [] }
|
|
14
11
|
|
|
15
12
|
attr_reader :type
|
|
16
13
|
|
|
@@ -47,7 +44,7 @@ module Mihari
|
|
|
47
44
|
#
|
|
48
45
|
# Search
|
|
49
46
|
#
|
|
50
|
-
# @return [Array<
|
|
47
|
+
# @return [Array<Mihari::Artifact>]
|
|
51
48
|
#
|
|
52
49
|
def search
|
|
53
50
|
raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
|
|
@@ -57,7 +54,12 @@ module Mihari
|
|
|
57
54
|
|
|
58
55
|
properties = api.indicator.get_properties_by_id(iid)
|
|
59
56
|
(properties["dns"] || []).filter_map do |property|
|
|
60
|
-
|
|
57
|
+
if ["A", "PTR"].include?(property["name"])
|
|
58
|
+
nil
|
|
59
|
+
else
|
|
60
|
+
data = property["value"]
|
|
61
|
+
Artifact.new(data: data, source: source, metadata: property)
|
|
62
|
+
end
|
|
61
63
|
end
|
|
62
64
|
end
|
|
63
65
|
end
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "uuidtools"
|
|
4
|
-
|
|
5
3
|
module Mihari
|
|
6
4
|
module Analyzers
|
|
7
5
|
ANALYZER_TO_CLASS = {
|
|
@@ -31,13 +29,14 @@ module Mihari
|
|
|
31
29
|
}.freeze
|
|
32
30
|
|
|
33
31
|
class Rule < Base
|
|
34
|
-
include
|
|
32
|
+
include Mixins::DisallowedDataValue
|
|
33
|
+
include Mixins::Rule
|
|
35
34
|
|
|
36
35
|
option :title
|
|
37
36
|
option :description
|
|
38
37
|
option :queries
|
|
39
38
|
|
|
40
|
-
option :id, default: proc {}
|
|
39
|
+
option :id, default: proc { "" }
|
|
41
40
|
option :tags, default: proc { [] }
|
|
42
41
|
option :allowed_data_types, default: proc { ALLOWED_DATA_TYPES }
|
|
43
42
|
option :disallowed_data_values, default: proc { [] }
|
|
@@ -47,7 +46,7 @@ module Mihari
|
|
|
47
46
|
def initialize(**kwargs)
|
|
48
47
|
super(**kwargs)
|
|
49
48
|
|
|
50
|
-
@source = id
|
|
49
|
+
@source = id
|
|
51
50
|
|
|
52
51
|
validate_analyzer_configurations
|
|
53
52
|
end
|
|
@@ -69,7 +68,7 @@ module Mihari
|
|
|
69
68
|
# set interval in the top level
|
|
70
69
|
options = params[:options] || {}
|
|
71
70
|
interval = options[:interval]
|
|
72
|
-
params[:interval] = interval
|
|
71
|
+
params[:interval] = interval if interval
|
|
73
72
|
|
|
74
73
|
analyzer = klass.new(query, **params)
|
|
75
74
|
|
|
@@ -8,9 +8,6 @@ module Mihari
|
|
|
8
8
|
include Mixins::Refang
|
|
9
9
|
|
|
10
10
|
param :query
|
|
11
|
-
option :title, default: proc { "SecurityTrails search" }
|
|
12
|
-
option :description, default: proc { "query = #{query}" }
|
|
13
|
-
option :tags, default: proc { [] }
|
|
14
11
|
|
|
15
12
|
attr_reader :type
|
|
16
13
|
|
|
@@ -47,7 +44,7 @@ module Mihari
|
|
|
47
44
|
#
|
|
48
45
|
# IP/domain/mail search
|
|
49
46
|
#
|
|
50
|
-
# @return [Array<String>]
|
|
47
|
+
# @return [Array<String>, Array<Mihari::Artifact>]
|
|
51
48
|
#
|
|
52
49
|
def search
|
|
53
50
|
case type
|
|
@@ -78,12 +75,15 @@ module Mihari
|
|
|
78
75
|
#
|
|
79
76
|
# IP search
|
|
80
77
|
#
|
|
81
|
-
# @return [Array<
|
|
78
|
+
# @return [Array<Mihari::Artifact>]
|
|
82
79
|
#
|
|
83
80
|
def ip_search
|
|
84
81
|
result = api.domains.search(filter: { ipv4: query })
|
|
85
82
|
records = result["records"] || []
|
|
86
|
-
records.filter_map
|
|
83
|
+
records.filter_map do |record|
|
|
84
|
+
data = record["hostname"]
|
|
85
|
+
Artifact.new(data: data, source: source, metadata: record)
|
|
86
|
+
end
|
|
87
87
|
end
|
|
88
88
|
|
|
89
89
|
#
|
|
@@ -94,7 +94,10 @@ module Mihari
|
|
|
94
94
|
def mail_search
|
|
95
95
|
result = api.domains.search(filter: { whois_email: query })
|
|
96
96
|
records = result["records"] || []
|
|
97
|
-
records.filter_map
|
|
97
|
+
records.filter_map do |record|
|
|
98
|
+
data = record["hostname"]
|
|
99
|
+
Artifact.new(data: data, source: source, metadata: record)
|
|
100
|
+
end
|
|
98
101
|
end
|
|
99
102
|
end
|
|
100
103
|
end
|
|
@@ -6,9 +6,6 @@ module Mihari
|
|
|
6
6
|
module Analyzers
|
|
7
7
|
class Shodan < Base
|
|
8
8
|
param :query
|
|
9
|
-
option :title, default: proc { "Shodan search" }
|
|
10
|
-
option :description, default: proc { "query = #{query}" }
|
|
11
|
-
option :tags, default: proc { [] }
|
|
12
9
|
|
|
13
10
|
option :interval, default: proc { 0 }
|
|
14
11
|
|
|
@@ -20,7 +17,7 @@ module Mihari
|
|
|
20
17
|
results.map do |result|
|
|
21
18
|
matches = result.matches || []
|
|
22
19
|
matches.map { |match| build_artifact match }
|
|
23
|
-
end.flatten.
|
|
20
|
+
end.flatten.uniq(&:data)
|
|
24
21
|
end
|
|
25
22
|
|
|
26
23
|
private
|
|
@@ -98,6 +95,7 @@ module Mihari
|
|
|
98
95
|
Artifact.new(
|
|
99
96
|
data: match.ip_str,
|
|
100
97
|
source: source,
|
|
98
|
+
metadata: match.metadata,
|
|
101
99
|
autonomous_system: as,
|
|
102
100
|
geolocation: geolocation
|
|
103
101
|
)
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "spyse"
|
|
4
|
-
require "json"
|
|
5
4
|
|
|
6
5
|
module Mihari
|
|
7
6
|
module Analyzers
|
|
8
7
|
class Spyse < Base
|
|
9
8
|
param :query
|
|
10
|
-
|
|
11
|
-
option :description, default: proc { "query = #{query}" }
|
|
9
|
+
|
|
12
10
|
option :type, default: proc { "domain" }
|
|
13
|
-
option :tags, default: proc { [] }
|
|
14
11
|
|
|
15
12
|
def artifacts
|
|
16
13
|
search || []
|
|
@@ -42,33 +39,35 @@ module Mihari
|
|
|
42
39
|
#
|
|
43
40
|
# Domain search
|
|
44
41
|
#
|
|
45
|
-
# @return [Array<
|
|
42
|
+
# @return [Array<Mihari::Artifact>]
|
|
46
43
|
#
|
|
47
44
|
def domain_search
|
|
48
45
|
res = api.domain.search(search_params, limit: 100)
|
|
49
46
|
items = res.dig("data", "items") || []
|
|
50
47
|
items.map do |item|
|
|
51
|
-
item["name"]
|
|
52
|
-
|
|
48
|
+
data = item["name"]
|
|
49
|
+
Artifact.new(data: data, source: source, metadata: item)
|
|
50
|
+
end
|
|
53
51
|
end
|
|
54
52
|
|
|
55
53
|
#
|
|
56
54
|
# IP search
|
|
57
55
|
#
|
|
58
|
-
# @return [Array<
|
|
56
|
+
# @return [Array<Mihari::Artifact>]
|
|
59
57
|
#
|
|
60
58
|
def ip_search
|
|
61
59
|
res = api.ip.search(search_params, limit: 100)
|
|
62
60
|
items = res.dig("data", "items") || []
|
|
63
61
|
items.map do |item|
|
|
64
|
-
item["ip"]
|
|
65
|
-
|
|
62
|
+
data = item["ip"]
|
|
63
|
+
Artifact.new(data: data, source: source, metadata: item)
|
|
64
|
+
end
|
|
66
65
|
end
|
|
67
66
|
|
|
68
67
|
#
|
|
69
68
|
# IP/domain search
|
|
70
69
|
#
|
|
71
|
-
# @return [Array<
|
|
70
|
+
# @return [Array<Mihari::Artifact>]
|
|
72
71
|
#
|
|
73
72
|
def search
|
|
74
73
|
case type
|
|
@@ -6,9 +6,7 @@ module Mihari
|
|
|
6
6
|
module Analyzers
|
|
7
7
|
class Urlscan < Base
|
|
8
8
|
param :query
|
|
9
|
-
|
|
10
|
-
option :description, default: proc { "query = #{query}" }
|
|
11
|
-
option :tags, default: proc { [] }
|
|
9
|
+
|
|
12
10
|
option :allowed_data_types, default: proc { SUPPORTED_DATA_TYPES }
|
|
13
11
|
|
|
14
12
|
option :interval, default: proc { 0 }
|
|
@@ -29,9 +27,10 @@ module Mihari
|
|
|
29
27
|
allowed_data_types.map do |type|
|
|
30
28
|
results.filter_map do |result|
|
|
31
29
|
page = result.page
|
|
32
|
-
page.send(type.to_sym)
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
data = page.send(type.to_sym)
|
|
31
|
+
data.nil? ? nil : Artifact.new(data: data, source: source, metadata: result)
|
|
32
|
+
end
|
|
33
|
+
end.flatten
|
|
35
34
|
end
|
|
36
35
|
|
|
37
36
|
private
|
|
@@ -8,9 +8,6 @@ module Mihari
|
|
|
8
8
|
include Mixins::Refang
|
|
9
9
|
|
|
10
10
|
param :query
|
|
11
|
-
option :title, default: proc { "VirusTotal search" }
|
|
12
|
-
option :description, default: proc { "query = #{query}" }
|
|
13
|
-
option :tags, default: proc { [] }
|
|
14
11
|
|
|
15
12
|
attr_reader :type
|
|
16
13
|
|
|
@@ -47,7 +44,7 @@ module Mihari
|
|
|
47
44
|
#
|
|
48
45
|
# Search
|
|
49
46
|
#
|
|
50
|
-
# @return [Array<
|
|
47
|
+
# @return [Array<Mihari::Artifact>]
|
|
51
48
|
#
|
|
52
49
|
def search
|
|
53
50
|
case type
|
|
@@ -63,28 +60,30 @@ module Mihari
|
|
|
63
60
|
#
|
|
64
61
|
# Domain search
|
|
65
62
|
#
|
|
66
|
-
# @return [Array<
|
|
63
|
+
# @return [Array<Mihari::Artifact>]
|
|
67
64
|
#
|
|
68
65
|
def domain_search
|
|
69
66
|
res = api.domain.resolutions(query)
|
|
70
67
|
|
|
71
68
|
data = res["data"] || []
|
|
72
69
|
data.filter_map do |item|
|
|
73
|
-
item.dig("attributes", "ip_address")
|
|
74
|
-
|
|
70
|
+
data = item.dig("attributes", "ip_address")
|
|
71
|
+
data.nil? ? nil : Artifact.new(data: data, source: source, metadata: item)
|
|
72
|
+
end
|
|
75
73
|
end
|
|
76
74
|
|
|
77
75
|
#
|
|
78
76
|
# IP search
|
|
79
77
|
#
|
|
80
|
-
# @return [Array<
|
|
78
|
+
# @return [Array<Mihari::Artifact>]
|
|
81
79
|
#
|
|
82
80
|
def ip_search
|
|
83
81
|
res = api.ip_address.resolutions(query)
|
|
84
82
|
|
|
85
83
|
data = res["data"] || []
|
|
86
84
|
data.filter_map do |item|
|
|
87
|
-
item.dig("attributes", "host_name")
|
|
85
|
+
data = item.dig("attributes", "host_name")
|
|
86
|
+
Artifact.new(data: data, source: source, metadata: item)
|
|
88
87
|
end.uniq
|
|
89
88
|
end
|
|
90
89
|
end
|
|
@@ -6,9 +6,6 @@ module Mihari
|
|
|
6
6
|
module Analyzers
|
|
7
7
|
class VirusTotalIntelligence < Base
|
|
8
8
|
param :query
|
|
9
|
-
option :title, default: proc { "VirusTotal Intelligence search" }
|
|
10
|
-
option :description, default: proc { "query = #{query}" }
|
|
11
|
-
option :tags, default: proc { [] }
|
|
12
9
|
|
|
13
10
|
option :interval, default: proc { 0 }
|
|
14
11
|
|
|
@@ -21,8 +18,10 @@ module Mihari
|
|
|
21
18
|
def artifacts
|
|
22
19
|
responses = search_witgh_cursor
|
|
23
20
|
responses.map do |response|
|
|
24
|
-
response.data.map
|
|
25
|
-
|
|
21
|
+
response.data.map do |datum|
|
|
22
|
+
Artifact.new(data: datum.value, source: source, metadata: datum.metadata)
|
|
23
|
+
end
|
|
24
|
+
end.flatten
|
|
26
25
|
end
|
|
27
26
|
|
|
28
27
|
private
|
|
@@ -6,9 +6,7 @@ module Mihari
|
|
|
6
6
|
module Analyzers
|
|
7
7
|
class ZoomEye < Base
|
|
8
8
|
param :query
|
|
9
|
-
|
|
10
|
-
option :description, default: proc { "query = #{query}" }
|
|
11
|
-
option :tags, default: proc { [] }
|
|
9
|
+
|
|
12
10
|
option :type, default: proc { "host" }
|
|
13
11
|
|
|
14
12
|
option :interval, default: proc { 0 }
|
|
@@ -50,13 +48,14 @@ module Mihari
|
|
|
50
48
|
#
|
|
51
49
|
# @param [Array<Hash>] responses
|
|
52
50
|
#
|
|
53
|
-
# @return [Array<
|
|
51
|
+
# @return [Array<Mihari::Artifact>]
|
|
54
52
|
#
|
|
55
53
|
def convert_responses(responses)
|
|
56
54
|
responses.map do |res|
|
|
57
55
|
matches = res["matches"] || []
|
|
58
56
|
matches.map do |match|
|
|
59
|
-
match["ip"]
|
|
57
|
+
data = match["ip"]
|
|
58
|
+
Artifact.new(data: data, source: source, metadata: match)
|
|
60
59
|
end
|
|
61
60
|
end.flatten.compact.uniq
|
|
62
61
|
end
|
data/lib/mihari/cli/base.rb
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "thor"
|
|
4
|
-
|
|
5
|
-
require "mihari/mixins/hash"
|
|
6
|
-
|
|
7
3
|
require "mihari/cli/mixins/utils"
|
|
8
4
|
|
|
9
5
|
module Mihari
|
|
10
6
|
module CLI
|
|
11
7
|
class Base < Thor
|
|
12
|
-
include Mihari::Mixins::Hash
|
|
13
8
|
include Mixins::Utils
|
|
14
9
|
|
|
15
10
|
class << self
|
data/lib/mihari/cli/init.rb
CHANGED
data/lib/mihari/cli/main.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "thor"
|
|
4
|
+
|
|
3
5
|
# Commands
|
|
4
6
|
require "mihari/commands/search"
|
|
5
7
|
require "mihari/commands/web"
|
|
@@ -7,7 +9,6 @@ require "mihari/commands/web"
|
|
|
7
9
|
# CLIs
|
|
8
10
|
require "mihari/cli/base"
|
|
9
11
|
|
|
10
|
-
require "mihari/cli/analyzer"
|
|
11
12
|
require "mihari/cli/init"
|
|
12
13
|
require "mihari/cli/validator"
|
|
13
14
|
|
|
@@ -17,13 +18,10 @@ module Mihari
|
|
|
17
18
|
include Mihari::Commands::Search
|
|
18
19
|
include Mihari::Commands::Web
|
|
19
20
|
|
|
20
|
-
desc "
|
|
21
|
-
subcommand "analyze", Analyzer
|
|
22
|
-
|
|
23
|
-
desc "init", "Sub commands to initialize config & rule"
|
|
21
|
+
desc "init", "Sub commands to initialize a rule"
|
|
24
22
|
subcommand "init", Initialization
|
|
25
23
|
|
|
26
|
-
desc "validate", "Sub commands to validate format of
|
|
24
|
+
desc "validate", "Sub commands to validate format of a rule"
|
|
27
25
|
subcommand "validate", Validator
|
|
28
26
|
end
|
|
29
27
|
end
|