mihari 6.3.0 → 7.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/.gitignore +4 -10
- data/.rubocop.yml +2 -0
- data/Dockerfile +13 -0
- data/config.ru +5 -3
- data/docker-compose.yml +62 -0
- data/exe/mihari +2 -1
- data/lefthook.yml +8 -0
- data/lib/mihari/actor.rb +4 -4
- data/lib/mihari/analyzers/base.rb +16 -0
- data/lib/mihari/analyzers/binaryedge.rb +4 -2
- data/lib/mihari/analyzers/censys.rb +7 -5
- data/lib/mihari/analyzers/circl.rb +5 -3
- data/lib/mihari/analyzers/crtsh.rb +4 -1
- data/lib/mihari/analyzers/dnstwister.rb +1 -1
- data/lib/mihari/analyzers/feed.rb +12 -20
- data/lib/mihari/analyzers/fofa.rb +6 -8
- data/lib/mihari/analyzers/greynoise.rb +4 -2
- data/lib/mihari/analyzers/hunterhow.rb +4 -2
- data/lib/mihari/analyzers/onyphe.rb +4 -2
- data/lib/mihari/analyzers/otx.rb +5 -3
- data/lib/mihari/analyzers/passivetotal.rb +29 -12
- data/lib/mihari/analyzers/pulsedive.rb +5 -3
- data/lib/mihari/analyzers/securitytrails.rb +32 -8
- data/lib/mihari/analyzers/shodan.rb +4 -2
- data/lib/mihari/analyzers/urlscan.rb +4 -2
- data/lib/mihari/analyzers/virustotal.rb +5 -5
- data/lib/mihari/analyzers/virustotal_intelligence.rb +4 -2
- data/lib/mihari/analyzers/zoomeye.rb +4 -2
- data/lib/mihari/cli/{main.rb → application.rb} +17 -5
- data/lib/mihari/cli/artifact.rb +14 -0
- data/lib/mihari/cli/config.rb +14 -0
- data/lib/mihari/cli/rule.rb +1 -0
- data/lib/mihari/cli/tag.rb +14 -0
- data/lib/mihari/clients/base.rb +2 -2
- data/lib/mihari/clients/binaryedge.rb +2 -2
- data/lib/mihari/clients/crtsh.rb +2 -9
- data/lib/mihari/clients/fofa.rb +1 -1
- data/lib/mihari/clients/hunterhow.rb +1 -1
- data/lib/mihari/clients/mmdb.rb +28 -0
- data/lib/mihari/clients/passivetotal.rb +7 -20
- data/lib/mihari/clients/securitytrails.rb +19 -43
- data/lib/mihari/clients/shodan_internet_db.rb +28 -0
- data/lib/mihari/clients/the_hive.rb +7 -5
- data/lib/mihari/commands/alert.rb +53 -11
- data/lib/mihari/commands/artifact.rb +66 -0
- data/lib/mihari/commands/config.rb +23 -0
- data/lib/mihari/commands/database.rb +1 -1
- data/lib/mihari/commands/rule.rb +40 -27
- data/lib/mihari/commands/search.rb +10 -11
- data/lib/mihari/commands/sidekiq.rb +31 -0
- data/lib/mihari/commands/tag.rb +46 -0
- data/lib/mihari/commands/web.rb +6 -7
- data/lib/mihari/{mixins/autonomous_system.rb → concerns/autonomous_system_normalizable.rb} +5 -3
- data/lib/mihari/concerns/configurable.rb +72 -0
- data/lib/mihari/concerns/database_connectable.rb +16 -0
- data/lib/mihari/{mixins/unwrap_error.rb → concerns/error_unwrappable.rb} +5 -3
- data/lib/mihari/{mixins/falsepositive.rb → concerns/falsepositive_validatable.rb} +5 -3
- data/lib/mihari/{mixins/refang.rb → concerns/refangable.rb} +5 -3
- data/lib/mihari/{mixins → concerns}/retriable.rb +4 -2
- data/lib/mihari/config.rb +13 -12
- data/lib/mihari/database.rb +30 -42
- data/lib/mihari/emitters/database.rb +5 -6
- data/lib/mihari/emitters/misp.rb +4 -11
- data/lib/mihari/emitters/slack.rb +7 -5
- data/lib/mihari/emitters/the_hive.rb +8 -58
- data/lib/mihari/emitters/webhook.rb +6 -6
- data/lib/mihari/enrichers/google_public_dns.rb +1 -1
- data/lib/mihari/enrichers/mmdb.rb +28 -0
- data/lib/mihari/enrichers/shodan.rb +3 -5
- data/lib/mihari/enrichers/whois.rb +3 -3
- data/lib/mihari/entities/alert.rb +3 -10
- data/lib/mihari/entities/artifact.rb +6 -14
- data/lib/mihari/entities/config.rb +2 -2
- data/lib/mihari/entities/cpe.rb +1 -0
- data/lib/mihari/entities/dns.rb +1 -0
- data/lib/mihari/entities/geolocation.rb +1 -0
- data/lib/mihari/entities/ip_address.rb +1 -3
- data/lib/mihari/entities/messages.rb +17 -0
- data/lib/mihari/entities/pagination.rb +11 -0
- data/lib/mihari/entities/port.rb +1 -0
- data/lib/mihari/entities/reverse_dns.rb +1 -0
- data/lib/mihari/entities/rule.rb +2 -20
- data/lib/mihari/entities/tag.rb +2 -2
- data/lib/mihari/entities/whois.rb +1 -0
- data/lib/mihari/errors.rb +2 -4
- data/lib/mihari/http.rb +4 -0
- data/lib/mihari/models/alert.rb +21 -53
- data/lib/mihari/models/artifact.rb +46 -88
- data/lib/mihari/models/autonomous_system.rb +5 -13
- data/lib/mihari/models/concerns/searchable.rb +50 -0
- data/lib/mihari/models/cpe.rb +3 -10
- data/lib/mihari/models/dns.rb +2 -6
- data/lib/mihari/models/geolocation.rb +7 -12
- data/lib/mihari/models/port.rb +3 -10
- data/lib/mihari/models/reverse_dns.rb +3 -8
- data/lib/mihari/models/rule.rb +16 -57
- data/lib/mihari/models/tag.rb +17 -1
- data/lib/mihari/models/tagging.rb +1 -1
- data/lib/mihari/models/whois.rb +1 -4
- data/lib/mihari/rule.rb +35 -24
- data/lib/mihari/schemas/alert.rb +1 -0
- data/lib/mihari/schemas/analyzer.rb +2 -2
- data/lib/mihari/schemas/concerns/orrable.rb +24 -0
- data/lib/mihari/schemas/emitter.rb +1 -2
- data/lib/mihari/schemas/enricher.rb +3 -4
- data/lib/mihari/schemas/macros.rb +1 -1
- data/lib/mihari/schemas/options.rb +0 -2
- data/lib/mihari/schemas/rule.rb +1 -2
- data/lib/mihari/services/{rule_builder.rb → builders.rb} +1 -6
- data/lib/mihari/services/creators.rb +22 -0
- data/lib/mihari/services/destroyers.rb +41 -0
- data/lib/mihari/services/enrichers.rb +25 -0
- data/lib/mihari/services/feed.rb +107 -0
- data/lib/mihari/services/getters.rb +58 -0
- data/lib/mihari/services/initializers.rb +22 -0
- data/lib/mihari/services/{alert_builder.rb → proxies.rb} +10 -40
- data/lib/mihari/services/searchers.rb +91 -0
- data/lib/mihari/sidekiq/application.rb +13 -0
- data/lib/mihari/sidekiq/jobs.rb +36 -0
- data/lib/mihari/structs/censys.rb +1 -1
- data/lib/mihari/structs/config.rb +10 -10
- data/lib/mihari/structs/filters.rb +12 -130
- data/lib/mihari/structs/google_public_dns.rb +1 -1
- data/lib/mihari/structs/greynoise.rb +1 -1
- data/lib/mihari/structs/mmdb.rb +115 -0
- data/lib/mihari/structs/onyphe.rb +1 -1
- data/lib/mihari/structs/shodan.rb +2 -2
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/{app.rb → application.rb} +28 -15
- data/lib/mihari/web/endpoints/alerts.rb +34 -73
- data/lib/mihari/web/endpoints/artifacts.rb +27 -111
- data/lib/mihari/web/endpoints/configs.rb +3 -5
- data/lib/mihari/web/endpoints/ip_addresses.rb +14 -15
- data/lib/mihari/web/endpoints/rules.rb +58 -130
- data/lib/mihari/web/endpoints/tags.rb +21 -17
- data/lib/mihari/web/middleware/capture_exceptions.rb +25 -0
- data/lib/mihari/web/middleware/{connection_adapter.rb → connection.rb} +4 -2
- data/lib/mihari/web/public/assets/index-cQUcyII5.js +1766 -0
- data/lib/mihari/web/public/assets/index-dVaNxqTC.css +1 -0
- data/lib/mihari/web/public/index.html +2 -2
- data/lib/mihari/web/public/redoc-static.html +385 -385
- data/lib/mihari.rb +56 -28
- data/mihari.gemspec +12 -4
- data/mkdocs.yml +5 -2
- data/requirements.txt +1 -1
- metadata +164 -34
- data/lib/mihari/commands/mixins.rb +0 -11
- data/lib/mihari/enrichers/ipinfo.rb +0 -52
- data/lib/mihari/entities/message.rb +0 -9
- data/lib/mihari/feed/parser.rb +0 -38
- data/lib/mihari/feed/reader.rb +0 -111
- data/lib/mihari/mixins/configurable.rb +0 -68
- data/lib/mihari/schemas/mixins.rb +0 -20
- data/lib/mihari/services/alert_runner.rb +0 -20
- data/lib/mihari/structs/ipinfo.rb +0 -53
- data/lib/mihari/web/endpoints/exports.rb +0 -0
- data/lib/mihari/web/middleware/error_notification_adapter.rb +0 -35
- data/lib/mihari/web/public/assets/index-81613_nX.js +0 -1763
- data/lib/mihari/web/public/assets/index-Wv6xUrTI.css +0 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c3f4b3b5ca761f5ca5e6f3697593f8253b1e6aa03f21924726ad5dc78ac3f011
|
|
4
|
+
data.tar.gz: f673dd7775f31c2fa134102c8cf9707e0d6fc74467f496c86202de43db7b3c5a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0f139c2a0795bd6e741ce93681f8be47cb75fcb5b707d187d1fd2c758bfe2877388d0d5a25fe5920ec2e7565532c142b585b0029816899664426becea2f0776c
|
|
7
|
+
data.tar.gz: 6dad7972edcba2090bfa12170539efcd51a20dc1ba94757383546ae630002d374e33dcdbc99675cc719801a80b92a11d2eff308a553d627050f8596d6a877c9a
|
data/.gitignore
CHANGED
|
@@ -52,20 +52,14 @@ Gemfile.lock
|
|
|
52
52
|
# rspec
|
|
53
53
|
.rspec_status
|
|
54
54
|
|
|
55
|
-
# solargraph
|
|
56
|
-
.solargraph.yml
|
|
57
|
-
|
|
58
55
|
# SQLite
|
|
59
56
|
*.db
|
|
60
57
|
*.db-shm
|
|
61
58
|
*.db-wal
|
|
62
59
|
|
|
63
|
-
# Config
|
|
64
|
-
mihari.yml
|
|
65
|
-
|
|
66
|
-
# Rule
|
|
67
|
-
rule.yml
|
|
68
|
-
!lib/mihari/templates/rule.yml
|
|
69
|
-
|
|
70
60
|
# Frontend assets
|
|
71
61
|
lib/mihari/web/public/
|
|
62
|
+
|
|
63
|
+
# Rules & Alerts
|
|
64
|
+
rules/
|
|
65
|
+
alerts/
|
data/.rubocop.yml
CHANGED
data/Dockerfile
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
FROM ruby:3.2.2-alpine3.19
|
|
2
|
+
|
|
3
|
+
ARG MIHARI_VERSION=0.0.0
|
|
4
|
+
|
|
5
|
+
RUN apk --no-cache add git build-base ruby-dev postgresql-dev && \
|
|
6
|
+
gem install pg && \
|
|
7
|
+
gem install mihari -v ${MIHARI_VERSION} && \
|
|
8
|
+
apk del --purge git build-base ruby-dev && \
|
|
9
|
+
rm -rf /usr/local/bundle/cache/*
|
|
10
|
+
|
|
11
|
+
ENTRYPOINT ["mihari"]
|
|
12
|
+
|
|
13
|
+
CMD ["--help"]
|
data/config.ru
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
$LOAD_PATH.unshift("#{__dir__}/../lib")
|
|
2
|
+
|
|
3
|
+
require "mihari"
|
|
4
|
+
require "mihari/web/application"
|
|
2
5
|
|
|
3
6
|
require "better_errors"
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
ENV["RACK_ENV"] ||= "development"
|
|
8
|
+
ENV["APP_ENV"] ||= "development"
|
|
7
9
|
|
|
8
10
|
run Mihari::Web::App.instance
|
data/docker-compose.yml
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
version: "3"
|
|
2
|
+
services:
|
|
3
|
+
database:
|
|
4
|
+
image: postgres:16
|
|
5
|
+
volumes:
|
|
6
|
+
- postgresql:/var/lib/postgresql/data
|
|
7
|
+
ports:
|
|
8
|
+
- ${POSTGRES_PORT:-5432}:5432
|
|
9
|
+
environment:
|
|
10
|
+
- POSTGRES_USER=${POSTGRES_USER:-user}
|
|
11
|
+
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-password}
|
|
12
|
+
- POSTGRES_DB=${POSTGRES_DB:-mihari}
|
|
13
|
+
restart: always
|
|
14
|
+
|
|
15
|
+
redis:
|
|
16
|
+
image: "redis/redis-stack:6.2.6-v10"
|
|
17
|
+
restart: always
|
|
18
|
+
ports:
|
|
19
|
+
- ${REDIS_PORT:-6379}:6379
|
|
20
|
+
- ${REDIS_INSIGHT_PORT:-8001}:8001
|
|
21
|
+
volumes:
|
|
22
|
+
- redis:/data
|
|
23
|
+
|
|
24
|
+
mihari-init:
|
|
25
|
+
image: ghcr.io/ninoseki/mihari:latest
|
|
26
|
+
environment:
|
|
27
|
+
- DATABASE_URL=${DATABASE_URL:-postgresql://${POSTGRES_USER:-user}:${POSTGRES_PASSWORD:-password}@database:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-mihari}}
|
|
28
|
+
entrypoint: ["mihari", "db", "migrate"]
|
|
29
|
+
depends_on:
|
|
30
|
+
- database
|
|
31
|
+
|
|
32
|
+
mihari:
|
|
33
|
+
image: ghcr.io/ninoseki/mihari:latest
|
|
34
|
+
ports:
|
|
35
|
+
- ${MIHARI_PORT:-9292}:9292
|
|
36
|
+
environment:
|
|
37
|
+
- DATABASE_URL=${DATABASE_URL:-postgresql://${POSTGRES_USER:-user}:${POSTGRES_PASSWORD:-password}@database:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-mihari}}
|
|
38
|
+
- REDIS_URL=${REDIS_URL:-redis://redis:${REDIS_PORT:-6379}}
|
|
39
|
+
env_file:
|
|
40
|
+
- .env
|
|
41
|
+
entrypoint: ["mihari", "web", "--host", "0.0.0.0"]
|
|
42
|
+
restart: always
|
|
43
|
+
depends_on:
|
|
44
|
+
- mihari-init
|
|
45
|
+
|
|
46
|
+
sidekiq:
|
|
47
|
+
image: ghcr.io/ninoseki/mihari:latest
|
|
48
|
+
environment:
|
|
49
|
+
- DATABASE_URL=${DATABASE_URL:-postgresql://${POSTGRES_USER:-user}:${POSTGRES_PASSWORD:-password}@database:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-mihari}}
|
|
50
|
+
- REDIS_URL=${REDIS_URL:-redis://redis:${REDIS_PORT:-6379}}
|
|
51
|
+
- USE_SIDEKIQ=true
|
|
52
|
+
env_file:
|
|
53
|
+
- .env
|
|
54
|
+
entrypoint: ["mihari", "sidekiq"]
|
|
55
|
+
restart: always
|
|
56
|
+
depends_on:
|
|
57
|
+
- mihari-init
|
|
58
|
+
- redis
|
|
59
|
+
|
|
60
|
+
volumes:
|
|
61
|
+
postgresql:
|
|
62
|
+
redis:
|
data/exe/mihari
CHANGED
data/lefthook.yml
CHANGED
|
@@ -10,3 +10,11 @@ pre-commit:
|
|
|
10
10
|
glob: "*.{js,ts,vue}"
|
|
11
11
|
run: npx eslint --fix {staged_files}
|
|
12
12
|
stage_fixed: true
|
|
13
|
+
prettier:
|
|
14
|
+
root: "frontend/"
|
|
15
|
+
glob: "*.{js,ts,vue}"
|
|
16
|
+
run: npx prettier --write {staged_files}
|
|
17
|
+
stage_fixed: true
|
|
18
|
+
actionlint:
|
|
19
|
+
glob: ".github/workflows/*.yaml"
|
|
20
|
+
run: actionlint
|
data/lib/mihari/actor.rb
CHANGED
|
@@ -7,8 +7,8 @@ module Mihari
|
|
|
7
7
|
class Actor
|
|
8
8
|
include Dry::Monads[:result, :try]
|
|
9
9
|
|
|
10
|
-
include
|
|
11
|
-
include
|
|
10
|
+
include Concerns::Configurable
|
|
11
|
+
include Concerns::Retriable
|
|
12
12
|
|
|
13
13
|
# @return [Hash]
|
|
14
14
|
attr_reader :options
|
|
@@ -53,8 +53,8 @@ module Mihari
|
|
|
53
53
|
def validate_configuration!
|
|
54
54
|
return if configured?
|
|
55
55
|
|
|
56
|
-
joined = configuration_keys.join(", ")
|
|
57
|
-
be = (configuration_keys.length > 1) ? "are" : "is"
|
|
56
|
+
joined = self.class.configuration_keys.join(", ")
|
|
57
|
+
be = (self.class.configuration_keys.length > 1) ? "are" : "is"
|
|
58
58
|
message = "#{self.class.class_key} is not configured correctly. #{joined} #{be} missing."
|
|
59
59
|
raise ConfigurationError, message
|
|
60
60
|
end
|
|
@@ -79,6 +79,22 @@ module Mihari
|
|
|
79
79
|
normalized_artifacts
|
|
80
80
|
end
|
|
81
81
|
|
|
82
|
+
def result(...)
|
|
83
|
+
res = Try[StandardError] do
|
|
84
|
+
retry_on_error(
|
|
85
|
+
times: retry_times,
|
|
86
|
+
interval: retry_interval,
|
|
87
|
+
exponential_backoff: retry_exponential_backoff
|
|
88
|
+
) do
|
|
89
|
+
call(...)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
return res.recover { [] } if ignore_error?
|
|
94
|
+
|
|
95
|
+
res.to_result
|
|
96
|
+
end
|
|
97
|
+
|
|
82
98
|
class << self
|
|
83
99
|
#
|
|
84
100
|
# Initialize an analyzer by query params
|
|
@@ -24,8 +24,10 @@ module Mihari
|
|
|
24
24
|
client.search_with_pagination(query, pagination_limit: pagination_limit).map(&:artifacts).flatten
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
class << self
|
|
28
|
+
def configuration_keys
|
|
29
|
+
%w[binaryedge_api_key]
|
|
30
|
+
end
|
|
29
31
|
end
|
|
30
32
|
|
|
31
33
|
private
|
|
@@ -41,11 +41,13 @@ module Mihari
|
|
|
41
41
|
configuration_keys? || (id? && secret?)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
class << self
|
|
45
|
+
#
|
|
46
|
+
# @return [Array<String>]
|
|
47
|
+
#
|
|
48
|
+
def configuration_keys
|
|
49
|
+
%w[censys_id censys_secret]
|
|
50
|
+
end
|
|
49
51
|
end
|
|
50
52
|
|
|
51
53
|
private
|
|
@@ -6,7 +6,7 @@ module Mihari
|
|
|
6
6
|
# CIRCL passive DNS/SSL analyzer
|
|
7
7
|
#
|
|
8
8
|
class CIRCL < Base
|
|
9
|
-
include
|
|
9
|
+
include Concerns::Refangable
|
|
10
10
|
|
|
11
11
|
# @return [String, nil]
|
|
12
12
|
attr_reader :type
|
|
@@ -47,8 +47,10 @@ module Mihari
|
|
|
47
47
|
configuration_keys? || (username? && password?)
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
class << self
|
|
51
|
+
def configuration_keys
|
|
52
|
+
%w[circl_passive_password circl_passive_username]
|
|
53
|
+
end
|
|
52
54
|
end
|
|
53
55
|
|
|
54
56
|
private
|
|
@@ -22,7 +22,10 @@ module Mihari
|
|
|
22
22
|
|
|
23
23
|
def artifacts
|
|
24
24
|
exclude = exclude_expired ? "expired" : nil
|
|
25
|
-
client.search(query, exclude: exclude)
|
|
25
|
+
client.search(query, exclude: exclude).map do |result|
|
|
26
|
+
values = result["name_value"].to_s.lines.map(&:chomp).reject { |value| value.starts_with?("*.") }
|
|
27
|
+
values.map { |value| Models::Artifact.new(data: value, metadata: result) }
|
|
28
|
+
end.flatten
|
|
26
29
|
end
|
|
27
30
|
|
|
28
31
|
private
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "mihari/feed/reader"
|
|
4
|
-
require "mihari/feed/parser"
|
|
5
|
-
|
|
6
3
|
module Mihari
|
|
7
4
|
module Analyzers
|
|
8
5
|
#
|
|
@@ -10,7 +7,7 @@ module Mihari
|
|
|
10
7
|
#
|
|
11
8
|
class Feed < Base
|
|
12
9
|
# @return [Hash, nil]
|
|
13
|
-
attr_reader :
|
|
10
|
+
attr_reader :form
|
|
14
11
|
|
|
15
12
|
# @return [Hash, nil]
|
|
16
13
|
attr_reader :json
|
|
@@ -37,37 +34,32 @@ module Mihari
|
|
|
37
34
|
# @param [Hash, nil] headers
|
|
38
35
|
# @param [Hash, nil] params
|
|
39
36
|
# @param [Hash, nil] json
|
|
40
|
-
# @param [
|
|
37
|
+
# @param [form, nil] form
|
|
41
38
|
# @param [String] selector
|
|
42
39
|
#
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
# @param [Object] url
|
|
41
|
+
def initialize(url, options: nil, method: "GET", headers: nil, params: nil, json: nil, form: nil, selector: "")
|
|
42
|
+
super(url, options: options)
|
|
45
43
|
|
|
46
44
|
@method = method
|
|
47
45
|
@headers = headers || {}
|
|
48
46
|
@params = params
|
|
49
47
|
@json = json
|
|
50
|
-
@
|
|
48
|
+
@form = form
|
|
51
49
|
@selector = selector
|
|
52
50
|
end
|
|
53
51
|
|
|
54
52
|
def artifacts
|
|
55
|
-
|
|
53
|
+
data = Services::FeedReader.call(
|
|
54
|
+
url, headers: headers, method: method, params: params, json: json, form: form, timeout: timeout
|
|
55
|
+
)
|
|
56
|
+
Services::FeedParser.call(data, selector)
|
|
56
57
|
end
|
|
57
58
|
|
|
58
59
|
private
|
|
59
60
|
|
|
60
|
-
def
|
|
61
|
-
|
|
62
|
-
query,
|
|
63
|
-
method: method,
|
|
64
|
-
headers: headers,
|
|
65
|
-
timeout: timeout,
|
|
66
|
-
params: params,
|
|
67
|
-
json: json,
|
|
68
|
-
data: data
|
|
69
|
-
)
|
|
70
|
-
reader.read
|
|
61
|
+
def url
|
|
62
|
+
query
|
|
71
63
|
end
|
|
72
64
|
end
|
|
73
65
|
end
|
|
@@ -31,20 +31,18 @@ module Mihari
|
|
|
31
31
|
end.flatten.compact
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
def configuration_keys
|
|
35
|
-
%w[fofa_api_key fofa_email]
|
|
36
|
-
end
|
|
37
|
-
|
|
38
34
|
def configured?
|
|
39
35
|
api_key? && email?
|
|
40
36
|
end
|
|
41
37
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
class << self
|
|
39
|
+
def configuration_keys
|
|
40
|
+
%w[fofa_api_key fofa_email]
|
|
41
|
+
end
|
|
46
42
|
end
|
|
47
43
|
|
|
44
|
+
private
|
|
45
|
+
|
|
48
46
|
def email?
|
|
49
47
|
!email.nil?
|
|
50
48
|
end
|
data/lib/mihari/analyzers/otx.rb
CHANGED
|
@@ -6,7 +6,7 @@ module Mihari
|
|
|
6
6
|
# OTX analyzer
|
|
7
7
|
#
|
|
8
8
|
class OTX < Base
|
|
9
|
-
include
|
|
9
|
+
include Concerns::Refangable
|
|
10
10
|
|
|
11
11
|
# @return [String, nil]
|
|
12
12
|
attr_reader :type
|
|
@@ -38,8 +38,10 @@ module Mihari
|
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
class << self
|
|
42
|
+
def configuration_keys
|
|
43
|
+
%w[otx_api_key]
|
|
44
|
+
end
|
|
43
45
|
end
|
|
44
46
|
|
|
45
47
|
private
|
|
@@ -6,7 +6,7 @@ module Mihari
|
|
|
6
6
|
# PassiveTotal analyzer
|
|
7
7
|
#
|
|
8
8
|
class PassiveTotal < Base
|
|
9
|
-
include
|
|
9
|
+
include Concerns::Refangable
|
|
10
10
|
|
|
11
11
|
# @return [String, nil]
|
|
12
12
|
attr_reader :type
|
|
@@ -35,11 +35,11 @@ module Mihari
|
|
|
35
35
|
def artifacts
|
|
36
36
|
case type
|
|
37
37
|
when "domain", "ip"
|
|
38
|
-
|
|
38
|
+
passive_dns_search
|
|
39
39
|
when "mail"
|
|
40
|
-
|
|
40
|
+
reverse_whois_search
|
|
41
41
|
when "hash"
|
|
42
|
-
|
|
42
|
+
ssl_search
|
|
43
43
|
else
|
|
44
44
|
raise ValueError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
|
|
45
45
|
end
|
|
@@ -49,11 +49,11 @@ module Mihari
|
|
|
49
49
|
configuration_keys? || (username? && api_key?)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
def configuration_keys
|
|
53
|
-
%w[passivetotal_username passivetotal_api_key]
|
|
54
|
-
end
|
|
55
|
-
|
|
56
52
|
class << self
|
|
53
|
+
def configuration_keys
|
|
54
|
+
%w[passivetotal_username passivetotal_api_key]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
57
|
#
|
|
58
58
|
# @return [Array<String>, nil]
|
|
59
59
|
#
|
|
@@ -64,6 +64,27 @@ module Mihari
|
|
|
64
64
|
|
|
65
65
|
private
|
|
66
66
|
|
|
67
|
+
def passive_dns_search
|
|
68
|
+
res = client.passive_dns_search(query)
|
|
69
|
+
res["results"] || []
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def reverse_whois_search
|
|
73
|
+
res = client.reverse_whois_search(query)
|
|
74
|
+
(res["results"] || []).map do |result|
|
|
75
|
+
data = result["domain"]
|
|
76
|
+
Models::Artifact.new(data: data, metadata: result)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def ssl_search
|
|
81
|
+
res = client.ssl_search(query)
|
|
82
|
+
(res["results"] || []).map do |result|
|
|
83
|
+
data = result["ipAddresses"]
|
|
84
|
+
data.map { |d| Models::Artifact.new(data: d, metadata: result) }
|
|
85
|
+
end.flatten
|
|
86
|
+
end
|
|
87
|
+
|
|
67
88
|
def client
|
|
68
89
|
Clients::PassiveTotal.new(username: username, api_key: api_key, timeout: timeout)
|
|
69
90
|
end
|
|
@@ -80,10 +101,6 @@ module Mihari
|
|
|
80
101
|
def username?
|
|
81
102
|
!username.nil?
|
|
82
103
|
end
|
|
83
|
-
|
|
84
|
-
def api_key?
|
|
85
|
-
!api_key.nil?
|
|
86
|
-
end
|
|
87
104
|
end
|
|
88
105
|
end
|
|
89
106
|
end
|
|
@@ -6,7 +6,7 @@ module Mihari
|
|
|
6
6
|
# Pulsedive analyzer
|
|
7
7
|
#
|
|
8
8
|
class Pulsedive < Base
|
|
9
|
-
include
|
|
9
|
+
include Concerns::Refangable
|
|
10
10
|
|
|
11
11
|
# @return [String, nil]
|
|
12
12
|
attr_reader :type
|
|
@@ -43,8 +43,10 @@ module Mihari
|
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
class << self
|
|
47
|
+
def configuration_keys
|
|
48
|
+
%w[pulsedive_api_key]
|
|
49
|
+
end
|
|
48
50
|
end
|
|
49
51
|
|
|
50
52
|
private
|
|
@@ -6,7 +6,7 @@ module Mihari
|
|
|
6
6
|
# SecurityTrails
|
|
7
7
|
#
|
|
8
8
|
class SecurityTrails < Base
|
|
9
|
-
include
|
|
9
|
+
include Concerns::Refangable
|
|
10
10
|
|
|
11
11
|
# @return [String, nil]
|
|
12
12
|
attr_reader :type
|
|
@@ -33,21 +33,21 @@ module Mihari
|
|
|
33
33
|
def artifacts
|
|
34
34
|
case type
|
|
35
35
|
when "domain"
|
|
36
|
-
|
|
36
|
+
domain_search
|
|
37
37
|
when "ip"
|
|
38
|
-
|
|
38
|
+
ip_search
|
|
39
39
|
when "mail"
|
|
40
|
-
|
|
40
|
+
mail_search
|
|
41
41
|
else
|
|
42
42
|
raise ValueError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
def configuration_keys
|
|
47
|
-
%w[securitytrails_api_key]
|
|
48
|
-
end
|
|
49
|
-
|
|
50
46
|
class << self
|
|
47
|
+
def configuration_keys
|
|
48
|
+
%w[securitytrails_api_key]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
51
|
#
|
|
52
52
|
# @return [Array<String>, nil]
|
|
53
53
|
#
|
|
@@ -58,6 +58,30 @@ module Mihari
|
|
|
58
58
|
|
|
59
59
|
private
|
|
60
60
|
|
|
61
|
+
def domain_search
|
|
62
|
+
client.get_all_dns_history(query, type: "a").map do |res|
|
|
63
|
+
(res["records"] || []).map do |record|
|
|
64
|
+
(record["values"] || []).map { |value| value["ip"] }
|
|
65
|
+
end.flatten.compact.uniq
|
|
66
|
+
end.flatten
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def ip_search
|
|
70
|
+
res = client.ip_search(query)
|
|
71
|
+
(res["records"] || []).filter_map do |record|
|
|
72
|
+
data = record["hostname"]
|
|
73
|
+
Models::Artifact.new(data: data, metadata: record)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def mail_search
|
|
78
|
+
res = client.mail_search(query)
|
|
79
|
+
(res["records"] || []).filter_map do |record|
|
|
80
|
+
data = record["hostname"]
|
|
81
|
+
Models::Artifact.new(data: data, metadata: record)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
61
85
|
def client
|
|
62
86
|
Clients::SecurityTrails.new(api_key: api_key, timeout: timeout)
|
|
63
87
|
end
|
|
@@ -6,7 +6,7 @@ module Mihari
|
|
|
6
6
|
# VirusTotal analyzer
|
|
7
7
|
#
|
|
8
8
|
class VirusTotal < Base
|
|
9
|
-
include
|
|
9
|
+
include Concerns::Refangable
|
|
10
10
|
|
|
11
11
|
# @return [String]
|
|
12
12
|
attr_reader :type
|
|
@@ -38,11 +38,11 @@ module Mihari
|
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
def configuration_keys
|
|
42
|
-
%w[virustotal_api_key]
|
|
43
|
-
end
|
|
44
|
-
|
|
45
41
|
class << self
|
|
42
|
+
def configuration_keys
|
|
43
|
+
%w[virustotal_api_key]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
46
|
#
|
|
47
47
|
# @return [Array<String>, nil]
|
|
48
48
|
#
|
|
@@ -24,8 +24,10 @@ module Mihari
|
|
|
24
24
|
client.intel_search_with_pagination(query, pagination_limit: pagination_limit).map(&:artifacts).flatten
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
class << self
|
|
28
|
+
def configuration_keys
|
|
29
|
+
%w[virustotal_api_key]
|
|
30
|
+
end
|
|
29
31
|
end
|
|
30
32
|
|
|
31
33
|
class << self
|