mihari 5.1.1 → 5.1.3
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/.gitmodules +0 -3
- data/.rubocop.yml +6 -0
- data/README.md +0 -1
- data/lib/mihari/analyzers/base.rb +32 -27
- data/lib/mihari/analyzers/binaryedge.rb +8 -2
- data/lib/mihari/analyzers/censys.rb +10 -61
- data/lib/mihari/analyzers/circl.rb +13 -19
- data/lib/mihari/analyzers/crtsh.rb +6 -0
- data/lib/mihari/analyzers/dnstwister.rb +12 -19
- data/lib/mihari/analyzers/feed.rb +21 -0
- data/lib/mihari/analyzers/greynoise.rb +5 -28
- data/lib/mihari/analyzers/onyphe.rb +8 -33
- data/lib/mihari/analyzers/otx.rb +11 -17
- data/lib/mihari/analyzers/passivetotal.rb +13 -19
- data/lib/mihari/analyzers/pulsedive.rb +3 -1
- data/lib/mihari/analyzers/rule.rb +0 -1
- data/lib/mihari/analyzers/securitytrails.rb +18 -29
- data/lib/mihari/analyzers/shodan.rb +13 -92
- data/lib/mihari/analyzers/urlscan.rb +12 -4
- data/lib/mihari/analyzers/virustotal.rb +4 -0
- data/lib/mihari/analyzers/virustotal_intelligence.rb +9 -6
- data/lib/mihari/analyzers/zoomeye.rb +9 -0
- data/lib/mihari/clients/binaryedge.rb +5 -0
- data/lib/mihari/clients/censys.rb +4 -4
- data/lib/mihari/clients/circl.rb +3 -3
- data/lib/mihari/clients/greynoise.rb +6 -1
- data/lib/mihari/clients/misp.rb +8 -1
- data/lib/mihari/clients/onyphe.rb +13 -1
- data/lib/mihari/clients/otx.rb +20 -0
- data/lib/mihari/clients/passivetotal.rb +6 -2
- data/lib/mihari/clients/publsedive.rb +18 -1
- data/lib/mihari/clients/securitytrails.rb +94 -0
- data/lib/mihari/clients/shodan.rb +14 -3
- data/lib/mihari/clients/the_hive.rb +6 -1
- data/lib/mihari/clients/urlscan.rb +3 -1
- data/lib/mihari/clients/virustotal.rb +9 -3
- data/lib/mihari/clients/zoomeye.rb +7 -1
- data/lib/mihari/commands/database.rb +1 -6
- data/lib/mihari/commands/searcher.rb +1 -2
- data/lib/mihari/database.rb +9 -0
- data/lib/mihari/http.rb +14 -18
- data/lib/mihari/structs/censys.rb +62 -0
- data/lib/mihari/structs/greynoise.rb +43 -0
- data/lib/mihari/structs/onyphe.rb +45 -0
- data/lib/mihari/structs/shodan.rb +83 -0
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/middleware/connection_adapter.rb +1 -3
- data/lib/mihari/web/public/assets/{index-63900d73.js → index-7d0fb8c4.js} +2 -2
- data/lib/mihari/web/public/index.html +1 -1
- data/lib/mihari/web/public/redoc-static.html +2 -2
- data/lib/mihari.rb +1 -3
- data/mihari.gemspec +2 -3
- metadata +8 -24
- data/lib/mihari/analyzers/dnpedia.rb +0 -33
- data/lib/mihari/clients/dnpedia.rb +0 -64
- data/lib/mihari/mixins/database.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd278975834369b3274b38b590f12d4f2fed97d7626363ff3cfbc9845195b386
|
4
|
+
data.tar.gz: 864ee1deae0bdb0390d9e330eb76c993860c37189dce0d23c9793b012f338275
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 258731713400cb40f6da8f24e6ce0213b883eeff98a22a16a88c84568633ad02ad3e18f4e70e6faea428a29bdcdc257b6ec3c86ebea7979065ec2e42ab445c47
|
7
|
+
data.tar.gz: 6c8beea0c3f4aa42f8fb8217a05c6256a6a8ea10daceb05d05ed2884d8b53c86195c765fa70cf35ea19c41d959fd6df114fa2b609893e828def028f5b16b5fc4
|
data/.gitmodules
CHANGED
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -45,7 +45,6 @@ Mihari supports the following services by default.
|
|
45
45
|
- [Censys](http://censys.io)
|
46
46
|
- [CIRCL passive DNS](https://www.circl.lu/services/passive-dns/) / [passive SSL](https://www.circl.lu/services/passive-ssl/)
|
47
47
|
- [crt.sh](https://crt.sh/)
|
48
|
-
- [DN Pedia](https://dnpedia.com/)
|
49
48
|
- [dnstwister](https://dnstwister.report/)
|
50
49
|
- [GreyNoise](https://www.greynoise.io/)
|
51
50
|
- [Onyphe](https://onyphe.io)
|
@@ -7,7 +7,6 @@ module Mihari
|
|
7
7
|
|
8
8
|
option :rule, default: proc {}
|
9
9
|
|
10
|
-
include Mixins::AutonomousSystem
|
11
10
|
include Mixins::Configurable
|
12
11
|
include Mixins::Retriable
|
13
12
|
|
@@ -20,6 +19,15 @@ module Mihari
|
|
20
19
|
@base_time = Time.now.utc
|
21
20
|
end
|
22
21
|
|
22
|
+
#
|
23
|
+
# Load/overwrite rule
|
24
|
+
#
|
25
|
+
# @param [String] path_or_id
|
26
|
+
#
|
27
|
+
def load_rule(path_or_id)
|
28
|
+
@rule = Structs::Rule.from_path_or_id path_or_id
|
29
|
+
end
|
30
|
+
|
23
31
|
# @return [Array<String>, Array<Mihari::Artifact>]
|
24
32
|
def artifacts
|
25
33
|
raise NotImplementedError, "You must implement #{self.class}##{__method__}"
|
@@ -30,35 +38,41 @@ module Mihari
|
|
30
38
|
self.class.to_s.split("::").last.to_s
|
31
39
|
end
|
32
40
|
|
41
|
+
# @return [String]
|
42
|
+
def class_name
|
43
|
+
self.class.to_s.split("::").last
|
44
|
+
end
|
45
|
+
|
33
46
|
#
|
34
47
|
# Set artifacts & run emitters in parallel
|
35
48
|
#
|
36
49
|
# @return [Mihari::Alert, nil]
|
37
50
|
#
|
38
51
|
def run
|
39
|
-
unless configured?
|
40
|
-
class_name = self.class.to_s.split("::").last
|
41
|
-
raise ConfigurationError, "#{class_name} is not configured correctly"
|
42
|
-
end
|
43
|
-
|
44
|
-
set_enriched_artifacts
|
45
|
-
|
46
|
-
responses = Parallel.map(valid_emitters) do |emitter|
|
47
|
-
run_emitter emitter
|
48
|
-
end
|
52
|
+
raise ConfigurationError, "#{class_name} is not configured correctly" unless configured?
|
49
53
|
|
54
|
+
alert_or_something = bulk_emit
|
50
55
|
# returns Mihari::Alert created by the database emitter
|
51
|
-
|
56
|
+
alert_or_something.find { |res| res.is_a?(Mihari::Alert) }
|
52
57
|
end
|
53
58
|
|
54
59
|
#
|
55
|
-
#
|
60
|
+
# Bulk emit
|
61
|
+
#
|
62
|
+
# @return [Array<Mihari::Alert>]
|
63
|
+
#
|
64
|
+
def bulk_emit
|
65
|
+
Parallel.map(valid_emitters) { |emitter| emit emitter }.compact
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Emit an alert
|
56
70
|
#
|
57
71
|
# @param [Mihari::Emitters::Base] emitter
|
58
72
|
#
|
59
73
|
# @return [Mihari::Alert, nil]
|
60
74
|
#
|
61
|
-
def
|
75
|
+
def emit(emitter)
|
62
76
|
return if enriched_artifacts.empty?
|
63
77
|
|
64
78
|
alert_or_something = emitter.run(artifacts: enriched_artifacts, rule: rule)
|
@@ -80,6 +94,7 @@ module Mihari
|
|
80
94
|
#
|
81
95
|
# Normalize artifacts
|
82
96
|
# - Convert data (string) into an artifact
|
97
|
+
# - Set rule ID
|
83
98
|
# - Reject an invalid artifact
|
84
99
|
# - Uniquefy artifacts by data
|
85
100
|
#
|
@@ -89,17 +104,16 @@ module Mihari
|
|
89
104
|
@normalized_artifacts ||= artifacts.compact.sort.map do |artifact|
|
90
105
|
# No need to set data_type manually
|
91
106
|
# It is set automatically in #initialize
|
92
|
-
artifact.is_a?(Artifact) ? artifact : Artifact.new(data: artifact, source: source)
|
93
|
-
end.select(&:valid?).uniq(&:data).map do |artifact|
|
107
|
+
artifact = artifact.is_a?(Artifact) ? artifact : Artifact.new(data: artifact, source: source)
|
94
108
|
artifact.rule_id = rule&.id
|
95
109
|
artifact
|
96
|
-
end
|
110
|
+
end.select(&:valid?).uniq(&:data)
|
97
111
|
end
|
98
112
|
|
99
113
|
private
|
100
114
|
|
101
115
|
#
|
102
|
-
# Uniquefy artifacts
|
116
|
+
# Uniquefy artifacts (assure rule level uniqueness)
|
103
117
|
#
|
104
118
|
# @return [Array<Mihari::Artifact>]
|
105
119
|
#
|
@@ -121,15 +135,6 @@ module Mihari
|
|
121
135
|
end
|
122
136
|
end
|
123
137
|
|
124
|
-
#
|
125
|
-
# Set enriched artifacts
|
126
|
-
#
|
127
|
-
# @return [nil]
|
128
|
-
#
|
129
|
-
def set_enriched_artifacts
|
130
|
-
retry_on_error { enriched_artifacts }
|
131
|
-
end
|
132
|
-
|
133
138
|
#
|
134
139
|
# Select valid emitters
|
135
140
|
#
|
@@ -10,6 +10,12 @@ module Mihari
|
|
10
10
|
# @return [String, nil]
|
11
11
|
attr_reader :api_key
|
12
12
|
|
13
|
+
# @return [String]
|
14
|
+
attr_reader :query
|
15
|
+
|
16
|
+
# @return [Integer]
|
17
|
+
attr_reader :interval
|
18
|
+
|
13
19
|
def initialize(*args, **kwargs)
|
14
20
|
super(*args, **kwargs)
|
15
21
|
|
@@ -41,7 +47,7 @@ module Mihari
|
|
41
47
|
#
|
42
48
|
# @return [Hash]
|
43
49
|
#
|
44
|
-
def search_with_page(
|
50
|
+
def search_with_page(page: 1)
|
45
51
|
client.search(query, page: page)
|
46
52
|
rescue UnsuccessfulStatusCodeError => e
|
47
53
|
raise RetryableError, e if e.message.include?("Request time limit exceeded")
|
@@ -57,7 +63,7 @@ module Mihari
|
|
57
63
|
def search
|
58
64
|
responses = []
|
59
65
|
(1..500).each do |page|
|
60
|
-
res = search_with_page(
|
66
|
+
res = search_with_page(page: page)
|
61
67
|
total = res["total"].to_i
|
62
68
|
|
63
69
|
responses << res
|
@@ -13,6 +13,12 @@ module Mihari
|
|
13
13
|
# @return [String, nil]
|
14
14
|
attr_reader :secret
|
15
15
|
|
16
|
+
# @return [Integer]
|
17
|
+
attr_reader :interval
|
18
|
+
|
19
|
+
# @return [String]
|
20
|
+
attr_reader :query
|
21
|
+
|
16
22
|
def initialize(*args, **kwargs)
|
17
23
|
super(*args, **kwargs)
|
18
24
|
|
@@ -21,30 +27,12 @@ module Mihari
|
|
21
27
|
end
|
22
28
|
|
23
29
|
def artifacts
|
24
|
-
search
|
25
|
-
end
|
26
|
-
|
27
|
-
def configured?
|
28
|
-
configuration_keys.all? { |key| Mihari.config.send(key) } || (id? && secret?)
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
#
|
34
|
-
# Search
|
35
|
-
#
|
36
|
-
# @return [Array<String>]
|
37
|
-
#
|
38
|
-
def search
|
39
30
|
artifacts = []
|
40
31
|
|
41
32
|
cursor = nil
|
42
33
|
loop do
|
43
34
|
response = client.search(query, cursor: cursor)
|
44
|
-
|
45
|
-
|
46
|
-
artifacts << response_to_artifacts(response)
|
47
|
-
|
35
|
+
artifacts << response.result.to_artifacts(source)
|
48
36
|
cursor = response.result.links.next
|
49
37
|
break if cursor == ""
|
50
38
|
|
@@ -55,50 +43,11 @@ module Mihari
|
|
55
43
|
artifacts.flatten.uniq(&:data)
|
56
44
|
end
|
57
45
|
|
58
|
-
|
59
|
-
|
60
|
-
#
|
61
|
-
# @param [Structs::Censys::Response] response
|
62
|
-
#
|
63
|
-
# @return [Array<String>]
|
64
|
-
#
|
65
|
-
def response_to_artifacts(response)
|
66
|
-
response.result.hits.map { |hit| build_artifact(hit) }
|
46
|
+
def configured?
|
47
|
+
configuration_keys.all? { |key| Mihari.config.send(key) } || (id? && secret?)
|
67
48
|
end
|
68
49
|
|
69
|
-
|
70
|
-
# Build an artifact from a Shodan search API response
|
71
|
-
#
|
72
|
-
# @param [Structs::Censys::Hit] hit
|
73
|
-
#
|
74
|
-
# @return [Artifact]
|
75
|
-
#
|
76
|
-
def build_artifact(hit)
|
77
|
-
as = AutonomousSystem.new(asn: normalize_asn(hit.autonomous_system.asn))
|
78
|
-
|
79
|
-
# sometimes Censys overlooks country
|
80
|
-
# then set geolocation as nil
|
81
|
-
geolocation = nil
|
82
|
-
unless hit.location.country.nil?
|
83
|
-
geolocation = Geolocation.new(
|
84
|
-
country: hit.location.country,
|
85
|
-
country_code: hit.location.country_code
|
86
|
-
)
|
87
|
-
end
|
88
|
-
|
89
|
-
ports = hit.services.map(&:port).map do |port|
|
90
|
-
Port.new(port: port)
|
91
|
-
end
|
92
|
-
|
93
|
-
Artifact.new(
|
94
|
-
data: hit.ip,
|
95
|
-
source: source,
|
96
|
-
metadata: hit.metadata,
|
97
|
-
autonomous_system: as,
|
98
|
-
geolocation: geolocation,
|
99
|
-
ports: ports
|
100
|
-
)
|
101
|
-
end
|
50
|
+
private
|
102
51
|
|
103
52
|
def configuration_keys
|
104
53
|
%w[censys_id censys_secret]
|
@@ -16,6 +16,9 @@ module Mihari
|
|
16
16
|
# @return [String, nil]
|
17
17
|
attr_reader :password
|
18
18
|
|
19
|
+
# @return [String]
|
20
|
+
attr_reader :query
|
21
|
+
|
19
22
|
def initialize(*args, **kwargs)
|
20
23
|
super
|
21
24
|
|
@@ -27,7 +30,14 @@ module Mihari
|
|
27
30
|
end
|
28
31
|
|
29
32
|
def artifacts
|
30
|
-
|
33
|
+
case type
|
34
|
+
when "domain"
|
35
|
+
passive_dns_search
|
36
|
+
when "hash"
|
37
|
+
passive_ssl_search
|
38
|
+
else
|
39
|
+
raise InvalidInputError, "#{@query}(type: #{@type || "unknown"}) is not supported."
|
40
|
+
end
|
31
41
|
end
|
32
42
|
|
33
43
|
def configured?
|
@@ -44,29 +54,13 @@ module Mihari
|
|
44
54
|
@client ||= Clients::CIRCL.new(username: username, password: password)
|
45
55
|
end
|
46
56
|
|
47
|
-
#
|
48
|
-
# Passive DNS/SSL search
|
49
|
-
#
|
50
|
-
# @return [Array<String>]
|
51
|
-
#
|
52
|
-
def search
|
53
|
-
case @type
|
54
|
-
when "domain"
|
55
|
-
passive_dns_search
|
56
|
-
when "hash"
|
57
|
-
passive_ssl_search
|
58
|
-
else
|
59
|
-
raise InvalidInputError, "#{@query}(type: #{@type || "unknown"}) is not supported."
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
57
|
#
|
64
58
|
# Passive DNS search
|
65
59
|
#
|
66
60
|
# @return [Array<String>]
|
67
61
|
#
|
68
62
|
def passive_dns_search
|
69
|
-
results = client.dns_query(
|
63
|
+
results = client.dns_query(query)
|
70
64
|
results.filter_map do |result|
|
71
65
|
type = result["rrtype"]
|
72
66
|
(type == "A") ? result["rdata"] : nil
|
@@ -79,7 +73,7 @@ module Mihari
|
|
79
73
|
# @return [Array<String>]
|
80
74
|
#
|
81
75
|
def passive_ssl_search
|
82
|
-
result = client.ssl_cquery(
|
76
|
+
result = client.ssl_cquery(query)
|
83
77
|
seen = result["seen"] || []
|
84
78
|
seen.uniq
|
85
79
|
end
|
@@ -7,10 +7,12 @@ module Mihari
|
|
7
7
|
|
8
8
|
param :query
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
# @return [String]
|
12
11
|
attr_reader :type
|
13
12
|
|
13
|
+
# @return [String]
|
14
|
+
attr_reader :query
|
15
|
+
|
14
16
|
def initialize(*args, **kwargs)
|
15
17
|
super
|
16
18
|
|
@@ -19,7 +21,14 @@ module Mihari
|
|
19
21
|
end
|
20
22
|
|
21
23
|
def artifacts
|
22
|
-
|
24
|
+
raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
|
25
|
+
|
26
|
+
res = client.fuzz(query)
|
27
|
+
fuzzy_domains = res["fuzzy_domains"] || []
|
28
|
+
domains = fuzzy_domains.map { |domain| domain["domain"] }
|
29
|
+
Parallel.map(domains) do |domain|
|
30
|
+
resolvable?(domain) ? domain : nil
|
31
|
+
end.compact
|
23
32
|
end
|
24
33
|
|
25
34
|
private
|
@@ -50,22 +59,6 @@ module Mihari
|
|
50
59
|
rescue Resolv::ResolvError => _e
|
51
60
|
false
|
52
61
|
end
|
53
|
-
|
54
|
-
#
|
55
|
-
# Search
|
56
|
-
#
|
57
|
-
# @return [Array<String>]
|
58
|
-
#
|
59
|
-
def search
|
60
|
-
raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
|
61
|
-
|
62
|
-
res = client.fuzz(query)
|
63
|
-
fuzzy_domains = res["fuzzy_domains"] || []
|
64
|
-
domains = fuzzy_domains.map { |domain| domain["domain"] }
|
65
|
-
Parallel.map(domains) do |domain|
|
66
|
-
resolvable?(domain) ? domain : nil
|
67
|
-
end.compact
|
68
|
-
end
|
69
62
|
end
|
70
63
|
end
|
71
64
|
end
|
@@ -16,6 +16,27 @@ module Mihari
|
|
16
16
|
|
17
17
|
option :selector, default: proc { "" }
|
18
18
|
|
19
|
+
# @return [Hash, nil]
|
20
|
+
attr_reader :data
|
21
|
+
|
22
|
+
# @return [Hash, nil]
|
23
|
+
attr_reader :json
|
24
|
+
|
25
|
+
# @return [Hash, nil]
|
26
|
+
attr_reader :params
|
27
|
+
|
28
|
+
# @return [Hash, nil]
|
29
|
+
attr_reader :headers
|
30
|
+
|
31
|
+
# @return [String]
|
32
|
+
attr_reader :method
|
33
|
+
|
34
|
+
# @return [String]
|
35
|
+
attr_reader :selector
|
36
|
+
|
37
|
+
# @return [String]
|
38
|
+
attr_reader :query
|
39
|
+
|
19
40
|
def artifacts
|
20
41
|
Mihari::Feed::Parser.new(results).parse selector
|
21
42
|
end
|
@@ -8,6 +8,9 @@ module Mihari
|
|
8
8
|
# @return [String, nil]
|
9
9
|
attr_reader :api_key
|
10
10
|
|
11
|
+
# @return [String]
|
12
|
+
attr_reader :query
|
13
|
+
|
11
14
|
def initialize(*args, **kwargs)
|
12
15
|
super(*args, **kwargs)
|
13
16
|
|
@@ -15,10 +18,8 @@ module Mihari
|
|
15
18
|
end
|
16
19
|
|
17
20
|
def artifacts
|
18
|
-
res =
|
19
|
-
res.
|
20
|
-
build_artifact datum
|
21
|
-
end
|
21
|
+
res = search
|
22
|
+
res.to_artifacts
|
22
23
|
end
|
23
24
|
|
24
25
|
private
|
@@ -41,30 +42,6 @@ module Mihari
|
|
41
42
|
def search
|
42
43
|
client.gnql_search(query, size: PAGE_SIZE)
|
43
44
|
end
|
44
|
-
|
45
|
-
#
|
46
|
-
# Build an artifact from a GreyNoise search API response
|
47
|
-
#
|
48
|
-
# @param [Structs::GreyNoise::Datum] datum
|
49
|
-
#
|
50
|
-
# @return [Artifact]
|
51
|
-
#
|
52
|
-
def build_artifact(datum)
|
53
|
-
as = AutonomousSystem.new(asn: normalize_asn(datum.metadata.asn))
|
54
|
-
|
55
|
-
geolocation = Geolocation.new(
|
56
|
-
country: datum.metadata.country,
|
57
|
-
country_code: datum.metadata.country_code
|
58
|
-
)
|
59
|
-
|
60
|
-
Artifact.new(
|
61
|
-
data: datum.ip,
|
62
|
-
source: source,
|
63
|
-
metadata: datum.metadata_,
|
64
|
-
autonomous_system: as,
|
65
|
-
geolocation: geolocation
|
66
|
-
)
|
67
|
-
end
|
68
45
|
end
|
69
46
|
end
|
70
47
|
end
|
@@ -12,6 +12,12 @@ module Mihari
|
|
12
12
|
# @return [String, nil]
|
13
13
|
attr_reader :api_key
|
14
14
|
|
15
|
+
# @return [String]
|
16
|
+
attr_reader :query
|
17
|
+
|
18
|
+
# @return [Integer]
|
19
|
+
attr_reader :interval
|
20
|
+
|
15
21
|
def initialize(*args, **kwargs)
|
16
22
|
super(*args, **kwargs)
|
17
23
|
|
@@ -22,10 +28,7 @@ module Mihari
|
|
22
28
|
responses = search
|
23
29
|
return [] unless responses
|
24
30
|
|
25
|
-
|
26
|
-
results.map do |result|
|
27
|
-
build_artifact result
|
28
|
-
end
|
31
|
+
responses.map { |response| response.to_artifacts(source) }.flatten
|
29
32
|
end
|
30
33
|
|
31
34
|
private
|
@@ -49,8 +52,7 @@ module Mihari
|
|
49
52
|
# @return [Structs::Onyphe::Response]
|
50
53
|
#
|
51
54
|
def search_with_page(query, page: 1)
|
52
|
-
|
53
|
-
Structs::Onyphe::Response.from_dynamic!(res)
|
55
|
+
client.datascan(query, page: page)
|
54
56
|
end
|
55
57
|
|
56
58
|
#
|
@@ -72,33 +74,6 @@ module Mihari
|
|
72
74
|
end
|
73
75
|
responses
|
74
76
|
end
|
75
|
-
|
76
|
-
#
|
77
|
-
# Build an artifact from an Onyphe search API result
|
78
|
-
#
|
79
|
-
# @param [Structs::Onyphe::Result] result
|
80
|
-
#
|
81
|
-
# @return [Artifact]
|
82
|
-
#
|
83
|
-
def build_artifact(result)
|
84
|
-
as = AutonomousSystem.new(asn: normalize_asn(result.asn))
|
85
|
-
|
86
|
-
geolocation = nil
|
87
|
-
unless result.country_code.nil?
|
88
|
-
geolocation = Geolocation.new(
|
89
|
-
country: NormalizeCountry(result.country_code, to: :short),
|
90
|
-
country_code: result.country_code
|
91
|
-
)
|
92
|
-
end
|
93
|
-
|
94
|
-
Artifact.new(
|
95
|
-
data: result.ip,
|
96
|
-
source: source,
|
97
|
-
metadata: result.metadata,
|
98
|
-
autonomous_system: as,
|
99
|
-
geolocation: geolocation
|
100
|
-
)
|
101
|
-
end
|
102
77
|
end
|
103
78
|
end
|
104
79
|
end
|
data/lib/mihari/analyzers/otx.rb
CHANGED
@@ -13,6 +13,9 @@ module Mihari
|
|
13
13
|
# @return [String, nil]
|
14
14
|
attr_reader :api_key
|
15
15
|
|
16
|
+
# @return [String]
|
17
|
+
attr_reader :query
|
18
|
+
|
16
19
|
def initialize(*args, **kwargs)
|
17
20
|
super
|
18
21
|
|
@@ -23,7 +26,14 @@ module Mihari
|
|
23
26
|
end
|
24
27
|
|
25
28
|
def artifacts
|
26
|
-
|
29
|
+
case type
|
30
|
+
when "domain"
|
31
|
+
domain_search
|
32
|
+
when "ip"
|
33
|
+
ip_search
|
34
|
+
else
|
35
|
+
raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
|
36
|
+
end
|
27
37
|
end
|
28
38
|
|
29
39
|
private
|
@@ -45,22 +55,6 @@ module Mihari
|
|
45
55
|
%w[ip domain].include? type
|
46
56
|
end
|
47
57
|
|
48
|
-
#
|
49
|
-
# IP/domain search
|
50
|
-
#
|
51
|
-
# @return [Array<String>]
|
52
|
-
#
|
53
|
-
def search
|
54
|
-
case type
|
55
|
-
when "domain"
|
56
|
-
domain_search
|
57
|
-
when "ip"
|
58
|
-
ip_search
|
59
|
-
else
|
60
|
-
raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
58
|
#
|
65
59
|
# Domain search
|
66
60
|
#
|
@@ -16,6 +16,9 @@ module Mihari
|
|
16
16
|
# @return [String, nil]
|
17
17
|
attr_reader :api_key
|
18
18
|
|
19
|
+
# @return [String]
|
20
|
+
attr_reader :query
|
21
|
+
|
19
22
|
def initialize(*args, **kwargs)
|
20
23
|
super(*args, **kwargs)
|
21
24
|
|
@@ -27,7 +30,16 @@ module Mihari
|
|
27
30
|
end
|
28
31
|
|
29
32
|
def artifacts
|
30
|
-
|
33
|
+
case type
|
34
|
+
when "domain", "ip"
|
35
|
+
passive_dns_search
|
36
|
+
when "mail"
|
37
|
+
reverse_whois_search
|
38
|
+
when "hash"
|
39
|
+
ssl_search
|
40
|
+
else
|
41
|
+
raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
|
42
|
+
end
|
31
43
|
end
|
32
44
|
|
33
45
|
def configured?
|
@@ -53,24 +65,6 @@ module Mihari
|
|
53
65
|
%w[ip domain mail hash].include? type
|
54
66
|
end
|
55
67
|
|
56
|
-
#
|
57
|
-
# Passive DNS/SSL, reverse whois search
|
58
|
-
#
|
59
|
-
# @return [Array<String>]
|
60
|
-
#
|
61
|
-
def search
|
62
|
-
case type
|
63
|
-
when "domain", "ip"
|
64
|
-
passive_dns_search
|
65
|
-
when "mail"
|
66
|
-
reverse_whois_search
|
67
|
-
when "hash"
|
68
|
-
ssl_search
|
69
|
-
else
|
70
|
-
raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
68
|
#
|
75
69
|
# Passive DNS search
|
76
70
|
#
|
@@ -13,6 +13,9 @@ module Mihari
|
|
13
13
|
# @return [String, nil]
|
14
14
|
attr_reader :api_key
|
15
15
|
|
16
|
+
# @return [Integer]
|
17
|
+
attr_reader :query
|
18
|
+
|
16
19
|
def initialize(*args, **kwargs)
|
17
20
|
super
|
18
21
|
|
@@ -55,7 +58,6 @@ module Mihari
|
|
55
58
|
|
56
59
|
indicator = client.get_indicator(query)
|
57
60
|
iid = indicator["iid"]
|
58
|
-
|
59
61
|
properties = client.get_properties(iid)
|
60
62
|
(properties["dns"] || []).filter_map do |property|
|
61
63
|
if %w[A PTR].include?(property["name"])
|