mihari 2.2.1 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +7 -0
- data/.overcommit.yml +12 -0
- data/README.md +7 -9
- data/exe/mihari +1 -1
- data/images/tines.png +0 -0
- data/lib/mihari.rb +89 -15
- data/lib/mihari/analyzers/base.rb +49 -8
- data/lib/mihari/analyzers/basic.rb +1 -2
- data/lib/mihari/analyzers/binaryedge.rb +7 -13
- data/lib/mihari/analyzers/censys.rb +26 -63
- data/lib/mihari/analyzers/circl.rb +20 -17
- data/lib/mihari/analyzers/crtsh.rb +6 -13
- data/lib/mihari/analyzers/dnpedia.rb +6 -12
- data/lib/mihari/analyzers/dnstwister.rb +13 -10
- data/lib/mihari/analyzers/onyphe.rb +6 -12
- data/lib/mihari/analyzers/otx.rb +22 -19
- data/lib/mihari/analyzers/passivetotal.rb +22 -21
- data/lib/mihari/analyzers/pulsedive.rb +16 -13
- data/lib/mihari/analyzers/rule.rb +99 -0
- data/lib/mihari/analyzers/securitytrails.rb +22 -19
- data/lib/mihari/analyzers/shodan.rb +7 -13
- data/lib/mihari/analyzers/spyse.rb +12 -19
- data/lib/mihari/analyzers/urlscan.rb +20 -30
- data/lib/mihari/analyzers/virustotal.rb +25 -22
- data/lib/mihari/analyzers/zoomeye.rb +16 -22
- data/lib/mihari/cli/analyzer.rb +44 -0
- data/lib/mihari/cli/base.rb +27 -0
- data/lib/mihari/cli/init.rb +13 -0
- data/lib/mihari/cli/main.rb +30 -0
- data/lib/mihari/cli/mixins/utils.rb +88 -0
- data/lib/mihari/cli/validator.rb +11 -0
- data/lib/mihari/commands/binaryedge.rb +1 -1
- data/lib/mihari/commands/censys.rb +1 -1
- data/lib/mihari/commands/circl.rb +2 -2
- data/lib/mihari/commands/crtsh.rb +1 -1
- data/lib/mihari/commands/dnpedia.rb +1 -1
- data/lib/mihari/commands/dnstwister.rb +2 -2
- data/lib/mihari/commands/init.rb +46 -0
- data/lib/mihari/commands/json.rb +1 -1
- data/lib/mihari/commands/onyphe.rb +1 -1
- data/lib/mihari/commands/otx.rb +2 -2
- data/lib/mihari/commands/passivetotal.rb +2 -2
- data/lib/mihari/commands/pulsedive.rb +2 -2
- data/lib/mihari/commands/search.rb +77 -0
- data/lib/mihari/commands/securitytrails.rb +2 -2
- data/lib/mihari/commands/shodan.rb +1 -1
- data/lib/mihari/commands/spyse.rb +1 -1
- data/lib/mihari/commands/urlscan.rb +2 -4
- data/lib/mihari/commands/validator.rb +38 -0
- data/lib/mihari/commands/virustotal.rb +2 -2
- data/lib/mihari/commands/zoomeye.rb +1 -1
- data/lib/mihari/constraints.rb +5 -0
- data/lib/mihari/database.rb +13 -2
- data/lib/mihari/emitters/base.rb +2 -2
- data/lib/mihari/emitters/database.rb +1 -1
- data/lib/mihari/emitters/misp.rb +3 -1
- data/lib/mihari/emitters/slack.rb +6 -10
- data/lib/mihari/emitters/the_hive.rb +1 -1
- data/lib/mihari/emitters/webhook.rb +53 -0
- data/lib/mihari/mixins/configurable.rb +38 -0
- data/lib/mihari/mixins/configuration.rb +90 -0
- data/lib/mihari/mixins/hash.rb +20 -0
- data/lib/mihari/mixins/refang.rb +21 -0
- data/lib/mihari/mixins/retriable.rb +27 -0
- data/lib/mihari/mixins/rule.rb +79 -0
- data/lib/mihari/models/alert.rb +28 -1
- data/lib/mihari/models/artifact.rb +10 -0
- data/lib/mihari/notifiers/base.rb +9 -1
- data/lib/mihari/notifiers/exception_notifier.rb +50 -0
- data/lib/mihari/notifiers/slack.rb +29 -1
- data/lib/mihari/schemas/configuration.rb +42 -0
- data/lib/mihari/schemas/macros.rb +17 -0
- data/lib/mihari/schemas/rule.rb +72 -0
- data/lib/mihari/serializers/artifact.rb +1 -1
- data/lib/mihari/status.rb +14 -0
- data/lib/mihari/templates/rule.yml.erb +19 -0
- data/lib/mihari/type_checker.rb +8 -3
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/controllers/base_controller.rb +1 -1
- data/lib/mihari/web/public/index.html +1 -1
- data/lib/mihari/web/public/redoc-static.html +2 -2
- data/lib/mihari/web/public/static/js/app.ab213f7c.js +12 -0
- data/lib/mihari/web/public/static/js/app.ab213f7c.js.map +1 -0
- data/mihari.gemspec +19 -12
- metadata +139 -65
- data/.rubocop.yml +0 -161
- data/lib/mihari/analyzers/free_text.rb +0 -48
- data/lib/mihari/analyzers/http_hash.rb +0 -100
- data/lib/mihari/analyzers/passive_dns.rb +0 -59
- data/lib/mihari/analyzers/passive_ssl.rb +0 -55
- data/lib/mihari/analyzers/reverse_whois.rb +0 -55
- data/lib/mihari/analyzers/securitytrails_domain_feed.rb +0 -59
- data/lib/mihari/analyzers/ssh_fingerprint.rb +0 -58
- data/lib/mihari/cli.rb +0 -126
- data/lib/mihari/commands/config.rb +0 -27
- data/lib/mihari/commands/free_text.rb +0 -21
- data/lib/mihari/commands/http_hash.rb +0 -25
- data/lib/mihari/commands/passive_dns.rb +0 -21
- data/lib/mihari/commands/passive_ssl.rb +0 -21
- data/lib/mihari/commands/reverse_whois.rb +0 -21
- data/lib/mihari/commands/securitytrails_domain_feed.rb +0 -23
- data/lib/mihari/commands/ssh_fingerprint.rb +0 -21
- data/lib/mihari/config.rb +0 -84
- data/lib/mihari/configurable.rb +0 -21
- data/lib/mihari/html.rb +0 -43
- data/lib/mihari/retriable.rb +0 -17
- data/lib/mihari/slack_monkeypatch.rb +0 -16
@@ -1,59 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "securitytrails"
|
4
|
-
|
5
|
-
module Mihari
|
6
|
-
module Analyzers
|
7
|
-
class SecurityTrailsDomainFeed < Base
|
8
|
-
attr_reader :type, :title, :description, :tags
|
9
|
-
|
10
|
-
def initialize(regexp, type: "registered", title: nil, description: nil, tags: [])
|
11
|
-
super()
|
12
|
-
|
13
|
-
@_regexp = regexp
|
14
|
-
@type = type
|
15
|
-
|
16
|
-
raise InvalidInputError, "#{@_regexp} is not a valid regexp" unless regexp
|
17
|
-
raise InvalidInputError, "#{type} is not a valid type" unless valid_type?
|
18
|
-
|
19
|
-
@title = title || "SecurityTrails domain feed lookup"
|
20
|
-
@description = description || "Regexp = /#{@_regexp}/"
|
21
|
-
@tags = tags
|
22
|
-
end
|
23
|
-
|
24
|
-
def artifacts
|
25
|
-
lookup || []
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def config_keys
|
31
|
-
%w[securitytrails_api_key]
|
32
|
-
end
|
33
|
-
|
34
|
-
def api
|
35
|
-
@api ||= ::SecurityTrails::API.new(Mihari.config.securitytrails_api_key)
|
36
|
-
end
|
37
|
-
|
38
|
-
def valid_type?
|
39
|
-
%w[all new registered].include? type
|
40
|
-
end
|
41
|
-
|
42
|
-
def regexp
|
43
|
-
@regexp ||= Regexp.compile(@_regexp)
|
44
|
-
rescue InvalidInputError => _e
|
45
|
-
nil
|
46
|
-
end
|
47
|
-
|
48
|
-
def lookup
|
49
|
-
new_domains.select do |domain|
|
50
|
-
regexp.match? domain
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def new_domains
|
55
|
-
api.feeds.domains type
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
@@ -1,58 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "parallel"
|
4
|
-
|
5
|
-
module Mihari
|
6
|
-
module Analyzers
|
7
|
-
class SSHFingerprint < Base
|
8
|
-
attr_reader :fingerprint, :title, :description, :tags
|
9
|
-
|
10
|
-
def initialize(fingerprint, title: nil, description: nil, tags: [])
|
11
|
-
super()
|
12
|
-
|
13
|
-
@fingerprint = fingerprint
|
14
|
-
|
15
|
-
@title = title || "SSH fingerprint cross search"
|
16
|
-
@description = description || "fingerprint = #{fingerprint}"
|
17
|
-
@tags = tags
|
18
|
-
end
|
19
|
-
|
20
|
-
def artifacts
|
21
|
-
Parallel.map(analyzers) do |analyzer|
|
22
|
-
run_analyzer analyzer
|
23
|
-
end.flatten
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def valid_fingerprint?
|
29
|
-
/^([0-9a-f]{2}:){15}[0-9a-f]{2}$/.match? fingerprint
|
30
|
-
end
|
31
|
-
|
32
|
-
def binary_edge
|
33
|
-
BinaryEdge.new "ssh.fingerprint:\"#{fingerprint}\""
|
34
|
-
end
|
35
|
-
|
36
|
-
def shodan
|
37
|
-
Shodan.new fingerprint
|
38
|
-
end
|
39
|
-
|
40
|
-
def analyzers
|
41
|
-
raise InvalidInputError, "Invalid fingerprint is given." unless valid_fingerprint?
|
42
|
-
|
43
|
-
[
|
44
|
-
binary_edge,
|
45
|
-
shodan
|
46
|
-
].compact
|
47
|
-
end
|
48
|
-
|
49
|
-
def run_analyzer(analyzer)
|
50
|
-
analyzer.artifacts
|
51
|
-
rescue ArgumentError, InvalidInputError => _e
|
52
|
-
nil
|
53
|
-
rescue ::BinaryEdge::Error, ::Shodan::Error => _e
|
54
|
-
nil
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
data/lib/mihari/cli.rb
DELETED
@@ -1,126 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "thor"
|
4
|
-
|
5
|
-
require "mihari/commands/binaryedge"
|
6
|
-
require "mihari/commands/censys"
|
7
|
-
require "mihari/commands/circl"
|
8
|
-
require "mihari/commands/crtsh"
|
9
|
-
require "mihari/commands/dnpedia"
|
10
|
-
require "mihari/commands/dnstwister"
|
11
|
-
require "mihari/commands/onyphe"
|
12
|
-
require "mihari/commands/otx"
|
13
|
-
require "mihari/commands/passivetotal"
|
14
|
-
require "mihari/commands/pulsedive"
|
15
|
-
require "mihari/commands/securitytrails_domain_feed"
|
16
|
-
require "mihari/commands/securitytrails"
|
17
|
-
require "mihari/commands/shodan"
|
18
|
-
require "mihari/commands/spyse"
|
19
|
-
require "mihari/commands/urlscan"
|
20
|
-
require "mihari/commands/virustotal"
|
21
|
-
require "mihari/commands/zoomeye"
|
22
|
-
|
23
|
-
require "mihari/commands/free_text"
|
24
|
-
require "mihari/commands/http_hash"
|
25
|
-
require "mihari/commands/passive_dns"
|
26
|
-
require "mihari/commands/passive_ssl"
|
27
|
-
require "mihari/commands/reverse_whois"
|
28
|
-
require "mihari/commands/ssh_fingerprint"
|
29
|
-
|
30
|
-
require "mihari/commands/config"
|
31
|
-
require "mihari/commands/json"
|
32
|
-
require "mihari/commands/web"
|
33
|
-
|
34
|
-
module Mihari
|
35
|
-
class CLI < Thor
|
36
|
-
class_option :config, type: :string, desc: "Path to the config file"
|
37
|
-
|
38
|
-
class_option :ignore_old_artifacts, type: :boolean, default: false, desc: "Whether to ignore old artifacts from checking or not. Only affects with analyze commands."
|
39
|
-
class_option :ignore_threshold, type: :numeric, default: 0, desc: "Number of days to define whether an artifact is old or not. Only affects with analyze commands."
|
40
|
-
|
41
|
-
include Mihari::Commands::BinaryEdge
|
42
|
-
include Mihari::Commands::Censys
|
43
|
-
include Mihari::Commands::CIRCL
|
44
|
-
include Mihari::Commands::Config
|
45
|
-
include Mihari::Commands::Crtsh
|
46
|
-
include Mihari::Commands::DNPedia
|
47
|
-
include Mihari::Commands::DNSTwister
|
48
|
-
include Mihari::Commands::FreeText
|
49
|
-
include Mihari::Commands::HTTPHash
|
50
|
-
include Mihari::Commands::JSON
|
51
|
-
include Mihari::Commands::Onyphe
|
52
|
-
include Mihari::Commands::OTX
|
53
|
-
include Mihari::Commands::PassiveDNS
|
54
|
-
include Mihari::Commands::PassiveSSL
|
55
|
-
include Mihari::Commands::PassiveTotal
|
56
|
-
include Mihari::Commands::Pulsedive
|
57
|
-
include Mihari::Commands::ReverseWhois
|
58
|
-
include Mihari::Commands::SecurityTrails
|
59
|
-
include Mihari::Commands::SecurityTrailsDomainFeed
|
60
|
-
include Mihari::Commands::Shodan
|
61
|
-
include Mihari::Commands::Spyse
|
62
|
-
include Mihari::Commands::SSHFingerprint
|
63
|
-
include Mihari::Commands::Urlscan
|
64
|
-
include Mihari::Commands::VirusTotal
|
65
|
-
include Mihari::Commands::Web
|
66
|
-
include Mihari::Commands::ZoomEye
|
67
|
-
|
68
|
-
class << self
|
69
|
-
def exit_on_failure?
|
70
|
-
true
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
no_commands do
|
75
|
-
def with_error_handling
|
76
|
-
yield
|
77
|
-
rescue StandardError => e
|
78
|
-
notifier = Notifiers::ExceptionNotifier.new
|
79
|
-
notifier.notify e
|
80
|
-
end
|
81
|
-
|
82
|
-
# @return [true, false]
|
83
|
-
def valid_json?(json)
|
84
|
-
%w[title description artifacts].all? { |key| json.key? key }
|
85
|
-
end
|
86
|
-
|
87
|
-
def load_configuration
|
88
|
-
config = options["config"]
|
89
|
-
return unless config
|
90
|
-
|
91
|
-
Config.load_from_yaml(config)
|
92
|
-
Database.connect
|
93
|
-
end
|
94
|
-
|
95
|
-
def run_analyzer(analyzer_class, query:, options:)
|
96
|
-
load_configuration
|
97
|
-
|
98
|
-
options = symbolize_hash_keys(options)
|
99
|
-
options = normalize_options(options)
|
100
|
-
|
101
|
-
analyzer = analyzer_class.new(query, **options)
|
102
|
-
|
103
|
-
analyzer.ignore_old_artifacts = options[:ignore_old_artifacts] || false
|
104
|
-
analyzer.ignore_threshold = options[:ignore_threshold] || 0
|
105
|
-
|
106
|
-
analyzer.run
|
107
|
-
end
|
108
|
-
|
109
|
-
def symbolize_hash_keys(hash)
|
110
|
-
hash.transform_keys(&:to_sym)
|
111
|
-
end
|
112
|
-
|
113
|
-
def normalize_options(options)
|
114
|
-
# Delete :config because it is not intended to use for running an analyzer
|
115
|
-
[:config, :ignore_old_artifacts, :ignore_threshold].each do |ignore_key|
|
116
|
-
options.delete(ignore_key)
|
117
|
-
end
|
118
|
-
options
|
119
|
-
end
|
120
|
-
|
121
|
-
def refang(indicator)
|
122
|
-
indicator.gsub("[.]", ".").gsub("(.)", ".")
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "colorize"
|
4
|
-
|
5
|
-
module Mihari
|
6
|
-
module Commands
|
7
|
-
module Config
|
8
|
-
def self.included(thor)
|
9
|
-
thor.class_eval do
|
10
|
-
desc "init_config", "Create a config file"
|
11
|
-
method_option :filename, type: :string, default: "mihari.yml"
|
12
|
-
def init_config
|
13
|
-
filename = options["filename"]
|
14
|
-
|
15
|
-
warning = "#{filename} exists. Do you want to overwrite it? (y/n)"
|
16
|
-
if File.exist?(filename) && !(yes? warning)
|
17
|
-
return
|
18
|
-
end
|
19
|
-
|
20
|
-
Mihari::Config.initialize_yaml filename
|
21
|
-
puts "The config file is initialized as #{filename}.".colorize(:blue)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mihari
|
4
|
-
module Commands
|
5
|
-
module FreeText
|
6
|
-
def self.included(thor)
|
7
|
-
thor.class_eval do
|
8
|
-
desc "free_text [TEXT]", "Cross search with search engines by a free text"
|
9
|
-
method_option :title, type: :string, desc: "title"
|
10
|
-
method_option :description, type: :string, desc: "description"
|
11
|
-
method_option :tags, type: :array, desc: "tags"
|
12
|
-
def free_text(text)
|
13
|
-
with_error_handling do
|
14
|
-
run_analyzer Analyzers::FreeText, query: text, options: options
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mihari
|
4
|
-
module Commands
|
5
|
-
module HTTPHash
|
6
|
-
def self.included(thor)
|
7
|
-
thor.class_eval do
|
8
|
-
desc "http_hash", "Cross search with search engines by a hash of an HTTP response (SHA256, MD5 and MurmurHash3)"
|
9
|
-
method_option :title, type: :string, desc: "title"
|
10
|
-
method_option :description, type: :string, desc: "description"
|
11
|
-
method_option :tags, type: :array, desc: "tags"
|
12
|
-
method_option :md5, type: :string, desc: "MD5 hash"
|
13
|
-
method_option :sha256, type: :string, desc: "SHA256 hash"
|
14
|
-
method_option :mmh3, type: :numeric, desc: "MurmurHash3 hash"
|
15
|
-
method_option :html, type: :string, desc: "path to an HTML file"
|
16
|
-
def http_hash
|
17
|
-
with_error_handling do
|
18
|
-
run_analyzer Analyzers::HTTPHash, query: nil, options: options
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mihari
|
4
|
-
module Commands
|
5
|
-
module PassiveDNS
|
6
|
-
def self.included(thor)
|
7
|
-
thor.class_eval do
|
8
|
-
desc "passive_dns [IP|DOMAIN]", "Cross search with passive DNS services by an ip or domain"
|
9
|
-
method_option :title, type: :string, desc: "title"
|
10
|
-
method_option :description, type: :string, desc: "description"
|
11
|
-
method_option :tags, type: :array, desc: "tags"
|
12
|
-
def passive_dns(query)
|
13
|
-
with_error_handling do
|
14
|
-
run_analyzer Analyzers::PassiveDNS, query: refang(query), options: options
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mihari
|
4
|
-
module Commands
|
5
|
-
module PassiveSSL
|
6
|
-
def self.included(thor)
|
7
|
-
thor.class_eval do
|
8
|
-
desc "passive_ssl [SHA1]", "Cross search with passive SSL services by an SHA1 certificate fingerprint"
|
9
|
-
method_option :title, type: :string, desc: "title"
|
10
|
-
method_option :description, type: :string, desc: "description"
|
11
|
-
method_option :tags, type: :array, desc: "tags"
|
12
|
-
def passive_ssl(query)
|
13
|
-
with_error_handling do
|
14
|
-
run_analyzer Analyzers::PassiveSSL, query: query, options: options
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mihari
|
4
|
-
module Commands
|
5
|
-
module ReverseWhois
|
6
|
-
def self.included(thor)
|
7
|
-
thor.class_eval do
|
8
|
-
desc "reverse_whois [EMAIL]", "Cross search with reverse whois services by an email"
|
9
|
-
method_option :title, type: :string, desc: "title"
|
10
|
-
method_option :description, type: :string, desc: "description"
|
11
|
-
method_option :tags, type: :array, desc: "tags"
|
12
|
-
def reverse_whois(query)
|
13
|
-
with_error_handling do
|
14
|
-
run_analyzer Analyzers::ReveseWhois, query: refang(query), options: options
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mihari
|
4
|
-
module Commands
|
5
|
-
module SecurityTrailsDomainFeed
|
6
|
-
def self.included(thor)
|
7
|
-
thor.class_eval do
|
8
|
-
desc "securitytrails_domain_feed [REGEXP]", "SecurityTrails new domain feed search by a regexp"
|
9
|
-
method_option :title, type: :string, desc: "title"
|
10
|
-
method_option :description, type: :string, desc: "description"
|
11
|
-
method_option :tags, type: :array, desc: "tags"
|
12
|
-
method_option :type, type: :string, default: "registered", desc: "A type of domain feed ('all', 'new' or 'registered')"
|
13
|
-
def securitytrails_domain_feed(regexp)
|
14
|
-
with_error_handling do
|
15
|
-
run_analyzer Analyzers::SecurityTrailsDomainFeed, query: regexp, options: options
|
16
|
-
end
|
17
|
-
end
|
18
|
-
map "st_domain_feed" => :securitytrails_domain_feedd
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mihari
|
4
|
-
module Commands
|
5
|
-
module SSHFingerprint
|
6
|
-
def self.included(thor)
|
7
|
-
thor.class_eval do
|
8
|
-
desc "ssh_fingerprint [FINGERPRINT]", "Cross search with search engines by an SSH fingerprint (e.g. dc:14:de:8e:d7:c1:15:43:23:82:25:81:d2:59:e8:c0)"
|
9
|
-
method_option :title, type: :string, desc: "title"
|
10
|
-
method_option :description, type: :string, desc: "description"
|
11
|
-
method_option :tags, type: :array, desc: "tags"
|
12
|
-
def ssh_fingerprint(fingerprint)
|
13
|
-
with_error_handling do
|
14
|
-
run_analyzer Analyzers::SSHFingerprint, query: fingerprint, options: options
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
data/lib/mihari/config.rb
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "yaml"
|
4
|
-
|
5
|
-
module Mihari
|
6
|
-
class Config
|
7
|
-
attr_accessor :binaryedge_api_key, :censys_id, :censys_secret, :circl_passive_password, :circl_passive_username, :misp_api_endpoint, :misp_api_key, :onyphe_api_key, :otx_api_key, :passivetotal_api_key, :passivetotal_username, :pulsedive_api_key, :securitytrails_api_key, :shodan_api_key, :slack_channel, :slack_webhook_url, :spyse_api_key, :thehive_api_endpoint, :thehive_api_key, :urlscan_api_key, :virustotal_api_key, :zoomeye_password, :zoomeye_username, :database
|
8
|
-
|
9
|
-
def initialize
|
10
|
-
load_from_env
|
11
|
-
end
|
12
|
-
|
13
|
-
def load_from_env
|
14
|
-
@binaryedge_api_key = ENV["BINARYEDGE_API_KEY"]
|
15
|
-
@censys_id = ENV["CENSYS_ID"]
|
16
|
-
@censys_secret = ENV["CENSYS_SECRET"]
|
17
|
-
@circl_passive_password = ENV["CIRCL_PASSIVE_PASSWORD"]
|
18
|
-
@circl_passive_username = ENV["CIRCL_PASSIVE_USERNAME"]
|
19
|
-
@misp_api_endpoint = ENV["MISP_API_ENDPOINT"]
|
20
|
-
@misp_api_key = ENV["MISP_API_KEY"]
|
21
|
-
@onyphe_api_key = ENV["ONYPHE_API_KEY"]
|
22
|
-
@otx_api_key = ENV["OTX_API_KEY"]
|
23
|
-
@passivetotal_api_key = ENV["PASSIVETOTAL_API_KEY"]
|
24
|
-
@passivetotal_username = ENV["PASSIVETOTAL_USERNAME"]
|
25
|
-
@pulsedive_api_key = ENV["PULSEDIVE_API_KEY"]
|
26
|
-
@securitytrails_api_key = ENV["SECURITYTRAILS_API_KEY"]
|
27
|
-
@shodan_api_key = ENV["SHODAN_API_KEY"]
|
28
|
-
@slack_channel = ENV["SLACK_CHANNEL"]
|
29
|
-
@slack_webhook_url = ENV["SLACK_WEBHOOK_URL"]
|
30
|
-
@spyse_api_key = ENV["SPYSE_API_KEY"]
|
31
|
-
@thehive_api_endpoint = ENV["THEHIVE_API_ENDPOINT"]
|
32
|
-
@thehive_api_key = ENV["THEHIVE_API_KEY"]
|
33
|
-
@urlscan_api_key = ENV["URLSCAN_API_KEY"]
|
34
|
-
@virustotal_api_key = ENV["VIRUSTOTAL_API_KEY"]
|
35
|
-
@zoomeye_password = ENV["ZOOMEYE_PASSWORD"]
|
36
|
-
@zoomeye_username = ENV["ZOOMEYE_USERNAME"]
|
37
|
-
|
38
|
-
@database = ENV["DATABASE"] || "mihari.db"
|
39
|
-
end
|
40
|
-
|
41
|
-
class << self
|
42
|
-
def load_from_yaml(path)
|
43
|
-
raise ArgumentError, "#{path} does not exist." unless File.exist?(path)
|
44
|
-
|
45
|
-
data = File.read(path)
|
46
|
-
begin
|
47
|
-
yaml = YAML.safe_load(data)
|
48
|
-
rescue TypeError => _e
|
49
|
-
return
|
50
|
-
end
|
51
|
-
|
52
|
-
Mihari.configure do |config|
|
53
|
-
yaml.each do |key, value|
|
54
|
-
config.send("#{key.downcase}=".to_sym, value)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def initialize_yaml(filename)
|
60
|
-
keys = new.instance_variables.map do |key|
|
61
|
-
key.to_s[1..]
|
62
|
-
end
|
63
|
-
|
64
|
-
config = keys.map do |key|
|
65
|
-
[key, nil]
|
66
|
-
end.to_h
|
67
|
-
|
68
|
-
YAML.dump(config, File.open(filename, "w"))
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
class << self
|
74
|
-
def config
|
75
|
-
@config ||= Config.new
|
76
|
-
end
|
77
|
-
|
78
|
-
attr_writer :config
|
79
|
-
|
80
|
-
def configure
|
81
|
-
yield config
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|