mihari 5.1.0 → 5.1.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mihari/analyzers/binaryedge.rb +9 -7
  3. data/lib/mihari/analyzers/censys.rb +3 -5
  4. data/lib/mihari/analyzers/circl.rb +4 -6
  5. data/lib/mihari/analyzers/crtsh.rb +6 -7
  6. data/lib/mihari/analyzers/dnpedia.rb +3 -7
  7. data/lib/mihari/analyzers/dnstwister.rb +3 -5
  8. data/lib/mihari/analyzers/feed.rb +12 -10
  9. data/lib/mihari/analyzers/greynoise.rb +3 -5
  10. data/lib/mihari/analyzers/onyphe.rb +3 -4
  11. data/lib/mihari/analyzers/otx.rb +1 -3
  12. data/lib/mihari/analyzers/passivetotal.rb +5 -7
  13. data/lib/mihari/analyzers/pulsedive.rb +5 -7
  14. data/lib/mihari/analyzers/shodan.rb +3 -9
  15. data/lib/mihari/analyzers/urlscan.rb +7 -6
  16. data/lib/mihari/analyzers/virustotal.rb +4 -6
  17. data/lib/mihari/analyzers/virustotal_intelligence.rb +4 -5
  18. data/lib/mihari/analyzers/zoomeye.rb +4 -10
  19. data/lib/mihari/clients/base.rb +53 -0
  20. data/lib/mihari/clients/binaryedge.rb +33 -0
  21. data/lib/mihari/clients/censys.rb +42 -0
  22. data/lib/mihari/clients/circl.rb +59 -0
  23. data/lib/mihari/clients/crtsh.rb +31 -0
  24. data/lib/mihari/clients/dnpedia.rb +64 -0
  25. data/lib/mihari/clients/dnstwister.rb +40 -0
  26. data/lib/mihari/clients/greynoise.rb +29 -0
  27. data/lib/mihari/clients/misp.rb +24 -0
  28. data/lib/mihari/clients/onyphe.rb +23 -0
  29. data/lib/mihari/clients/otx.rb +29 -0
  30. data/lib/mihari/clients/passivetotal.rb +65 -0
  31. data/lib/mihari/clients/publsedive.rb +39 -0
  32. data/lib/mihari/clients/shodan.rb +30 -0
  33. data/lib/mihari/clients/the_hive.rb +28 -0
  34. data/lib/mihari/clients/urlscan.rb +31 -0
  35. data/lib/mihari/clients/virustotal.rb +56 -0
  36. data/lib/mihari/clients/zoomeye.rb +68 -0
  37. data/lib/mihari/emitters/misp.rb +13 -20
  38. data/lib/mihari/emitters/the_hive.rb +3 -5
  39. data/lib/mihari/emitters/webhook.rb +2 -2
  40. data/lib/mihari/feed/reader.rb +14 -11
  41. data/lib/mihari/http.rb +29 -21
  42. data/lib/mihari/mixins/retriable.rb +3 -1
  43. data/lib/mihari/schemas/analyzer.rb +5 -4
  44. data/lib/mihari/version.rb +1 -1
  45. data/lib/mihari.rb +21 -0
  46. data/mihari.gemspec +13 -20
  47. metadata +51 -244
  48. data/lib/mihari/analyzers/clients/otx.rb +0 -36
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "misp"
4
-
5
3
  module Mihari
6
4
  module Emitters
7
5
  class MISP < Base
@@ -16,11 +14,6 @@ module Mihari
16
14
 
17
15
  @url = kwargs[:url] || Mihari.config.misp_url
18
16
  @api_key = kwargs[:api_key] || Mihari.config.misp_api_key
19
-
20
- ::MISP.configure do |config|
21
- config.api_endpoint = url
22
- config.api_key = api_key
23
- end
24
17
  end
25
18
 
26
19
  # @return [Boolean]
