mihari 0.9.0 → 0.9.1

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: a1801d9d520fb6de9a4a27d17145b775b074f87e7e1ff88fcb7c50d5630d19e4
4
- data.tar.gz: 886708647767e1d5d5a7aaaf7bfd9aca8d25bc714f7f2faf72e0c2c2c4b3073f
3
+ metadata.gz: 4175ef15648358026415714167bb1b0567076ad01c20ecf172def0272610ed02
4
+ data.tar.gz: 5b001b4a18c211441a753c5325f355028ae7bf426dbe2c51d676be95f267cf48
5
5
  SHA512:
6
- metadata.gz: 727703b118506f0b310ed1422a757f669748057bd6b4bdb091c638d716209c5ff220088c1396c91924ca275c6fb959e2014f80cb5b9ecbdf72eee23025cf2a7d
7
- data.tar.gz: 150c88bac7b129001b109b1966dc527eda5a7e734438507028e5e2a79f74d1884d6cf98d63a4142a8c45f37f501093a7214187aac88265d9a15a9e6f3d24d03e
6
+ metadata.gz: 351a8537861e52c4d4f5e3eb159d83ee10a699870198736169631c7353726ca6e22cf79c35db827b48b10fef9fc1e6ef236bbb4b07d42dde5452d3316fc051d8
7
+ data.tar.gz: 1467f8fbbce999eef16a72e430a70a5e40faeb9597f2b6f533a202efe27cce7022598768557b8459d1859c33252311ec63fcbe0005a4225dc076173d4a2b712c
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/mihari.svg)](https://badge.fury.io/rb/mihari)
4
4
  [![Build Status](https://travis-ci.org/ninoseki/mihari.svg?branch=master)](https://travis-ci.org/ninoseki/mihari)
5
+ [![Docker Cloud Build Status](https://img.shields.io/docker/cloud/build/ninoseki/mihari)](https://hub.docker.com/r/ninoseki/mihari)
5
6
  [![Coverage Status](https://coveralls.io/repos/github/ninoseki/mihari/badge.svg?branch=master)](https://coveralls.io/github/ninoseki/mihari?branch=master)
6
7
  [![CodeFactor](https://www.codefactor.io/repository/github/ninoseki/mihari/badge)](https://www.codefactor.io/repository/github/ninoseki/mihari)
7
8
 
@@ -26,15 +27,15 @@ You can use mihari without TheHive. But note that mihari depends on TheHive to m
26
27
 
27
28
  - TheHive alert example
28
29
 
29
- ![img](./screenshots/alert.png)
30
+ ![img](https://github.com/ninoseki/mihari/raw/master/screenshots/alert.png)
30
31
 
31
32
  - Slack notification example
32
33
 
33
- ![img](./screenshots/slack.png)
34
+ ![img](https://github.com/ninoseki/mihari/raw/master/screenshots/slack.png)
34
35
 
35
36
  - MISP event example
36
37
 
37
- ![img](./screenshots/misp.png)
38
+ ![img](https://github.com/ninoseki/mihari/raw/master/screenshots/misp.png)
38
39
 
39
40
  ## Installation
40
41
 
@@ -159,6 +160,12 @@ All configuration is done via ENV variables.
159
160
  | SHODAN_API_KEY | Shodan API key | Optional |
160
161
  | VIRUSTOTAL_API_KEY | VirusTotal API key | Optional |
161
162
 
163
+ You can check the configuration status via `status` command.
164
+
165
+ ```bash
166
+ mihari status
167
+ ```
168
+
162
169
  ## How to create a custom script
163
170
 
164
171
  Create a class which extends `Mihari::Analyzers::Base` and implements the following methods.
data/Rakefile CHANGED
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/gem_tasks"
2
4
  require "rspec/core/rake_task"
3
5
 
4
6
  RSpec::Core::RakeTask.new(:spec)
5
7
 
6
- task :default => :spec
8
+ task default: :spec
@@ -1,10 +1,12 @@
1
- FROM ruby:2.6
2
-
3
- RUN cd /tmp/ \
1
+ FROM ruby:2.6-alpine3.10
2
+ RUN apk --no-cache add git build-base ruby-dev \
3
+ && cd /tmp/ \
4
4
  && git clone https://github.com/ninoseki/mihari.git \
5
5
  && cd mihari \
6
6
  && gem build mihari.gemspec -o mihari.gem \
7
- && gem install mihari.gem
7
+ && gem install mihari.gem \
8
+ && rm -rf /tmp/mihari \
9
+ && apk del --purge git build-base ruby-dev
8
10
 
9
11
  ENTRYPOINT ["mihari"]
10
12
 
@@ -69,10 +69,11 @@ module Mihari
69
69
  @unique_artifacts ||= @the_hive.artifact.find_non_existing_artifacts(uncached_artifacts)
70
70
  end
71
71
 
72
- private
73
-
74
72
  def set_unique_artifacts
75
73
  unique_artifacts
74
+ rescue ArgumentError => _e
75
+ klass = self.class.to_s.split("::").last.to_s
76
+ raise Error, "Please configure #{klass} API settings properly"
76
77
  end
77
78
  end
78
79
  end
@@ -5,7 +5,6 @@ require "censu"
5
5
  module Mihari
6
6
  module Analyzers
7
7
  class Censys < Base
8
- attr_reader :api
9
8
  attr_reader :title
10
9
  attr_reader :description
11
10
  attr_reader :query
@@ -17,9 +16,6 @@ module Mihari
17
16
  def initialize(query, title: nil, description: nil, tags: [])
18
17
  super()
19
18
 
20
- raise ArgumentError, "#{CENSYS_ID_KEY} and #{CENSYS_SECRET_KEY} are required" unless valid?
21
-
22
- @api = ::Censys::API.new
23
19
  @query = query
24
20
  @title = title || "Censys lookup"
25
21
  @description = description || "query = #{query}"
@@ -36,6 +32,13 @@ module Mihari
36
32
  ipv4s
37
33
  end
38
34
 
35
+ # @return [true, false]
36
+ def valid?
37
+ censys_id? && censys_secret?
38
+ end
39
+
40
+ private
41
+
39
42
  # @return [true, false]
40
43
  def censys_id?
41
44
  ENV.key? CENSYS_ID_KEY
@@ -46,9 +49,10 @@ module Mihari
46
49
  ENV.key? CENSYS_SECRET_KEY
47
50
  end
48
51
 
49
- # @return [true, false]
50
- def valid?
51
- censys_id? && censys_secret?
52
+ def api
53
+ raise ArgumentError, "#{CENSYS_ID_KEY} and #{CENSYS_SECRET_KEY} are required" unless valid?
54
+
55
+ @api ||= ::Censys::API.new
52
56
  end
53
57
  end
54
58
  end
@@ -5,7 +5,6 @@ require "crtsh"
5
5
  module Mihari
6
6
  module Analyzers
7
7
  class Crtsh < Base
8
- attr_reader :api
9
8
  attr_reader :title
10
9
  attr_reader :description
11
10
  attr_reader :query
@@ -14,7 +13,6 @@ module Mihari
14
13
  def initialize(query, title: nil, description: nil, tags: [])
15
14
  super()
16
15
 
17
- @api = ::Crtsh::API.new
18
16
  @query = query
19
17
  @title = title || "crt.sh lookup"
20
18
  @description = description || "query = #{query}"
@@ -28,6 +26,10 @@ module Mihari
28
26
 
29
27
  private
30
28
 
29
+ def api
30
+ @api ||= ::Crtsh::API.new
31
+ end
32
+
31
33
  def search
32
34
  api.search(query)
33
35
  rescue ::Crtsh::Error => _e
@@ -5,7 +5,6 @@ require "onyphe"
5
5
  module Mihari
6
6
  module Analyzers
7
7
  class Onyphe < Base
8
- attr_reader :api
9
8
  attr_reader :title
10
9
  attr_reader :description
11
10
  attr_reader :query
@@ -14,7 +13,6 @@ module Mihari
14
13
  def initialize(query, title: nil, description: nil, tags: [])
15
14
  super()
16
15
 
17
- @api = ::Onyphe::API.new
18
16
  @query = query
19
17
  @title = title || "Onyphe lookup"
20
18
  @description = description || "query = #{query}"
@@ -31,10 +29,12 @@ module Mihari
31
29
 
32
30
  private
33
31
 
32
+ def api
33
+ @api ||= ::Onyphe::API.new
34
+ end
35
+
34
36
  def search
35
37
  api.datascan(query)
36
- rescue ::Onyphe::Error => _e
37
- nil
38
38
  end
39
39
  end
40
40
  end
@@ -5,7 +5,6 @@ require "securitytrails"
5
5
  module Mihari
6
6
  module Analyzers
7
7
  class SecurityTrails < Base
8
- attr_reader :api
9
8
  attr_reader :indicator
10
9
  attr_reader :type
11
10
 
@@ -16,7 +15,6 @@ module Mihari
16
15
  def initialize(indicator, title: nil, description: nil, tags: [])
17
16
  super()
18
17
 
19
- @api = ::SecurityTrails::API.new
20
18
  @indicator = indicator
21
19
  @type = TypeChecker.type(indicator)
22
20
 
@@ -31,6 +29,10 @@ module Mihari
31
29
 
32
30
  private
33
31
 
32
+ def api
33
+ @api ||= ::SecurityTrails::API.new
34
+ end
35
+
34
36
  def valid_type?
35
37
  %w(ip domain).include? type
36
38
  end
@@ -5,7 +5,6 @@ require "securitytrails"
5
5
  module Mihari
6
6
  module Analyzers
7
7
  class SecurityTrailsDomainFeed < Base
8
- attr_reader :api
9
8
  attr_reader :type
10
9
 
11
10
  attr_reader :title
@@ -15,7 +14,6 @@ module Mihari
15
14
  def initialize(regexp, type: "registered", title: nil, description: nil, tags: [])
16
15
  super()
17
16
 
18
- @api = ::SecurityTrails::API.new
19
17
  @_regexp = regexp
20
18
  @type = type
21
19
 
@@ -33,6 +31,10 @@ module Mihari
33
31
 
34
32
  private
35
33
 
34
+ def api
35
+ @api ||= ::SecurityTrails::API.new
36
+ end
37
+
36
38
  def valid_type?
37
39
  %w(all new registered).include? type
38
40
  end
@@ -5,7 +5,6 @@ require "shodan"
5
5
  module Mihari
6
6
  module Analyzers
7
7
  class Shodan < Base
8
- attr_reader :api
9
8
  attr_reader :title
10
9
  attr_reader :description
11
10
  attr_reader :query
@@ -14,7 +13,6 @@ module Mihari
14
13
  def initialize(query, title: nil, description: nil, tags: [])
15
14
  super()
16
15
 
17
- @api = ::Shodan::API.new
18
16
  @query = query
19
17
  @title = title || "Shodan lookup"
20
18
  @description = description || "query = #{query}"
@@ -33,6 +31,10 @@ module Mihari
33
31
 
34
32
  private
35
33
 
34
+ def api
35
+ @api ||= ::Shodan::API.new
36
+ end
37
+
36
38
  def search
37
39
  api.host.search(query)
38
40
  rescue ::Shodan::Error => _e
@@ -5,7 +5,6 @@ require "urlscan"
5
5
  module Mihari
6
6
  module Analyzers
7
7
  class Urlscan < Base
8
- attr_reader :api
9
8
  attr_reader :title
10
9
  attr_reader :description
11
10
  attr_reader :query
@@ -15,7 +14,6 @@ module Mihari
15
14
  def initialize(query, title: nil, description: nil, tags: [], target_type: "url")
16
15
  super()
17
16
 
18
- @api = ::UrlScan::API.new
19
17
  @query = query
20
18
  @title = title || "urlscan lookup"
21
19
  @description = description || "query = #{query}"
@@ -37,6 +35,10 @@ module Mihari
37
35
 
38
36
  private
39
37
 
38
+ def api
39
+ @api ||= ::UrlScan::API.new
40
+ end
41
+
40
42
  def search
41
43
  api.search(query)
42
44
  rescue ::UrlScan::ResponseError => _e
@@ -5,7 +5,6 @@ require "virustotal"
5
5
  module Mihari
6
6
  module Analyzers
7
7
  class VirusTotal < Base
8
- attr_reader :api
9
8
  attr_reader :indicator
10
9
  attr_reader :type
11
10
 
@@ -16,7 +15,6 @@ module Mihari
16
15
  def initialize(indicator, title: nil, description: nil, tags: [])
17
16
  super()
18
17
 
19
- @api = ::VirusTotal::API.new
20
18
  @indicator = indicator
21
19
  @type = TypeChecker.type(indicator)
22
20
 
@@ -31,6 +29,10 @@ module Mihari
31
29
 
32
30
  private
33
31
 
32
+ def api
33
+ @api = ::VirusTotal::API.new
34
+ end
35
+
34
36
  def valid_type?
35
37
  %w(ip domain).include? type
36
38
  end
@@ -49,22 +51,28 @@ module Mihari
49
51
  end
50
52
 
51
53
  def domain_lookup
52
- report = api.domain.report(indicator)
53
- return nil unless report
54
+ begin
55
+ res = api.domain.resolutions(indicator)
56
+ rescue ::VirusTotal::Error => _e
57
+ return nil
58
+ end
54
59
 
55
- resolutions = report.dig("resolutions") || []
56
- resolutions.map do |resolution|
57
- resolution.dig("ip_address")
60
+ data = res.dig("data") || []
61
+ data.map do |item|
62
+ item.dig("attributes", "ip_address")
58
63
  end.compact.uniq
59
64
  end
60
65
 
61
66
  def ip_lookup
62
- report = api.ip_address.report(indicator)
63
- return nil unless report
67
+ begin
68
+ res = api.ip_address.resolutions(indicator)
69
+ rescue ::VirusTotal::Error => _e
70
+ return nil
71
+ end
64
72
 
65
- resolutions = report.dig("resolutions") || []
66
- resolutions.map do |resolution|
67
- resolution.dig("hostname")
73
+ data = res.dig("data") || []
74
+ data.map do |item|
75
+ item.dig("attributes", "host_name")
68
76
  end.compact.uniq
69
77
  end
70
78
  end
@@ -135,7 +135,7 @@ module Mihari
135
135
 
136
136
  def parse_as_json(input)
137
137
  JSON.parse input
138
- rescue JSON::ParserError => e
138
+ rescue JSON::ParserError => _e
139
139
  nil
140
140
  end
141
141
 
@@ -12,7 +12,7 @@ module Mihari
12
12
  raise NotImplementedError, "You must implement #{self.class}##{__method__}"
13
13
  end
14
14
 
15
- def emit(title:, description:, artifacts:)
15
+ def emit(*)
16
16
  raise NotImplementedError, "You must implement #{self.class}##{__method__}"
17
17
  end
18
18
  end
@@ -11,7 +11,7 @@ module Mihari
11
11
  api_endpoint? && api_key? && ping?
12
12
  end
13
13
 
14
- def emit(title:, description:, artifacts:, tags: [])
14
+ def emit(title:, artifacts:, tags: [], **_options)
15
15
  event = ::MISP::Event.new(info: title)
16
16
 
17
17
  artifacts.each do |artifact|
@@ -5,6 +5,7 @@ module Mihari
5
5
  def check
6
6
  {
7
7
  censys: { status: censys?, message: censys },
8
+ misp: { status: misp?, message: misp },
8
9
  onyphe: { status: onyphe?, message: onyphe },
9
10
  securitytrails: { status: securitytrails?, message: securitytrails },
10
11
  shodan: { status: shodan?, message: shodan },
@@ -84,5 +85,13 @@ module Mihari
84
85
  def the_hive
85
86
  the_hive? ? "THEHIVE_API_ENDPOINT and THEHIVE_API_KEY are found" : "THEHIVE_API_ENDPOINT and THEHIVE_API_KEY are are missing"
86
87
  end
88
+
89
+ def misp?
90
+ ENV.key?("MISP_API_ENDPOINT") && ENV.key?("MISP_API_KEY")
91
+ end
92
+
93
+ def misp
94
+ misp? ? "MISP_API_ENDPOINT and MISP_API_KEY are found" : "MISP_API_ENDPOINT and MISP_API_KEY are are missing"
95
+ end
87
96
  end
88
97
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- VERSION = "0.9.0"
4
+ VERSION = "0.9.1"
5
5
  end
@@ -50,5 +50,5 @@ Gem::Specification.new do |spec|
50
50
  spec.add_dependency "slack-notifier", "~> 2.3"
51
51
  spec.add_dependency "thor", "~> 0.20"
52
52
  spec.add_dependency "urlscan", "~> 0.4"
53
- spec.add_dependency "virustotalx", "~> 0.1"
53
+ spec.add_dependency "virustotalx", "~> 1.0"
54
54
  end
Binary file
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: 0.9.0
4
+ version: 0.9.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: 2019-09-24 00:00:00.000000000 Z
11
+ date: 2019-09-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -366,14 +366,14 @@ dependencies:
366
366
  requirements:
367
367
  - - "~>"
368
368
  - !ruby/object:Gem::Version
369
- version: '0.1'
369
+ version: '1.0'
370
370
  type: :runtime
371
371
  prerelease: false
372
372
  version_requirements: !ruby/object:Gem::Requirement
373
373
  requirements:
374
374
  - - "~>"
375
375
  - !ruby/object:Gem::Version
376
- version: '0.1'
376
+ version: '1.0'
377
377
  description: A framework for continuous malicious hosts monitoring.
378
378
  email:
379
379
  - manabu.niseki@gmail.com
@@ -393,7 +393,6 @@ files:
393
393
  - bin/setup
394
394
  - docker/Dockerfile
395
395
  - examples/ipinfo_hosted_domains.rb
396
- - examples/vt_passive_dns.rb
397
396
  - exe/mihari
398
397
  - lib/mihari.rb
399
398
  - lib/mihari/alert_viewer.rb
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- $LOAD_PATH.unshift("#{__dir__}/../lib")
4
-
5
- require "mihari"
6
-
7
- require "virustotal_api"
8
-
9
- module Mihari
10
- module Analyzers
11
- class VTPassiveDNS < Base
12
- attr_reader :ip
13
-
14
- def initialize(ip, api_key: nil)
15
- @ip = ip
16
- @api_key = api_key
17
- end
18
-
19
- def title
20
- "VT passive DNS"
21
- end
22
-
23
- def description
24
- "VT passive DNS: #{ip}"
25
- end
26
-
27
- def api_key
28
- ENV["VT_API_KEY"] || @api_key
29
- end
30
-
31
- def artifacts
32
- ip_report = VirustotalAPI::IPReport.find(ip, api_key)
33
- return [] unless ip_report.exists?
34
-
35
- report = ip_report.report
36
- report.dig("resolutions")&.map do |resolution|
37
- resolution.dig("hostname")
38
- end&.compact
39
- end
40
- end
41
- end
42
- end
43
-
44
- ip = "TARGET_IP"
45
- analyzer = Mihari::Analyzers::VTPassiveDNS.new(ip)
46
- analyzer.run