mihari 3.4.1 → 3.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitmodules +3 -0
- data/README.md +2 -0
- data/Steepfile +32 -0
- data/config.ru +1 -0
- data/lib/mihari/analyzers/base.rb +24 -11
- data/lib/mihari/analyzers/binaryedge.rb +13 -0
- data/lib/mihari/analyzers/censys.rb +42 -9
- data/lib/mihari/analyzers/circl.rb +15 -0
- data/lib/mihari/analyzers/crtsh.rb +5 -0
- data/lib/mihari/analyzers/dnpedia.rb +5 -0
- data/lib/mihari/analyzers/dnstwister.rb +17 -0
- data/lib/mihari/analyzers/onyphe.rb +50 -9
- data/lib/mihari/analyzers/otx.rb +20 -0
- data/lib/mihari/analyzers/passivetotal.rb +25 -0
- data/lib/mihari/analyzers/pulsedive.rb +10 -0
- data/lib/mihari/analyzers/rule.rb +18 -0
- data/lib/mihari/analyzers/securitytrails.rb +25 -0
- data/lib/mihari/analyzers/shodan.rb +39 -5
- data/lib/mihari/analyzers/spyse.rb +20 -0
- data/lib/mihari/analyzers/urlscan.rb +10 -0
- data/lib/mihari/analyzers/virustotal.rb +20 -0
- data/lib/mihari/analyzers/zoomeye.rb +38 -0
- data/lib/mihari/cli/analyzer.rb +1 -0
- data/lib/mihari/cli/base.rb +0 -2
- data/lib/mihari/commands/init.rb +1 -1
- data/lib/mihari/commands/search.rb +1 -0
- data/lib/mihari/commands/web.rb +1 -0
- data/lib/mihari/{constraints.rb → constants.rb} +0 -0
- data/lib/mihari/database.rb +55 -3
- data/lib/mihari/emitters/base.rb +1 -1
- data/lib/mihari/emitters/misp.rb +38 -5
- data/lib/mihari/emitters/slack.rb +20 -2
- data/lib/mihari/emitters/the_hive.rb +16 -3
- data/lib/mihari/emitters/webhook.rb +18 -3
- data/lib/mihari/enrichers/ipinfo.rb +38 -0
- data/lib/mihari/mixins/autonomous_system.rb +19 -0
- data/lib/mihari/mixins/disallowed_data_value.rb +1 -1
- data/lib/mihari/models/alert.rb +28 -10
- data/lib/mihari/models/artifact.rb +94 -0
- data/lib/mihari/models/autonomous_system.rb +28 -0
- data/lib/mihari/models/dns.rb +55 -0
- data/lib/mihari/models/geolocation.rb +29 -0
- data/lib/mihari/models/reverse_dns.rb +26 -0
- data/lib/mihari/models/whois.rb +119 -0
- data/lib/mihari/schemas/configuration.rb +1 -0
- data/lib/mihari/schemas/rule.rb +2 -15
- data/lib/mihari/serializers/alert.rb +6 -4
- data/lib/mihari/serializers/artifact.rb +11 -2
- data/lib/mihari/serializers/autonomous_system.rb +9 -0
- data/lib/mihari/serializers/dns.rb +11 -0
- data/lib/mihari/serializers/geolocation.rb +11 -0
- data/lib/mihari/serializers/reverse_dns.rb +11 -0
- data/lib/mihari/serializers/tag.rb +4 -2
- data/lib/mihari/serializers/whois.rb +11 -0
- data/lib/mihari/structs/censys.rb +92 -0
- data/lib/mihari/structs/ipinfo.rb +36 -0
- data/lib/mihari/structs/onyphe.rb +47 -0
- data/lib/mihari/structs/shodan.rb +53 -0
- data/lib/mihari/type_checker.rb +9 -9
- data/lib/mihari/types.rb +21 -0
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/app.rb +2 -0
- data/lib/mihari/web/controllers/alerts_controller.rb +3 -4
- data/lib/mihari/web/controllers/artifacts_controller.rb +73 -3
- data/lib/mihari/web/controllers/ip_address_controller.rb +21 -0
- data/lib/mihari/web/controllers/sources_controller.rb +2 -2
- data/lib/mihari/web/controllers/tags_controller.rb +3 -1
- data/lib/mihari/web/public/index.html +1 -1
- data/lib/mihari/web/public/redoc-static.html +14 -11
- data/lib/mihari/web/public/static/fonts/fa-brands-400.1a575a41.woff +0 -0
- data/lib/mihari/web/public/static/fonts/fa-brands-400.513aa607.ttf +0 -0
- data/lib/mihari/web/public/static/fonts/fa-brands-400.592643a8.eot +0 -0
- data/lib/mihari/web/public/static/fonts/fa-brands-400.ed311c7a.woff2 +0 -0
- data/lib/mihari/web/public/static/fonts/fa-regular-400.766913e6.ttf +0 -0
- data/lib/mihari/web/public/static/fonts/fa-regular-400.b0e2db3b.eot +0 -0
- data/lib/mihari/web/public/static/fonts/fa-regular-400.b91d376b.woff2 +0 -0
- data/lib/mihari/web/public/static/fonts/fa-regular-400.d1d7e3b4.woff +0 -0
- data/lib/mihari/web/public/static/fonts/fa-solid-900.0c6bfc66.eot +0 -0
- data/lib/mihari/web/public/static/fonts/fa-solid-900.b9625119.ttf +0 -0
- data/lib/mihari/web/public/static/fonts/fa-solid-900.d745348d.woff +0 -0
- data/lib/mihari/web/public/static/fonts/fa-solid-900.d824df7e.woff2 +0 -0
- data/lib/mihari/web/public/static/img/fa-brands-400.1d5619cd.svg +3717 -0
- data/lib/mihari/web/public/static/img/fa-regular-400.c5d109be.svg +801 -0
- data/lib/mihari/web/public/static/img/fa-solid-900.37bc7099.svg +5034 -0
- data/lib/mihari/web/public/static/js/app.06d5cf1c.js +36 -0
- data/lib/mihari/web/public/static/js/app.06d5cf1c.js.map +1 -0
- data/lib/mihari/web/public/static/js/app.8e3e5150.js +36 -0
- data/lib/mihari/web/public/static/js/app.8e3e5150.js.map +1 -0
- data/lib/mihari/web/public/static/js/app.b5914c39.js +36 -0
- data/lib/mihari/web/public/static/js/app.b5914c39.js.map +1 -0
- data/lib/mihari.rb +30 -4
- data/mihari.gemspec +10 -1
- data/sig/lib/mihari/analyzers/base.rbs +90 -0
- data/sig/lib/mihari/analyzers/basic.rbs +17 -0
- data/sig/lib/mihari/analyzers/binaryedge.rbs +25 -0
- data/sig/lib/mihari/analyzers/censys.rbs +38 -0
- data/sig/lib/mihari/analyzers/circl.rbs +29 -0
- data/sig/lib/mihari/analyzers/crtsh.rbs +19 -0
- data/sig/lib/mihari/analyzers/dnpedia.rbs +18 -0
- data/sig/lib/mihari/analyzers/dnstwister.rbs +27 -0
- data/sig/lib/mihari/analyzers/onyphe.rbs +33 -0
- data/sig/lib/mihari/analyzers/otx.rbs +33 -0
- data/sig/lib/mihari/analyzers/passivetotal.rbs +33 -0
- data/sig/lib/mihari/analyzers/pulsedive.rbs +27 -0
- data/sig/lib/mihari/analyzers/rule.rbs +68 -0
- data/sig/lib/mihari/analyzers/securitytrails.rbs +33 -0
- data/sig/lib/mihari/analyzers/shodan.rbs +33 -0
- data/sig/lib/mihari/analyzers/spyse.rbs +29 -0
- data/sig/lib/mihari/analyzers/urlscan.rbs +28 -0
- data/sig/lib/mihari/analyzers/virustotal.rbs +31 -0
- data/sig/lib/mihari/analyzers/zoomeye.rbs +33 -0
- data/sig/lib/mihari/cli/analyzer.rbs +39 -0
- data/sig/lib/mihari/cli/base.rbs +11 -0
- data/sig/lib/mihari/cli/init.rbs +7 -0
- data/sig/lib/mihari/cli/main.rbs +9 -0
- data/sig/lib/mihari/cli/mixins/utils.rbs +50 -0
- data/sig/lib/mihari/cli/validator.rbs +7 -0
- data/sig/lib/mihari/commands/binaryedge.rbs +7 -0
- data/sig/lib/mihari/commands/censys.rbs +7 -0
- data/sig/lib/mihari/commands/circl.rbs +7 -0
- data/sig/lib/mihari/commands/crtsh.rbs +7 -0
- data/sig/lib/mihari/commands/dnpedia.rbs +7 -0
- data/sig/lib/mihari/commands/dnstwister.rbs +7 -0
- data/sig/lib/mihari/commands/init.rbs +11 -0
- data/sig/lib/mihari/commands/json.rbs +7 -0
- data/sig/lib/mihari/commands/onyphe.rbs +7 -0
- data/sig/lib/mihari/commands/otx.rbs +7 -0
- data/sig/lib/mihari/commands/passivetotal.rbs +7 -0
- data/sig/lib/mihari/commands/pulsedive.rbs +7 -0
- data/sig/lib/mihari/commands/search.rbs +35 -0
- data/sig/lib/mihari/commands/securitytrails.rbs +7 -0
- data/sig/lib/mihari/commands/shodan.rbs +7 -0
- data/sig/lib/mihari/commands/spyse.rbs +7 -0
- data/sig/lib/mihari/commands/urlscan.rbs +7 -0
- data/sig/lib/mihari/commands/validator.rbs +11 -0
- data/sig/lib/mihari/commands/virustotal.rbs +7 -0
- data/sig/lib/mihari/commands/web.rbs +7 -0
- data/sig/lib/mihari/commands/zoomeye.rbs +7 -0
- data/sig/lib/mihari/constants.rbs +3 -0
- data/sig/lib/mihari/database.rbs +25 -0
- data/sig/lib/mihari/emitters/base.rbs +18 -0
- data/sig/lib/mihari/emitters/database.rbs +9 -0
- data/sig/lib/mihari/emitters/misp.rbs +28 -0
- data/sig/lib/mihari/emitters/slack.rbs +58 -0
- data/sig/lib/mihari/emitters/stdout.rbs +9 -0
- data/sig/lib/mihari/emitters/the_hive.rbs +24 -0
- data/sig/lib/mihari/emitters/webhook.rbs +20 -0
- data/sig/lib/mihari/enrichers/ipinfo.rbs +14 -0
- data/sig/lib/mihari/errors.rbs +10 -0
- data/sig/lib/mihari/mixins/autonomous_system.rbs +14 -0
- data/sig/lib/mihari/mixins/configurable.rbs +26 -0
- data/sig/lib/mihari/mixins/configuration.rbs +45 -0
- data/sig/lib/mihari/mixins/disallowed_data_value.rbs +25 -0
- data/sig/lib/mihari/mixins/hash.rbs +14 -0
- data/sig/lib/mihari/mixins/refang.rbs +14 -0
- data/sig/lib/mihari/mixins/retriable.rbs +15 -0
- data/sig/lib/mihari/mixins/rule.rbs +41 -0
- data/sig/lib/mihari/models/alert.rbs +46 -0
- data/sig/lib/mihari/models/artifact.rbs +65 -0
- data/sig/lib/mihari/models/autonomous_system.rbs +14 -0
- data/sig/lib/mihari/models/dns.rbs +19 -0
- data/sig/lib/mihari/models/geolocation.rbs +15 -0
- data/sig/lib/mihari/models/reverse_dns.rbs +14 -0
- data/sig/lib/mihari/models/tag.rbs +5 -0
- data/sig/lib/mihari/models/tagging.rbs +4 -0
- data/sig/lib/mihari/models/whois.rbs +66 -0
- data/sig/lib/mihari/notifiers/base.rbs +18 -0
- data/sig/lib/mihari/notifiers/exception_notifier.rbs +75 -0
- data/sig/lib/mihari/notifiers/slack.rbs +50 -0
- data/sig/lib/mihari/status.rbs +25 -0
- data/sig/lib/mihari/structs/censys.rbs +50 -0
- data/sig/lib/mihari/structs/ipinfo.rbs +17 -0
- data/sig/lib/mihari/structs/onyphe.rbs +25 -0
- data/sig/lib/mihari/structs/shodan.rbs +28 -0
- data/sig/lib/mihari/type_checker.rbs +48 -0
- data/sig/lib/mihari/types.rbs +17 -0
- data/sig/lib/mihari/version.rbs +3 -0
- data/sig/lib/mihari/web/app.rbs +5 -0
- data/sig/lib/mihari.rbs +57 -0
- metadata +259 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f6e9001e10ac0891e2e10d90bccbd165afbdfc3bcd2724a3d5adf521b2be843b
|
4
|
+
data.tar.gz: 98119fae9302eb4251ceda56c1ddb0ab615fbf36d67505fd8af2ffb08f1dcfaf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 92ae37318ffb97ab4746cb44c266e63fba5c505a6c81c141be362c11ecf4e399850f1921b2907bf511f6b0a4ea5884642282f319962af1628fc8bf9e69503fa8
|
7
|
+
data.tar.gz: 45f2a2a748bb362a0daa7f9c3c7da5329cb7bab002f1ddcec4a56d111102d311471b3904b2d77f50f406e05f43deeacbd8f235e5ff4ae2dd2a0096a4dd98074d
|
data/.gitmodules
ADDED
data/README.md
CHANGED
@@ -64,3 +64,5 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
64
64
|
## Acknowledgement
|
65
65
|
|
66
66
|
Mihari is proudly supported by [Tines.io](https://tines.io?utm_source=github&utm_medium=sponsorship&utm_campaign=ninoseki), The SOAR Platform for Enterprise Security Teams.
|
67
|
+
|
68
|
+
$ bundle exec rbs -rpathname --repo=gem_rbs/gems -ractivesupport -ractionpack -ractivejob -ractivemodel -ractionview -ractiverecord -rrailties -I sig validate
|
data/Steepfile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
target :lib do
|
2
|
+
signature "sig"
|
3
|
+
check "lib"
|
4
|
+
|
5
|
+
repo_path "vendor/rbs/gem_rbs_collection/gems"
|
6
|
+
|
7
|
+
library "date"
|
8
|
+
library "json"
|
9
|
+
library "logger"
|
10
|
+
library "monitor"
|
11
|
+
library "mutex_m"
|
12
|
+
library "pathname"
|
13
|
+
library "securerandom"
|
14
|
+
library "singleton"
|
15
|
+
library "time"
|
16
|
+
library "tsort"
|
17
|
+
library "uri"
|
18
|
+
library "resolv"
|
19
|
+
library "timeout"
|
20
|
+
library "socket"
|
21
|
+
|
22
|
+
library "rack"
|
23
|
+
|
24
|
+
library "actionpack"
|
25
|
+
library "actionview"
|
26
|
+
library "activejob"
|
27
|
+
library "activemodel"
|
28
|
+
library "activerecord"
|
29
|
+
library "activesupport"
|
30
|
+
library "parallel"
|
31
|
+
library "railties"
|
32
|
+
end
|
data/config.ru
CHANGED
@@ -8,6 +8,7 @@ module Mihari
|
|
8
8
|
class Base
|
9
9
|
extend Dry::Initializer
|
10
10
|
|
11
|
+
include Mixins::AutonomousSystem
|
11
12
|
include Mixins::Configurable
|
12
13
|
include Mixins::Retriable
|
13
14
|
|
@@ -27,7 +28,7 @@ module Mihari
|
|
27
28
|
|
28
29
|
# @return [String]
|
29
30
|
def title
|
30
|
-
self.class.to_s.split("::").last
|
31
|
+
self.class.to_s.split("::").last.to_s
|
31
32
|
end
|
32
33
|
|
33
34
|
# @return [String]
|
@@ -37,7 +38,7 @@ module Mihari
|
|
37
38
|
|
38
39
|
# @return [String]
|
39
40
|
def source
|
40
|
-
self.class.to_s.split("::").last
|
41
|
+
self.class.to_s.split("::").last.to_s
|
41
42
|
end
|
42
43
|
|
43
44
|
# @return [Array<String>]
|
@@ -51,7 +52,7 @@ module Mihari
|
|
51
52
|
# @return [nil]
|
52
53
|
#
|
53
54
|
def run
|
54
|
-
|
55
|
+
set_enriched_artifacts
|
55
56
|
|
56
57
|
Parallel.each(valid_emitters) do |emitter|
|
57
58
|
run_emitter emitter
|
@@ -66,7 +67,7 @@ module Mihari
|
|
66
67
|
# @return [nil]
|
67
68
|
#
|
68
69
|
def run_emitter(emitter)
|
69
|
-
emitter.run(title: title, description: description, artifacts:
|
70
|
+
emitter.run(title: title, description: description, artifacts: enriched_artifacts, source: source, tags: tags)
|
70
71
|
rescue StandardError => e
|
71
72
|
puts "Emission by #{emitter.class} is failed: #{e}"
|
72
73
|
end
|
@@ -88,7 +89,7 @@ module Mihari
|
|
88
89
|
# No need to set data_type manually
|
89
90
|
# It is set automatically in #initialize
|
90
91
|
artifact.is_a?(Artifact) ? artifact : Artifact.new(data: artifact, source: source)
|
91
|
-
end.select(&:valid?)
|
92
|
+
end.select(&:valid?).uniq(&:data)
|
92
93
|
end
|
93
94
|
|
94
95
|
private
|
@@ -105,15 +106,27 @@ module Mihari
|
|
105
106
|
end
|
106
107
|
|
107
108
|
#
|
108
|
-
#
|
109
|
+
# Enriched artifacts
|
110
|
+
#
|
111
|
+
# @return [Array<Mihari::Artifact>]
|
112
|
+
#
|
113
|
+
def enriched_artifacts
|
114
|
+
@enriched_artifacts ||= unique_artifacts.map do |artifact|
|
115
|
+
artifact.enrich_all
|
116
|
+
artifact
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
#
|
121
|
+
# Set enriched artifacts
|
109
122
|
#
|
110
123
|
# @return [nil]
|
111
124
|
#
|
112
|
-
def
|
113
|
-
retry_on_error {
|
114
|
-
rescue ArgumentError =>
|
125
|
+
def set_enriched_artifacts
|
126
|
+
retry_on_error { enriched_artifacts }
|
127
|
+
rescue ArgumentError => e
|
115
128
|
klass = self.class.to_s.split("::").last.to_s
|
116
|
-
raise Error, "Please configure #{klass}
|
129
|
+
raise Error, "Please configure #{klass} settings properly. (#{e})"
|
117
130
|
end
|
118
131
|
|
119
132
|
#
|
@@ -125,7 +138,7 @@ module Mihari
|
|
125
138
|
@valid_emitters ||= Mihari.emitters.filter_map do |klass|
|
126
139
|
emitter = klass.new
|
127
140
|
emitter.valid? ? emitter : nil
|
128
|
-
end
|
141
|
+
end.compact
|
129
142
|
end
|
130
143
|
end
|
131
144
|
end
|
@@ -26,6 +26,14 @@ module Mihari
|
|
26
26
|
|
27
27
|
PAGE_SIZE = 20
|
28
28
|
|
29
|
+
#
|
30
|
+
# Search with pagination
|
31
|
+
#
|
32
|
+
# @param [String] query
|
33
|
+
# @param [Integer] page
|
34
|
+
#
|
35
|
+
# @return [Hash]
|
36
|
+
#
|
29
37
|
def search_with_page(query, page: 1)
|
30
38
|
api.host.search(query, page: page)
|
31
39
|
rescue ::BinaryEdge::Error => e
|
@@ -34,6 +42,11 @@ module Mihari
|
|
34
42
|
raise e
|
35
43
|
end
|
36
44
|
|
45
|
+
#
|
46
|
+
# Search
|
47
|
+
#
|
48
|
+
# @return [Array<Hash>]
|
49
|
+
#
|
37
50
|
def search
|
38
51
|
responses = []
|
39
52
|
(1..Float::INFINITY).each do |page|
|
@@ -16,32 +16,65 @@ module Mihari
|
|
16
16
|
|
17
17
|
private
|
18
18
|
|
19
|
+
#
|
20
|
+
# Search
|
21
|
+
#
|
22
|
+
# @return [Array<String>]
|
23
|
+
#
|
19
24
|
def search
|
20
|
-
|
25
|
+
artifacts = []
|
21
26
|
|
22
27
|
cursor = nil
|
23
28
|
loop do
|
24
29
|
response = api.search(query, cursor: cursor)
|
25
|
-
|
30
|
+
response = Structs::Censys::Response.from_dynamic!(response)
|
26
31
|
|
27
|
-
|
28
|
-
|
32
|
+
artifacts << response_to_artifacts(response)
|
33
|
+
|
34
|
+
cursor = response.result.links.next
|
29
35
|
break if cursor == ""
|
30
36
|
end
|
31
37
|
|
32
|
-
|
38
|
+
artifacts.flatten.uniq(&:data)
|
33
39
|
end
|
34
40
|
|
35
41
|
#
|
36
42
|
# Extract IPv4s from Censys search API response
|
37
43
|
#
|
38
|
-
# @param [
|
44
|
+
# @param [Structs::Censys::Response] response
|
39
45
|
#
|
40
46
|
# @return [Array<String>]
|
41
47
|
#
|
42
|
-
def
|
43
|
-
hits
|
44
|
-
|
48
|
+
def response_to_artifacts(response)
|
49
|
+
response.result.hits.map { |hit| build_artifact(hit) }
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Build an artifact from a Shodan search API response
|
54
|
+
#
|
55
|
+
# @param [Structs::Censys::Hit] hit
|
56
|
+
#
|
57
|
+
# @return [Artifact]
|
58
|
+
#
|
59
|
+
def build_artifact(hit)
|
60
|
+
as = AutonomousSystem.new(asn: normalize_asn(hit.autonomous_system.asn))
|
61
|
+
|
62
|
+
# sometimes Censys overlooks country
|
63
|
+
# then set geolocation as nil
|
64
|
+
geolocation = nil
|
65
|
+
unless hit.location.country.nil?
|
66
|
+
geolocation = Geolocation.new(
|
67
|
+
country: hit.location.country,
|
68
|
+
country_code: hit.location.country_code
|
69
|
+
)
|
70
|
+
end
|
71
|
+
|
72
|
+
Artifact.new(
|
73
|
+
data: hit.ip,
|
74
|
+
source: source,
|
75
|
+
autonomous_system: as,
|
76
|
+
geolocation: geolocation
|
77
|
+
)
|
45
78
|
end
|
46
79
|
|
47
80
|
def configuration_keys
|
@@ -35,6 +35,11 @@ module Mihari
|
|
35
35
|
@api ||= ::PassiveCIRCL::API.new(username: Mihari.config.circl_passive_username, password: Mihari.config.circl_passive_password)
|
36
36
|
end
|
37
37
|
|
38
|
+
#
|
39
|
+
# Passive DNS/SSL search
|
40
|
+
#
|
41
|
+
# @return [Array<String>]
|
42
|
+
#
|
38
43
|
def search
|
39
44
|
case @type
|
40
45
|
when "domain"
|
@@ -46,6 +51,11 @@ module Mihari
|
|
46
51
|
end
|
47
52
|
end
|
48
53
|
|
54
|
+
#
|
55
|
+
# Passive DNS search
|
56
|
+
#
|
57
|
+
# @return [Array<String>]
|
58
|
+
#
|
49
59
|
def passive_dns_search
|
50
60
|
results = api.dns.query(@query)
|
51
61
|
results.filter_map do |result|
|
@@ -54,6 +64,11 @@ module Mihari
|
|
54
64
|
end.uniq
|
55
65
|
end
|
56
66
|
|
67
|
+
#
|
68
|
+
# Passive SSL search
|
69
|
+
#
|
70
|
+
# @return [Array<String>]
|
71
|
+
#
|
57
72
|
def passive_ssl_search
|
58
73
|
result = api.ssl.cquery(@query)
|
59
74
|
seen = result["seen"] || []
|
@@ -29,6 +29,11 @@ module Mihari
|
|
29
29
|
|
30
30
|
private
|
31
31
|
|
32
|
+
#
|
33
|
+
# Check whether a type is valid or not
|
34
|
+
#
|
35
|
+
# @return [Boolean]
|
36
|
+
#
|
32
37
|
def valid_type?
|
33
38
|
type == "domain"
|
34
39
|
end
|
@@ -37,6 +42,13 @@ module Mihari
|
|
37
42
|
@api ||= ::DNSTwister::API.new
|
38
43
|
end
|
39
44
|
|
45
|
+
#
|
46
|
+
# Check whether a domain is resolvable or not
|
47
|
+
#
|
48
|
+
# @param [String] domain
|
49
|
+
#
|
50
|
+
# @return [Boolean]
|
51
|
+
#
|
40
52
|
def resolvable?(domain)
|
41
53
|
Resolv.getaddress domain
|
42
54
|
true
|
@@ -44,6 +56,11 @@ module Mihari
|
|
44
56
|
false
|
45
57
|
end
|
46
58
|
|
59
|
+
#
|
60
|
+
# Search
|
61
|
+
#
|
62
|
+
# @return [Array<String>]
|
63
|
+
#
|
47
64
|
def search
|
48
65
|
raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
|
49
66
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "onyphe"
|
4
|
+
require "normalize_country"
|
4
5
|
|
5
6
|
module Mihari
|
6
7
|
module Analyzers
|
@@ -11,14 +12,13 @@ module Mihari
|
|
11
12
|
option :tags, default: proc { [] }
|
12
13
|
|
13
14
|
def artifacts
|
14
|
-
|
15
|
-
return [] unless
|
15
|
+
responses = search
|
16
|
+
return [] unless responses
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
flat_results.filter_map { |result| result["ip"] }.uniq
|
18
|
+
results = responses.map(&:results).flatten
|
19
|
+
results.map do |result|
|
20
|
+
build_artifact result
|
21
|
+
end
|
22
22
|
end
|
23
23
|
|
24
24
|
private
|
@@ -33,20 +33,61 @@ module Mihari
|
|
33
33
|
@api ||= ::Onyphe::API.new(Mihari.config.onyphe_api_key)
|
34
34
|
end
|
35
35
|
|
36
|
+
#
|
37
|
+
# Search with pagination
|
38
|
+
#
|
39
|
+
# @param [String] query
|
40
|
+
# @param [Integer] page
|
41
|
+
#
|
42
|
+
# @return [Structs::Onyphe::Response]
|
43
|
+
#
|
36
44
|
def search_with_page(query, page: 1)
|
37
|
-
api.simple.datascan(query, page: page)
|
45
|
+
res = api.simple.datascan(query, page: page)
|
46
|
+
Structs::Onyphe::Response.from_dynamic!(res)
|
38
47
|
end
|
39
48
|
|
49
|
+
#
|
50
|
+
# Search
|
51
|
+
#
|
52
|
+
# @return [Array<Structs::Onyphe::Response>]
|
53
|
+
#
|
40
54
|
def search
|
41
55
|
responses = []
|
42
56
|
(1..Float::INFINITY).each do |page|
|
43
57
|
res = search_with_page(query, page: page)
|
44
58
|
responses << res
|
45
|
-
|
59
|
+
|
60
|
+
total = res.total
|
46
61
|
break if total <= page * PAGE_SIZE
|
47
62
|
end
|
48
63
|
responses
|
49
64
|
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Build an artifact from an Onyphe search API result
|
68
|
+
#
|
69
|
+
# @param [Structs::Onyphe::Result] result
|
70
|
+
#
|
71
|
+
# @return [Artifact]
|
72
|
+
#
|
73
|
+
def build_artifact(result)
|
74
|
+
as = AutonomousSystem.new(asn: normalize_asn(result.asn))
|
75
|
+
|
76
|
+
geolocation = nil
|
77
|
+
unless result.country_code.nil?
|
78
|
+
geolocation = Geolocation.new(
|
79
|
+
country: NormalizeCountry(result.country_code, to: :short),
|
80
|
+
country_code: result.country_code
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
Artifact.new(
|
85
|
+
data: result.ip,
|
86
|
+
source: source,
|
87
|
+
autonomous_system: as,
|
88
|
+
geolocation: geolocation
|
89
|
+
)
|
90
|
+
end
|
50
91
|
end
|
51
92
|
end
|
52
93
|
end
|