@@ -50,17 +43,13 @@ module Mihari
50
43
  def emit(rule:, artifacts:, **_options)
51
44
  return if artifacts.empty?
52
45
 
53
- event = ::MISP::Event.new(info: rule.title)
54
-
55
- artifacts.each do |artifact|
56
- event.attributes << build_attribute(artifact)
57
- end
58
-
59
- rule.tags.each do |tag|
60
- event.add_tag name: tag
61
- end
62
-
63
- event.create
46
+ client.create_event({
47
+ Event: {
48
+ info: rule.title
49
+ },
50
+ Attribute: artifacts.map { |artifact| build_attribute(artifact) },
51
+ Tag: rule.tags.map { |tag| { name: tag } }
52
+ })
64
53
  end
65
54
 
66
55
  private
@@ -69,15 +58,19 @@ module Mihari
69
58
  %w[misp_url misp_api_key]
70
59
  end
71
60
 
61
+ def client
62
+ @client ||= Clients::MISP.new(url, api_key: api_key)
63
+ end
64
+
72
65
  #
73
66
  # Build a MISP attribute
74
67
  #
75
68
  # @param [Mihari::Artifact] artifact
76
69
  #
77
- # @return [::MISP::Attribute]
70
+ # @return [Hash]
78
71
  #
79
72
  def build_attribute(artifact)
80
- ::MISP::Attribute.new(value: artifact.data, type: to_misp_type(type: artifact.data_type, value: artifact.data))
73
+ { value: artifact.data, type: to_misp_type(type: artifact.data_type, value: artifact.data) }
81
74
  end
82
75
 
83
76
  #
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "hachi"
4
-
5
3
  module Mihari
6
4
  module Emitters
7
5
  class TheHive < Base
@@ -50,7 +48,7 @@ module Mihari
50
48
  return if artifacts.empty?
51
49
 
52
50
  payload = payload(rule: rule, artifacts: artifacts)
53
- api.alert.create(**payload)
51
+ client.alert(payload)
54
52
  end
55
53
 
56
54
  #
@@ -79,8 +77,8 @@ module Mihari
79
77
  %w[thehive_url thehive_api_key]
80
78
  end
81
79
 
82
- def api
83
- @api ||= Hachi::API.new(api_endpoint: url, api_key: api_key, api_version: normalized_api_version)
80
+ def client
81
+ @client ||= Clients::TheHive.new(url, api_key: api_key, api_version: normalized_api_version)
84
82
  end
85
83
 
86
84
  #
@@ -77,13 +77,13 @@ module Mihari
77
77
  payload_ = payload_as_string(artifacts: artifacts, rule: rule)
78
78
  payload = JSON.parse(payload_)
79
79
 
80
- client = Mihari::HTTP.new(url, headers: headers, payload: payload)
80
+ client = Mihari::HTTP.new(url, headers: headers)
81
81
 
82
82
  case method
83
83
  when "GET"
84
84
  res = client.get
85
85
  when "POST"
86
- res = client.post
86
+ res = client.post(json: payload)
87
87
  end
88
88
 
89
89
  res
@@ -6,25 +6,28 @@ require "insensitive_hash"
6
6
  module Mihari
7
7
  module Feed
8
8
  class Reader
9
- attr_reader :uri, :http_request_headers, :http_request_method, :http_request_payload
9
+ attr_reader :url, :headers, :params, :json, :data, :method
10
10
 
11
- def initialize(uri, http_request_headers: {}, http_request_method: "GET", http_request_payload_type: nil, http_request_payload: {})
12
- @uri = Addressable::URI.parse(uri)
13
- @http_request_headers = http_request_headers.insensitive
14
- @http_request_method = http_request_method
15
- @http_request_payload = http_request_payload
11
+ def initialize(url, headers: {}, method: "GET", params: nil, json: nil, data: nil)
12
+ @url = Addressable::URI.parse(url)
13
+ @headers = headers.insensitive
14
+ @method = method
16
15
 
