mihari 1.2.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 901c334bf0485bbb82a422a1900347e77e476143afaef3036c177ceadbb7e6c6
4
- data.tar.gz: 3fd3663d4d05518b46f9d1a53d9d742b150a84ffba93aaf4d9ebdcbd93505342
3
+ metadata.gz: ab3906ec64d1f2fe33db26d91da0459b3509a8a30b7ad68bd5613fb04f6b788b
4
+ data.tar.gz: 6824cc1b248e17828f57fd5c39089a04ac49ac5e8e92b7b30491c2e32d2eefe7
5
5
  SHA512:
6
- metadata.gz: b97df59e99c969940ffe54a1ecf1e655f582ed4f2372c4e08feb3572fd7f38e767303911a4ec36151325da78415738a0f952f35dfbd010bd9dc6a1832635c78a
7
- data.tar.gz: b092fdfa627a2ab2d2e4a71c4e070e1788fa496b3be6f64e038b332632adbdd4d70c2cae239e14814a31f03def374eb215f3cc580695af38d9562e1b2e1da4e1
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 | |
@@ -1,4 +1,4 @@
1
- FROM ruby:2.6-alpine3.10
1
+ FROM ruby:2.7-alpine3.10
2
2
  RUN apk --no-cache add git build-base ruby-dev sqlite-dev postgresql-dev \
3
3
  && cd /tmp/ \
4
4
  && git clone https://github.com/ninoseki/mihari.git \
@@ -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,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 => _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
- raise
13
+ raise e
14
14
  end
15
15
  end
16
16
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- VERSION = "1.2.0"
4
+ VERSION = "1.4.0"
5
5
  end
@@ -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.88"
35
- spec.add_development_dependency "rubocop-performance", "~> 1.7"
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.8"
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.5"
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
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": [
3
+ "config:base"
4
+ ]
5
+ }
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.0
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-08-01 00:00:00.000000000 Z
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.88'
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.88'
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.7'
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.7'
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.8'
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.8'
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.5'
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.5'
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