mihari 1.2.1 → 1.4.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5bd4fc32291966114c9c687f44c930d1974348cc61a36cf682f33efcc617118f
4
- data.tar.gz: a7ed78b49a8b3fe3e9ea398d1e41d13c3ed9f3dd6c23ac2de4e1d8cd8328e59e
3
+ metadata.gz: 3739df12ff7fe35c98ad1dbd181fd8b300486443e36b7ed50bbbd8507a00eccf
4
+ data.tar.gz: 43e048cf9eb60f8c0e32cbd43b729e25fa86da2e09784dc24d52163260653988
5
5
  SHA512:
6
- metadata.gz: f752ce54d8cccc4b6f8c81a87939dabf707629ca1ce5c3244f7ae7a595e808b0a326dc068eac58f705b48b65c7d378aa22f7ee062bcce3d967a6e3518ea29974
7
- data.tar.gz: 00110a28edd487a1f4f200f3f0fd93f28b8fd358de936651453b2caa75420a90b330f1605f3a8c2a3e36b362fc269a178b693f1752249768591dbb413dcaf555
6
+ metadata.gz: f62b84ba24b7405b0977414c6c91c9d97219a77f5d166c46c83682613a99f19a17dfedd8768f560eed7c0e6d28d7ea343a332400512748551b518b8e09e038fd
7
+ data.tar.gz: 794a4b44504e01cbb8b772fb7d7f9e389b67895352e4552549cf02bb70827695d44424ba583059020394ea0eb620a58ef05c4e34bed78b9dabc842abad996516
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 | |
@@ -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"
@@ -37,6 +37,10 @@ module Mihari
37
37
 
38
38
  def search_with_page(query, page: 1)
39
39
  api.host.search(query, page: page)
40
+ rescue ::BinaryEdge::Error => e
41
+ raise RetryableError, e if e.message.include?("Request time limit exceeded")
42
+
43
+ raise e
40
44
  end
41
45
 
42
46
  def search
@@ -45,6 +45,10 @@ module Mihari
45
45
 
46
46
  def search_with_page(query, page: 1)
47
47
  api.host.search(query, page: page)
48
+ rescue ::Shodan::Error => e
49
+ raise RetryableError, e if e.message.include?("request timed out")
50
+
51
+ raise e
48
52
  end
49
53
 
50
54
  def search
@@ -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(query, title: nil, description: nil, tags: [], target_type: "url")
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
 
@@ -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"
@@ -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"]
@@ -3,4 +3,5 @@
3
3
  module Mihari
4
4
  class Error < StandardError; end
5
5
  class InvalidInputError < Error; end
6
+ class RetryableError < Error; end
6
7
  end
@@ -7,7 +7,7 @@ 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, ::Shodan::Error => e
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
13
  raise e
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- VERSION = "1.2.1"
4
+ VERSION = "1.4.1"
5
5
  end
@@ -30,15 +30,15 @@ Gem::Specification.new do |spec|
30
30
  spec.add_development_dependency "fakefs", "~> 1.2"
31
31
  spec.add_development_dependency "pre-commit", "~> 0.39"
32
32
  spec.add_development_dependency "rake", "~> 13.0"
33
- spec.add_development_dependency "rspec", "~> 3.9"
34
- spec.add_development_dependency "rubocop", "~> 0.88"
35
- spec.add_development_dependency "rubocop-performance", "~> 1.7"
33
+ spec.add_development_dependency "rspec", "~> 3.10"
34
+ spec.add_development_dependency "rubocop", "~> 1.6.0"
35
+ spec.add_development_dependency "rubocop-performance", "~> 1.9"
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.8"
38
+ spec.add_development_dependency "webmock", "~> 3.10"
39
39
 
40
40
  spec.add_dependency "active_model_serializers", "~> 0.10"
41
- spec.add_dependency "activerecord", "~> 6.0"
41
+ spec.add_dependency "activerecord", "~> 6.1"
42
42
  spec.add_dependency "addressable", "~> 2.7"
43
43
  spec.add_dependency "binaryedge", "~> 0.1"
44
44
  spec.add_dependency "censu", "~> 0.2"
@@ -53,7 +53,7 @@ Gem::Specification.new do |spec|
53
53
  spec.add_dependency "net-ping", "~> 2.0"
54
54
  spec.add_dependency "onyphe", "~> 2.0"
55
55
  spec.add_dependency "otx_ruby", "~> 0.9"
56
- spec.add_dependency "parallel", "~> 1.19"
56
+ spec.add_dependency "parallel", "~> 1.20"
57
57
  spec.add_dependency "passive_circl", "~> 0.1"
58
58
  spec.add_dependency "passivetotalx", "~> 0.1"
59
59
  spec.add_dependency "pg", "~> 1.2"