17
- http_request_headers["content-type"] = http_request_payload_type if http_request_payload_type
16
+ @params = params
17
+ @json = json
18
+ @data = data
19
+
20
+ headers["content-type"] = "application/json" unless json.nil?
18
21
  end
19
22
 
20
23
  def read
21
- return read_file(uri.path) if uri.scheme == "file"
24
+ return read_file(url.path) if url.scheme == "file"
22
25
 
23
26
  res = nil
24
- client = HTTP.new(uri, headers: http_request_headers, payload: http_request_payload)
27
+ client = HTTP.new(url, headers: headers)
25
28
 
26
- res = client.get if http_request_method == "GET"
27
- res = client.post if http_request_method == "POST"
29
+ res = client.get(params: params) if method == "GET"
30
+ res = client.post(params: params, json: json, data: data) if method == "POST"
28
31
 
29
32
  return [] if res.nil?
30
33
 
data/lib/mihari/http.rb CHANGED
@@ -4,54 +4,62 @@ require "insensitive_hash"
4
4
 
5
5
  module Mihari
6
6
  class HTTP
7
- attr_reader :url, :headers, :payload
7
+ # @return [String]
8
+ attr_reader :url
8
9
 
9
- def initialize(url, headers: {}, payload: {})
10
+ # @return [Hash]
11
+ attr_reader :headers
12
+
13
+ def initialize(url, headers: {})
10
14
  @url = url.is_a?(URI) ? url : URI(url.to_s)
11
15
  @headers = headers.insensitive
12
- @payload = payload
13
16
  end
14
17
 
15
18
  #
16
19
  # Make a GET request
17
20
  #
21
+ # @param [Hash, nil] params
22
+ #
18
23
  # @return [Net::HTTPResponse]
19
24
  #
20
- def get
25
+ def get(params: nil)
21
26
  new_url = url.deep_dup
22
- new_url.query = Addressable::URI.form_encode(payload) unless payload.empty?
27
+ new_url.query = Addressable::URI.form_encode(params) unless (params || {}).empty?
23
28
 
24
29
  get = Net::HTTP::Get.new(new_url)
25
30
  request get
26
31
  end
27
32
 
28
33
  #
29
- # Make a POST request
34
+ # Make a POST requesti
35
+ #
36
+ # @param [Hash, nil] params
37
+ # @param [Hash, nil] json
38
+ # @param [Hash, nil] data
30
39
  #
31
40
  # @return [Net::HTTPResponse]
32
41
  #
33
- def post
34
- post = Net::HTTP::Post.new(url)
35
-
36
- case content_type
37
- when "application/json"
38
- post.body = JSON.generate(payload)
39
- when "application/x-www-form-urlencoded"
40
- post.set_form_data(payload)
41
- end
42
+ def post(params: nil, json: nil, data: nil)
43
+ new_url = url.deep_dup
44
+ new_url.query = Addressable::URI.form_encode(params) unless (params || {}).empty?
45
+
46
+ post = Net::HTTP::Post.new(new_url)
47
+
48
+ post.body = JSON.generate(json) if json
49
+ post.set_form_data(data) if data
42
50
 
43
51
  request post
44
52
  end
45
53
 
46
54
  class << self
47
- def get(url, headers: {}, params: {})
48
- client = new(url, headers: headers, payload: params)
49
- client.get
55
+ def get(url, headers: {}, params: nil)
56
+ client = new(url, headers: headers)
57
+ client.get(params: params)
50
58
  end
51
59
 
52
- def post(url, headers: {}, payload: {})
53
- client = new(url, headers: headers, payload: payload)
54
- client.post
60
+ def post(url, headers: {}, params: nil, json: nil, data: nil)
61
+ client = new(url, headers: headers)
62
+ client.post(params: params, json: json, data: data)
55
63
  end
56
64
  end
57
65
 
@@ -9,7 +9,9 @@ module Mihari
9
9
  Errno::EPIPE,
