mihari 0.17.5 → 1.0.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/.gitignore +3 -0
- data/.rubocop.yml +155 -0
- data/.travis.yml +1 -0
- data/Gemfile +2 -0
- data/README.md +30 -72
- data/config/pre_commit.yml +3 -0
- data/lib/mihari.rb +12 -8
- data/lib/mihari/alert_viewer.rb +6 -28
- data/lib/mihari/analyzers/base.rb +7 -19
- data/lib/mihari/analyzers/basic.rb +3 -1
- data/lib/mihari/analyzers/binaryedge.rb +2 -2
- data/lib/mihari/analyzers/censys.rb +2 -2
- data/lib/mihari/analyzers/circl.rb +2 -2
- data/lib/mihari/analyzers/onyphe.rb +3 -3
- data/lib/mihari/analyzers/passivetotal.rb +2 -2
- data/lib/mihari/analyzers/pulsedive.rb +2 -2
- data/lib/mihari/analyzers/securitytrails.rb +2 -2
- data/lib/mihari/analyzers/securitytrails_domain_feed.rb +2 -2
- data/lib/mihari/analyzers/shodan.rb +2 -2
- data/lib/mihari/analyzers/virustotal.rb +2 -2
- data/lib/mihari/analyzers/zoomeye.rb +2 -2
- data/lib/mihari/cli.rb +2 -2
- data/lib/mihari/config.rb +68 -2
- data/lib/mihari/configurable.rb +1 -1
- data/lib/mihari/database.rb +45 -0
- data/lib/mihari/emitters/base.rb +1 -1
- data/lib/mihari/emitters/misp.rb +8 -1
- data/lib/mihari/emitters/slack.rb +2 -2
- data/lib/mihari/emitters/sqlite.rb +29 -0
- data/lib/mihari/emitters/stdout.rb +2 -1
- data/lib/mihari/emitters/the_hive.rb +28 -14
- data/lib/mihari/models/alert.rb +11 -0
- data/lib/mihari/models/artifact.rb +27 -0
- data/lib/mihari/models/tag.rb +10 -0
- data/lib/mihari/models/tagging.rb +10 -0
- data/lib/mihari/notifiers/slack.rb +4 -4
- data/lib/mihari/serializers/alert.rb +12 -0
- data/lib/mihari/serializers/artifact.rb +9 -0
- data/lib/mihari/serializers/tag.rb +9 -0
- data/lib/mihari/status.rb +1 -1
- data/lib/mihari/type_checker.rb +1 -1
- data/lib/mihari/version.rb +1 -1
- data/mihari.gemspec +11 -5
- metadata +120 -31
- data/lib/mihari/artifact.rb +0 -36
- data/lib/mihari/cache.rb +0 -35
- data/lib/mihari/the_hive.rb +0 -42
- data/lib/mihari/the_hive/alert.rb +0 -25
- data/lib/mihari/the_hive/artifact.rb +0 -33
- data/lib/mihari/the_hive/base.rb +0 -14
data/lib/mihari/artifact.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mihari
|
4
|
-
class Artifact
|
5
|
-
attr_reader :data
|
6
|
-
|
7
|
-
#
|
8
|
-
# @param [String] data
|
9
|
-
# @param [String, nil] message
|
10
|
-
#
|
11
|
-
def initialize(data, message: nil)
|
12
|
-
@data = data
|
13
|
-
@message = message
|
14
|
-
end
|
15
|
-
|
16
|
-
# @return [String, nil]
|
17
|
-
def data_type
|
18
|
-
TypeChecker.type data
|
19
|
-
end
|
20
|
-
|
21
|
-
# @return [String]
|
22
|
-
def message
|
23
|
-
@mesasge || data
|
24
|
-
end
|
25
|
-
|
26
|
-
# @return [true, false]
|
27
|
-
def valid?
|
28
|
-
!data_type.nil?
|
29
|
-
end
|
30
|
-
|
31
|
-
# @return [Hash]
|
32
|
-
def to_h
|
33
|
-
{ data: data, data_type: data_type, message: message }
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
data/lib/mihari/cache.rb
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "lightly"
|
4
|
-
|
5
|
-
module Mihari
|
6
|
-
class Cache
|
7
|
-
DEFAULT_CACHE_DIR = "/tmp/mihari"
|
8
|
-
|
9
|
-
def initialize
|
10
|
-
@data = Lightly.new(life: "7d", dir: DEFAULT_CACHE_DIR)
|
11
|
-
end
|
12
|
-
|
13
|
-
def cached?(key)
|
14
|
-
return false unless @data.enabled?
|
15
|
-
|
16
|
-
begin
|
17
|
-
@data.cached? key
|
18
|
-
rescue Errno::ENOENT => _e
|
19
|
-
false
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def save(*keys)
|
24
|
-
return unless @data.enabled?
|
25
|
-
|
26
|
-
begin
|
27
|
-
keys.flatten.each do |key|
|
28
|
-
@data.save key, true
|
29
|
-
end
|
30
|
-
rescue Errno::ENOENT => _e
|
31
|
-
nil
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
data/lib/mihari/the_hive.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "net/ping"
|
4
|
-
require "uri"
|
5
|
-
|
6
|
-
module Mihari
|
7
|
-
class TheHive
|
8
|
-
attr_reader :artifact
|
9
|
-
attr_reader :alert
|
10
|
-
|
11
|
-
def initialize
|
12
|
-
@artifact = Artifact.new
|
13
|
-
@alert = Alert.new
|
14
|
-
end
|
15
|
-
|
16
|
-
# @return [true, false]
|
17
|
-
def valid?
|
18
|
-
api_endpont? && api_key? && ping?
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
# @return [true, false]
|
24
|
-
def api_endpont?
|
25
|
-
ENV.key? "THEHIVE_API_ENDPOINT"
|
26
|
-
end
|
27
|
-
|
28
|
-
# @return [true, false]
|
29
|
-
def api_key?
|
30
|
-
ENV.key? "THEHIVE_API_KEY"
|
31
|
-
end
|
32
|
-
|
33
|
-
def ping?
|
34
|
-
base_url = ENV.fetch("THEHIVE_API_ENDPOINT")
|
35
|
-
base_url = base_url.end_with?("/") ? base_url[0..-2] : base_url
|
36
|
-
url = "#{base_url}/index.html"
|
37
|
-
|
38
|
-
http = Net::Ping::HTTP.new(url)
|
39
|
-
http.ping?
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mihari
|
4
|
-
class TheHive
|
5
|
-
class Alert < Base
|
6
|
-
# @return [Array]
|
7
|
-
def list(range: "all", sort: "-date")
|
8
|
-
alerts = api.alert.search({ source: "mihari" }, range: range, sort: sort)
|
9
|
-
alerts.sort_by { |alert| -alert.dig("createdAt") }
|
10
|
-
end
|
11
|
-
|
12
|
-
# @return [Hash]
|
13
|
-
def create(title:, description:, artifacts:, tags: [])
|
14
|
-
api.alert.create(
|
15
|
-
title: title,
|
16
|
-
description: description,
|
17
|
-
artifacts: artifacts,
|
18
|
-
tags: tags,
|
19
|
-
type: "external",
|
20
|
-
source: "mihari"
|
21
|
-
)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mihari
|
4
|
-
class TheHive
|
5
|
-
class Artifact < Base
|
6
|
-
# @return [Array]
|
7
|
-
def search(data:, data_type:, range: "all")
|
8
|
-
api.artifact.search({ data: data, data_type: data_type }, range: range)
|
9
|
-
end
|
10
|
-
|
11
|
-
# @return [Array]
|
12
|
-
def search_all(data:, range: "all")
|
13
|
-
api.artifact.search({ data: data }, range: range)
|
14
|
-
end
|
15
|
-
|
16
|
-
# @return [true, false]
|
17
|
-
def exists?(data:, data_type:)
|
18
|
-
res = search(data: data, data_type: data_type, range: "0-1")
|
19
|
-
!res.empty?
|
20
|
-
end
|
21
|
-
|
22
|
-
# @return [Array<Mihari::Artifact>]
|
23
|
-
def find_non_existing_artifacts(artifacts)
|
24
|
-
data = artifacts.map(&:data)
|
25
|
-
results = search_all(data: data)
|
26
|
-
keys = results.map { |result| result.dig("data") }.compact.uniq
|
27
|
-
artifacts.reject do |artifact|
|
28
|
-
keys.include? artifact.data
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|