@@ -62,9 +62,11 @@ 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.5"
68
+ spec.add_dependency "thread_safe", "~> 0.3"
69
+ spec.add_dependency "urlscan", "~> 0.6"
68
70
  spec.add_dependency "virustotalx", "~> 1.1"
69
71
  spec.add_dependency "zoomeye-rb", "~> 0.1"
70
72
  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.2.1
4
+ version: 1.4.1
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-08-10 00:00:00.000000000 Z
11
+ date: 2020-12-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -100,42 +100,42 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '3.9'
103
+ version: '3.10'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '3.9'
110
+ version: '3.10'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: rubocop
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
115
  - - "~>"
116
116
  - !ruby/object:Gem::Version
117
- version: '0.88'
117
+ version: 1.6.0
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.88'
124
+ version: 1.6.0
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.7'
131
+ version: '1.9'
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.7'
138
+ version: '1.9'
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.8'
173
+ version: '3.10'
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.8'
180
+ version: '3.10'
181
181
  - !ruby/object:Gem::Dependency
182
182
  name: active_model_serializers
183
183
  requirement: !ruby/object:Gem::Requirement
@@ -198,14 +198,14 @@ dependencies:
198
198
  requirements:
199
199
  - - "~>"
200
200
  - !ruby/object:Gem::Version
201
- version: '6.0'
201
+ version: '6.1'
202
202
  type: :runtime
203
203
  prerelease: false
204
204
  version_requirements: !ruby/object:Gem::Requirement
205
205
  requirements:
206
206
  - - "~>"
207
207
  - !ruby/object:Gem::Version
208
- version: '6.0'
208
+ version: '6.1'
209
209
  - !ruby/object:Gem::Dependency
210
210
  name: addressable
211
211
  requirement: !ruby/object:Gem::Requirement
@@ -408,14 +408,14 @@ dependencies:
408
408
  requirements:
409
409
  - - "~>"
410
410
  - !ruby/object:Gem::Version
411
- version: '1.19'
411
+ version: '1.20'
412
412
  type: :runtime
413
413
  prerelease: false
414
414
  version_requirements: !ruby/object:Gem::Requirement
415
415
  requirements:
416
416
  - - "~>"
417
417
  - !ruby/object:Gem::Version
418
- version: '1.19'
418
+ version: '1.20'
419
419
  - !ruby/object:Gem::Dependency
420
420
  name: passive_circl
421
421
  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
@@ -556,20 +570,34 @@ dependencies:
556
570
  - - "~>"
557
571
  - !ruby/object:Gem::Version
558
572
  version: '1.0'
573
+ - !ruby/object:Gem::Dependency
574
+ name: thread_safe
575
+ requirement: !ruby/object:Gem::Requirement
576
+ requirements:
577
+ - - "~>"
578
+ - !ruby/object:Gem::Version
579
+ version: '0.3'
580
+ type: :runtime
581
+ prerelease: false
582
+ version_requirements: !ruby/object:Gem::Requirement
583
+ requirements:
584
+ - - "~>"
585
+ - !ruby/object:Gem::Version
586
+ version: '0.3'
559
587
  - !ruby/object:Gem::Dependency
560
588
  name: urlscan
561
589
  requirement: !ruby/object:Gem::Requirement
562
590
  requirements:
563
591
  - - "~>"
564
592
  - !ruby/object:Gem::Version
565
- version: '0.5'
593
+ version: '0.6'
566
594
  type: :runtime
567
595
  prerelease: false
568
596
  version_requirements: !ruby/object:Gem::Requirement
569
597
  requirements:
570
598
  - - "~>"
571
599
  - !ruby/object:Gem::Version
572
- version: '0.5'
600
+ version: '0.6'
573
601
  - !ruby/object:Gem::Dependency
574
602
  name: virustotalx
575
603
  requirement: !ruby/object:Gem::Requirement
@@ -642,6 +670,7 @@ files:
642
670
  - lib/mihari/analyzers/securitytrails.rb
643
671
  - lib/mihari/analyzers/securitytrails_domain_feed.rb
644
672
  - lib/mihari/analyzers/shodan.rb
673
+ - lib/mihari/analyzers/spyse.rb
645
674
  - lib/mihari/analyzers/ssh_fingerprint.rb
646
675
  - lib/mihari/analyzers/urlscan.rb
647
676
  - lib/mihari/analyzers/virustotal.rb
@@ -698,7 +727,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
698
727
  - !ruby/object:Gem::Version
699
728
  version: '0'
700
729
  requirements: []
701
- rubygems_version: 3.1.2
730
+ rubygems_version: 3.1.4
702
731
  signing_key:
703
732
  specification_version: 4
704
733
  summary: A framework for continuous malicious hosts monitoring.