10
10
  OpenSSL::SSL::SSLError,
11
11
  Timeout::Error,
12
- RetryableError
12
+ RetryableError,
13
+ NetworkError,
14
+ TimeoutError
13
15
  ]
14
16
 
15
17
  #
@@ -82,10 +82,11 @@ module Mihari
82
82
  required(:analyzer).value(Types::String.enum("feed"))
83
83
  required(:query).value(:string)
84
84
  required(:selector).value(:string)
85
- optional(:http_request_method).value(Types::HTTPRequestMethods).default("GET")
86
- optional(:http_request_headers).value(:hash).default({})
87
- optional(:http_request_payload).value(:hash).default({})
88
- optional(:http_request_payload_type).value(Types::HTTPRequestPayloadTypes)
85
+ optional(:method).value(Types::HTTPRequestMethods).default("GET")
86
+ optional(:headers).value(:hash).default({})
87
+ optional(:params).value(:hash)
88
+ optional(:data).value(:hash)
89
+ optional(:json).value(:hash)
89
90
  optional(:options).hash(AnalyzerOptions)
90
91
  end
91
92
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- VERSION = "5.1.0"
4
+ VERSION = "5.1.1"
5
5
  end
data/lib/mihari.rb CHANGED
@@ -212,6 +212,27 @@ require "mihari/emitters/slack"
212
212
  require "mihari/emitters/the_hive"
213
213
  require "mihari/emitters/webhook"
214
214
 
215
+ # Clients
216
+ require "mihari/clients/base"
217
+
218
+ require "mihari/clients/binaryedge"
219
+ require "mihari/clients/censys"
220
+ require "mihari/clients/circl"
221
+ require "mihari/clients/crtsh"
222
+ require "mihari/clients/dnpedia"
223
+ require "mihari/clients/dnstwister"
224
+ require "mihari/clients/greynoise"
225
+ require "mihari/clients/misp"
226
+ require "mihari/clients/onyphe"
227
+ require "mihari/clients/otx"
228
+ require "mihari/clients/passivetotal"
229
+ require "mihari/clients/publsedive"
230
+ require "mihari/clients/shodan"
231
+ require "mihari/clients/the_hive"
232
+ require "mihari/clients/urlscan"
233
+ require "mihari/clients/virustotal"
234
+ require "mihari/clients/zoomeye"
235
+
215
236
  # Analyzers
216
237
  require "mihari/analyzers/base"
217
238
 
