mihari 1.2.0 → 1.4.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/README.md +4 -0
- data/docker/Dockerfile +1 -1
- data/lib/mihari.rb +1 -0
- data/lib/mihari/analyzers/binaryedge.rb +4 -0
- data/lib/mihari/analyzers/shodan.rb +4 -0
- data/lib/mihari/analyzers/spyse.rb +77 -0
- data/lib/mihari/analyzers/urlscan.rb +26 -2
- data/lib/mihari/cli.rb +18 -0
- data/lib/mihari/config.rb +4 -0
- data/lib/mihari/errors.rb +1 -0
- data/lib/mihari/retriable.rb +2 -2
- data/lib/mihari/version.rb +1 -1
- data/mihari.gemspec +5 -4
- data/renovate.json +5 -0
- metadata +26 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab3906ec64d1f2fe33db26d91da0459b3509a8a30b7ad68bd5613fb04f6b788b
|
4
|
+
data.tar.gz: 6824cc1b248e17828f57fd5c39089a04ac49ac5e8e92b7b30491c2e32d2eefe7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6449ac095213ed065d8a00f98d34666b3824acf77a1183e17b65a24d1cb29088284677b7169e5832755daa20a8db16df474b241df74f4ee06e556bf6cebaf7ae
|
7
|
+
data.tar.gz: 6816de8e51d95352265678bc6cba347b462f1d4a100896a3a48a848c92516bb13e8d106964a13d44082d55e2be88447e92bac6abee799ef50b2b935543a588e9
|
data/README.md
CHANGED
@@ -71,6 +71,7 @@ Mihari supports the following services by default.
|
|
71
71
|
- [PassiveTotal](https://community.riskiq.com/)
|
72
72
|
- [SecurityTrails](https://securitytrails.com/)
|
73
73
|
- [Shodan](https://shodan.io)
|
74
|
+
- [Spyse](https://spyse.com)
|
74
75
|
- [urlscan.io](https://urlscan.io)
|
75
76
|
- [VirusTotal](http://virustotal.com)
|
76
77
|
- [ZoomEye](https://zoomeye.org)
|
@@ -99,6 +100,7 @@ Commands:
|
|
99
100
|
mihari securitytrails [IP|DOMAIN|EMAIL] # SecurityTrails lookup by an ip, domain or email
|
100
101
|
mihari securitytrails_domain_feed [REGEXP] # SecurityTrails new domain feed search by a regexp
|
101
102
|
mihari shodan [QUERY] # Shodan host search by a query
|
103
|
+
mihari spyse [QUERY] # Spyse search by a query
|
102
104
|
mihari 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)
|
103
105
|
mihari status # Show the current configuration status
|
104
106
|
mihari urlscan [QUERY] # urlscan search by a given query
|
@@ -221,8 +223,10 @@ Configuration can be done via environment variables or a YAML file.
|
|
221
223
|
| SHODAN_API_KEY | Shodan API key | |
|
222
224
|
| SLACK_CHANNEL | Slack channel name | `#general` |
|
223
225
|
| SLACK_WEBHOOK_URL | Slack Webhook URL | |
|
226
|
+
| SPYSE_API_KEY | Spyse API key | |
|
224
227
|
| THEHIVE_API_ENDPOINT | TheHive URL | |
|
225
228
|
| THEHIVE_API_KEY | TheHive API key | |
|
229
|
+
| URLSCAN_API_KEY | urlscan.io API key | |
|
226
230
|
| VIRUSTOTAL_API_KEY | VirusTotal API key | |
|
227
231
|
| ZOOMEYE_PASSWORD | ZoomEye password | |
|
228
232
|
| ZOOMEYE_USERNAMME | ZoomEye username | |
|
data/docker/Dockerfile
CHANGED
data/lib/mihari.rb
CHANGED
@@ -56,6 +56,7 @@ require "mihari/analyzers/pulsedive"
|
|
56
56
|
require "mihari/analyzers/securitytrails_domain_feed"
|
57
57
|
require "mihari/analyzers/securitytrails"
|
58
58
|
require "mihari/analyzers/shodan"
|
59
|
+
require "mihari/analyzers/spyse"
|
59
60
|
require "mihari/analyzers/urlscan"
|
60
61
|
require "mihari/analyzers/virustotal"
|
61
62
|
require "mihari/analyzers/zoomeye"
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spyse"
|
4
|
+
require "json"
|
5
|
+
|
6
|
+
module Mihari
|
7
|
+
module Analyzers
|
8
|
+
class Spyse < Base
|
9
|
+
attr_reader :query
|
10
|
+
attr_reader :type
|
11
|
+
|
12
|
+
attr_reader :title
|
13
|
+
attr_reader :description
|
14
|
+
attr_reader :tags
|
15
|
+
|
16
|
+
def initialize(query, title: nil, description: nil, tags: [], type: "domain")
|
17
|
+
super()
|
18
|
+
|
19
|
+
@query = query
|
20
|
+
|
21
|
+
@title = title || "Spyse lookup"
|
22
|
+
@description = description || "query = #{query}"
|
23
|
+
@tags = tags
|
24
|
+
@type = type
|
25
|
+
end
|
26
|
+
|
27
|
+
def artifacts
|
28
|
+
lookup || []
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def search_params
|
34
|
+
@search_params ||= JSON.parse(query)
|
35
|
+
end
|
36
|
+
|
37
|
+
def config_keys
|
38
|
+
%w(spyse_api_key)
|
39
|
+
end
|
40
|
+
|
41
|
+
def api
|
42
|
+
@api ||= ::Spyse::API.new(Mihari.config.spyse_api_key)
|
43
|
+
end
|
44
|
+
|
45
|
+
def valid_type?
|
46
|
+
%w(ip domain cert).include? type
|
47
|
+
end
|
48
|
+
|
49
|
+
def domain_lookup
|
50
|
+
res = api.domain.search(search_params, limit: 100)
|
51
|
+
items = res.dig("data", "items") || []
|
52
|
+
items.map do |item|
|
53
|
+
item.dig("name")
|
54
|
+
end.uniq.compact
|
55
|
+
end
|
56
|
+
|
57
|
+
def ip_lookup
|
58
|
+
res = api.ip.search(search_params, limit: 100)
|
59
|
+
items = res.dig("data", "items") || []
|
60
|
+
items.map do |item|
|
61
|
+
item.dig("ip")
|
62
|
+
end.uniq.compact
|
63
|
+
end
|
64
|
+
|
65
|
+
def lookup
|
66
|
+
case type
|
67
|
+
when "domain"
|
68
|
+
domain_lookup
|
69
|
+
when "ip"
|
70
|
+
ip_lookup
|
71
|
+
else
|
72
|
+
raise InvalidInputError, "#{query}(type: #{type || 'unknown'}) is not supported." unless valid_type?
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -9,16 +9,33 @@ module Mihari
|
|
9
9
|
attr_reader :description
|
10
10
|
attr_reader :query
|
11
11
|
attr_reader :tags
|
12
|
+
|
13
|
+
attr_reader :filter
|
12
14
|
attr_reader :target_type
|
15
|
+
attr_reader :use_pro
|
16
|
+
attr_reader :use_similarity
|
13
17
|
|
14
|
-
def initialize(
|
18
|
+
def initialize(
|
19
|
+
query,
|
20
|
+
description: nil,
|
21
|
+
filter: nil,
|
22
|
+
tags: [],
|
23
|
+
target_type: "url",
|
24
|
+
title: nil,
|
25
|
+
use_pro: false,
|
26
|
+
use_similarity: false
|
27
|
+
)
|
15
28
|
super()
|
16
29
|
|
17
30
|
@query = query
|
18
31
|
@title = title || "urlscan lookup"
|
19
32
|
@description = description || "query = #{query}"
|
20
33
|
@tags = tags
|
34
|
+
|
35
|
+
@filter = filter
|
21
36
|
@target_type = target_type
|
37
|
+
@use_pro = use_pro
|
38
|
+
@use_similarity = use_similarity
|
22
39
|
|
23
40
|
raise InvalidInputError, "type should be url, domain or ip." unless valid_target_type?
|
24
41
|
end
|
@@ -35,11 +52,18 @@ module Mihari
|
|
35
52
|
|
36
53
|
private
|
37
54
|
|
55
|
+
def config_keys
|
56
|
+
%w(urlscan_api_key)
|
57
|
+
end
|
58
|
+
|
38
59
|
def api
|
39
|
-
@api ||= ::UrlScan::API.new
|
60
|
+
@api ||= ::UrlScan::API.new(Mihari.config.urlscan_api_key)
|
40
61
|
end
|
41
62
|
|
42
63
|
def search
|
64
|
+
return api.pro.similar(query) if use_similarity
|
65
|
+
return api.pro.search(query: query, filter: filter, size: 10_000) if use_pro
|
66
|
+
|
43
67
|
api.search(query, size: 10_000)
|
44
68
|
end
|
45
69
|
|
data/lib/mihari/cli.rb
CHANGED
@@ -7,6 +7,10 @@ module Mihari
|
|
7
7
|
class CLI < Thor
|
8
8
|
class_option :config, type: :string, desc: "path to config file"
|
9
9
|
|
10
|
+
def self.exit_on_failure?
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
10
14
|
desc "censys [QUERY]", "Censys IPv4 search by a query"
|
11
15
|
method_option :title, type: :string, desc: "title"
|
12
16
|
method_option :description, type: :string, desc: "description"
|
@@ -42,7 +46,10 @@ module Mihari
|
|
42
46
|
method_option :title, type: :string, desc: "title"
|
43
47
|
method_option :description, type: :string, desc: "description"
|
44
48
|
method_option :tags, type: :array, desc: "tags"
|
49
|
+
method_option :filter, type: :string, desc: "filter for urlscan pro search"
|
45
50
|
method_option :target_type, type: :string, default: "url", desc: "target type to fetch from lookup results (target type should be 'url', 'domain' or 'ip')"
|
51
|
+
method_option :use_pro, type: :boolean, default: false, desc: "use pro search API or not"
|
52
|
+
method_option :use_similarity, type: :boolean, default: false, desc: "use similarity API or not"
|
46
53
|
def urlscan(query)
|
47
54
|
with_error_handling do
|
48
55
|
run_analyzer Analyzers::Urlscan, query: query, options: options
|
@@ -174,6 +181,17 @@ module Mihari
|
|
174
181
|
end
|
175
182
|
end
|
176
183
|
|
184
|
+
desc "spyse [QUERY]", "Spyse search by a query"
|
185
|
+
method_option :title, type: :string, desc: "title"
|
186
|
+
method_option :description, type: :string, desc: "description"
|
187
|
+
method_option :tags, type: :array, desc: "tags"
|
188
|
+
method_option :type, type: :string, desc: "type to search (ip or domain)", default: "doamin"
|
189
|
+
def spyse(query)
|
190
|
+
with_error_handling do
|
191
|
+
run_analyzer Analyzers::Spyse, query: query, options: options
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
177
195
|
desc "passive_dns [IP|DOMAIN]", "Cross search with passive DNS services by an ip or domain"
|
178
196
|
method_option :title, type: :string, desc: "title"
|
179
197
|
method_option :description, type: :string, desc: "description"
|
data/lib/mihari/config.rb
CHANGED
@@ -20,8 +20,10 @@ module Mihari
|
|
20
20
|
attr_accessor :shodan_api_key
|
21
21
|
attr_accessor :slack_channel
|
22
22
|
attr_accessor :slack_webhook_url
|
23
|
+
attr_accessor :spyse_api_key
|
23
24
|
attr_accessor :thehive_api_endpoint
|
24
25
|
attr_accessor :thehive_api_key
|
26
|
+
attr_accessor :urlscan_api_key
|
25
27
|
attr_accessor :virustotal_api_key
|
26
28
|
attr_accessor :zoomeye_password
|
27
29
|
attr_accessor :zoomeye_username
|
@@ -49,8 +51,10 @@ module Mihari
|
|
49
51
|
@shodan_api_key = ENV["SHODAN_API_KEY"]
|
50
52
|
@slack_channel = ENV["SLACK_CHANNEL"]
|
51
53
|
@slack_webhook_url = ENV["SLACK_WEBHOOK_URL"]
|
54
|
+
@spyse_api_key = ENV["SPYSE_API_KEY"]
|
52
55
|
@thehive_api_endpoint = ENV["THEHIVE_API_ENDPOINT"]
|
53
56
|
@thehive_api_key = ENV["THEHIVE_API_KEY"]
|
57
|
+
@urlscan_api_key = ENV["URLSCAN_API_KEY"]
|
54
58
|
@virustotal_api_key = ENV["VIRUSTOTAL_API_KEY"]
|
55
59
|
@zoomeye_password = ENV["ZOOMEYE_PASSWORD"]
|
56
60
|
@zoomeye_username = ENV["ZOOMEYE_USERNAME"]
|
data/lib/mihari/errors.rb
CHANGED
data/lib/mihari/retriable.rb
CHANGED
@@ -7,10 +7,10 @@ module Mihari
|
|
7
7
|
begin
|
8
8
|
try += 1
|
9
9
|
yield
|
10
|
-
rescue Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE, OpenSSL::SSL::SSLError, Timeout::Error =>
|
10
|
+
rescue Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE, OpenSSL::SSL::SSLError, Timeout::Error, RetryableError => e
|
11
11
|
sleep interval
|
12
12
|
retry if try < times
|
13
|
-
raise
|
13
|
+
raise e
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
data/lib/mihari/version.rb
CHANGED
data/mihari.gemspec
CHANGED
@@ -31,11 +31,11 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.add_development_dependency "pre-commit", "~> 0.39"
|
32
32
|
spec.add_development_dependency "rake", "~> 13.0"
|
33
33
|
spec.add_development_dependency "rspec", "~> 3.9"
|
34
|
-
spec.add_development_dependency "rubocop", "~> 0.
|
35
|
-
spec.add_development_dependency "rubocop-performance", "~> 1.
|
34
|
+
spec.add_development_dependency "rubocop", "~> 0.90"
|
35
|
+
spec.add_development_dependency "rubocop-performance", "~> 1.8"
|
36
36
|
spec.add_development_dependency "timecop", "~> 0.9"
|
37
37
|
spec.add_development_dependency "vcr", "~> 6.0"
|
38
|
-
spec.add_development_dependency "webmock", "~> 3.
|
38
|
+
spec.add_development_dependency "webmock", "~> 3.9"
|
39
39
|
|
40
40
|
spec.add_dependency "active_model_serializers", "~> 0.10"
|
41
41
|
spec.add_dependency "activerecord", "~> 6.0"
|
@@ -62,9 +62,10 @@ Gem::Specification.new do |spec|
|
|
62
62
|
spec.add_dependency "securitytrails", "~> 1.0"
|
63
63
|
spec.add_dependency "shodanx", "~> 0.2"
|
64
64
|
spec.add_dependency "slack-notifier", "~> 2.3"
|
65
|
+
spec.add_dependency "spysex", "~> 0.1"
|
65
66
|
spec.add_dependency "sqlite3", "~> 1.4"
|
66
67
|
spec.add_dependency "thor", "~> 1.0"
|
67
|
-
spec.add_dependency "urlscan", "~> 0.
|
68
|
+
spec.add_dependency "urlscan", "~> 0.6"
|
68
69
|
spec.add_dependency "virustotalx", "~> 1.1"
|
69
70
|
spec.add_dependency "zoomeye-rb", "~> 0.1"
|
70
71
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mihari
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Manabu Niseki
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -114,28 +114,28 @@ dependencies:
|
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '0.
|
117
|
+
version: '0.90'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: '0.
|
124
|
+
version: '0.90'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: rubocop-performance
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: '1.
|
131
|
+
version: '1.8'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: '1.
|
138
|
+
version: '1.8'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: timecop
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -170,14 +170,14 @@ dependencies:
|
|
170
170
|
requirements:
|
171
171
|
- - "~>"
|
172
172
|
- !ruby/object:Gem::Version
|
173
|
-
version: '3.
|
173
|
+
version: '3.9'
|
174
174
|
type: :development
|
175
175
|
prerelease: false
|
176
176
|
version_requirements: !ruby/object:Gem::Requirement
|
177
177
|
requirements:
|
178
178
|
- - "~>"
|
179
179
|
- !ruby/object:Gem::Version
|
180
|
-
version: '3.
|
180
|
+
version: '3.9'
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
182
|
name: active_model_serializers
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -528,6 +528,20 @@ dependencies:
|
|
528
528
|
- - "~>"
|
529
529
|
- !ruby/object:Gem::Version
|
530
530
|
version: '2.3'
|
531
|
+
- !ruby/object:Gem::Dependency
|
532
|
+
name: spysex
|
533
|
+
requirement: !ruby/object:Gem::Requirement
|
534
|
+
requirements:
|
535
|
+
- - "~>"
|
536
|
+
- !ruby/object:Gem::Version
|
537
|
+
version: '0.1'
|
538
|
+
type: :runtime
|
539
|
+
prerelease: false
|
540
|
+
version_requirements: !ruby/object:Gem::Requirement
|
541
|
+
requirements:
|
542
|
+
- - "~>"
|
543
|
+
- !ruby/object:Gem::Version
|
544
|
+
version: '0.1'
|
531
545
|
- !ruby/object:Gem::Dependency
|
532
546
|
name: sqlite3
|
533
547
|
requirement: !ruby/object:Gem::Requirement
|
@@ -562,14 +576,14 @@ dependencies:
|
|
562
576
|
requirements:
|
563
577
|
- - "~>"
|
564
578
|
- !ruby/object:Gem::Version
|
565
|
-
version: '0.
|
579
|
+
version: '0.6'
|
566
580
|
type: :runtime
|
567
581
|
prerelease: false
|
568
582
|
version_requirements: !ruby/object:Gem::Requirement
|
569
583
|
requirements:
|
570
584
|
- - "~>"
|
571
585
|
- !ruby/object:Gem::Version
|
572
|
-
version: '0.
|
586
|
+
version: '0.6'
|
573
587
|
- !ruby/object:Gem::Dependency
|
574
588
|
name: virustotalx
|
575
589
|
requirement: !ruby/object:Gem::Requirement
|
@@ -642,6 +656,7 @@ files:
|
|
642
656
|
- lib/mihari/analyzers/securitytrails.rb
|
643
657
|
- lib/mihari/analyzers/securitytrails_domain_feed.rb
|
644
658
|
- lib/mihari/analyzers/shodan.rb
|
659
|
+
- lib/mihari/analyzers/spyse.rb
|
645
660
|
- lib/mihari/analyzers/ssh_fingerprint.rb
|
646
661
|
- lib/mihari/analyzers/urlscan.rb
|
647
662
|
- lib/mihari/analyzers/virustotal.rb
|
@@ -674,6 +689,7 @@ files:
|
|
674
689
|
- lib/mihari/type_checker.rb
|
675
690
|
- lib/mihari/version.rb
|
676
691
|
- mihari.gemspec
|
692
|
+
- renovate.json
|
677
693
|
- screenshots/alert.png
|
678
694
|
- screenshots/eyecatch.png
|
679
695
|
- screenshots/misp.png
|