data/mihari.gemspec CHANGED
@@ -4,6 +4,11 @@ lib = File.expand_path("lib", __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require "mihari/version"
6
6
 
7
+ def ci_env?
8
+ # CI=true in GitHub Actions
9
+ ENV["CI"]
10
+ end
11
+
7
12
  Gem::Specification.new do |spec|
8
13
  spec.name = "mihari"
9
14
  spec.version = Mihari::VERSION
@@ -32,7 +37,6 @@ Gem::Specification.new do |spec|
32
37
  spec.add_development_dependency "fakefs", "~> 2.4"
33
38
  spec.add_development_dependency "fuubar", "~> 2.5"
34
39
  spec.add_development_dependency "mysql2", "~> 0.5"
35
- spec.add_development_dependency "overcommit", "~> 0.60"
36
40
  spec.add_development_dependency "pg", "~> 1.4"
37
41
  spec.add_development_dependency "rack-test", "~> 2.0"
38
42
  spec.add_development_dependency "rake", "~> 13.0"
@@ -41,19 +45,19 @@ Gem::Specification.new do |spec|
41
45
  spec.add_development_dependency "rspec", "~> 3.12"
42
46
  spec.add_development_dependency "simplecov-lcov", "~> 0.8.0"
43
47
  spec.add_development_dependency "standard", "~> 1.24"
44
- spec.add_development_dependency "steep", "~> 1.3"
45
48
  spec.add_development_dependency "timecop", "~> 0.9"
46
49
  spec.add_development_dependency "vcr", "~> 6.1"
47
50
  spec.add_development_dependency "webmock", "~> 3.18"
48
51
 
52
+ unless ci_env?
53
+ spec.add_development_dependency "overcommit", "~> 0.60"
54
+ spec.add_development_dependency "ruby-lsp", "~> 0.4"
55
+ spec.add_development_dependency "steep", "~> 1.3"
56
+ end
57
+
49
58
  spec.add_dependency "activerecord", "7.0.4.2"
50
59
  spec.add_dependency "addressable", "2.8.1"
51
60
  spec.add_dependency "awrence", "2.0.1"
52
- spec.add_dependency "binaryedge", "0.1.0"
53
- spec.add_dependency "censysx", "0.1.1"
54
- spec.add_dependency "crtsh-rb", "0.3.1"
55
- spec.add_dependency "dnpedia", "0.1.0"
56
- spec.add_dependency "dnstwister", "0.1.0"
57
61
  spec.add_dependency "dotenv", "2.8.1"
58
62
  spec.add_dependency "dry-configurable", "1.0.1"
59
63
  spec.add_dependency "dry-container", "0.11.0"
@@ -67,37 +71,26 @@ Gem::Specification.new do |spec|
67
71
  spec.add_dependency "grape-entity", "1.0.0"
68
72
  spec.add_dependency "grape-swagger", "1.5.0"
69
73
  spec.add_dependency "grape-swagger-entity", "0.5.1"
70
- spec.add_dependency "greynoise", "0.1.1"
71
- spec.add_dependency "hachi", "2.0.0"
72
74
  spec.add_dependency "insensitive_hash", "0.3.3"
73
75
  spec.add_dependency "jr-cli", "0.6.0"
74
76
  spec.add_dependency "launchy", "2.5.2"
75
77
  spec.add_dependency "memist", "2.0.2"
76
- spec.add_dependency "misp", "0.1.4"
77
78
  spec.add_dependency "net-ping", "2.0.8"
78
79
  spec.add_dependency "normalize_country", "0.3.2"
79
- spec.add_dependency "onyphe", "2.0.0"
80
80
  spec.add_dependency "parallel", "1.22.1"
81
- spec.add_dependency "passive_circl", "0.1.0"
82
- spec.add_dependency "passivetotalx", "0.1.1"
83
81
  spec.add_dependency "plissken", "2.0.1"
84
82
  spec.add_dependency "public_suffix", "5.0.1"
85
- spec.add_dependency "pulsedive", "0.1.5"
86
83
  spec.add_dependency "puma", "6.0.2"
87
84
  spec.add_dependency "rack", "2.2.4"
88
85
  spec.add_dependency "rack-contrib", "2.3.0"
89
86
  spec.add_dependency "rack-cors", "1.1.1"
90
87
  spec.add_dependency "securitytrails", "1.0.0"
91
88
  spec.add_dependency "semantic_logger", "4.12.0"
92
- spec.add_dependency "sentry-ruby", "5.7.0"
93
- spec.add_dependency "shodanx", "0.2.1"
89
+ spec.add_dependency "sentry-ruby", "5.8.0"
94
90
  spec.add_dependency "slack-notifier", "2.4.0"
95
- spec.add_dependency "sqlite3", "1.6.0"
91
+ spec.add_dependency "sqlite3", "1.6.1"
96
92
  spec.add_dependency "thor", "1.2.1"
97
- spec.add_dependency "urlscan", "0.8.0"
98
93
  spec.add_dependency "uuidtools", "2.2.0"
99
- spec.add_dependency "virustotalx", "1.2.0"
100
94
  spec.add_dependency "whois", "5.1.0"
101
95
  spec.add_dependency "whois-parser", "2.0.0"
102
- spec.add_dependency "zoomeye-rb", "0.2.0"
103
96
  end