mihari 4.5.3 → 4.7.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/lib/mihari/analyzers/rule.rb +17 -0
- data/lib/mihari/constants.rb +2 -0
- data/lib/mihari/emitters/the_hive.rb +69 -10
- data/lib/mihari/emitters/webhook.rb +1 -1
- data/lib/mihari/enrichers/google_public_dns.rb +36 -0
- data/lib/mihari/enrichers/whois.rb +126 -0
- data/lib/mihari/http.rb +2 -2
- data/lib/mihari/models/artifact.rb +30 -0
- data/lib/mihari/models/cpe.rb +1 -1
- data/lib/mihari/models/dns.rb +5 -21
- data/lib/mihari/models/reverse_dns.rb +1 -1
- data/lib/mihari/models/whois.rb +1 -96
- data/lib/mihari/schemas/emitter.rb +1 -0
- data/lib/mihari/schemas/enricher.rb +9 -0
- data/lib/mihari/schemas/rule.rb +6 -0
- data/lib/mihari/structs/google_public_dns.rb +42 -0
- data/lib/mihari/structs/rule.rb +2 -1
- data/lib/mihari/structs/virustotal_intelligence.rb +2 -2
- data/lib/mihari/types.rb +7 -0
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/app.rb +3 -0
- data/lib/mihari.rb +52 -28
- data/mihari.gemspec +11 -11
- data/sig/lib/mihari/emitters/the_hive.rbs +4 -0
- data/sig/lib/mihari/enrichers/google_public_dns.rbs +18 -0
- data/sig/lib/mihari/structs/google_public_dns.rbs +21 -0
- data/sig/lib/mihari.rbs +1 -0
- metadata +30 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '091892853042ab3f1010c89b943eb2a885370da2d619016f3f3cd9dcb59e80cf'
|
4
|
+
data.tar.gz: 119ccbb407a49c741a4bf6c7cfafc7cd99855c3af950af9d0f1dc3735fc24672
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5364837634a6cde1b370db5613e745f05b40bf7321a5b7fcc4a2c7d32b1d395fa45e4472ef2a5f9f28d664f0b45e31d0554acec7bb641a21ce179ebf70bf9317
|
7
|
+
data.tar.gz: 57ca2f920db2da9e8c9a10f59aa81984dff0a81f0073ba839c351f3fe5e7979358ce44d87f48adcffd7df1bf7268bab178fec82731f72d62c24aa9ce04eed026
|
@@ -51,6 +51,7 @@ module Mihari
|
|
51
51
|
option :disallowed_data_values, default: proc { [] }
|
52
52
|
|
53
53
|
option :emitters, optional: true
|
54
|
+
option :enrichers, optional: true
|
54
55
|
|
55
56
|
attr_reader :source
|
56
57
|
|
@@ -60,6 +61,7 @@ module Mihari
|
|
60
61
|
@source = id
|
61
62
|
|
62
63
|
@emitters = emitters || DEFAULT_EMITTERS
|
64
|
+
@enrichers = enrichers || DEFAULT_ENRICHERS
|
63
65
|
|
64
66
|
validate_analyzer_configurations
|
65
67
|
end
|
@@ -112,6 +114,21 @@ module Mihari
|
|
112
114
|
end
|
113
115
|
end
|
114
116
|
|
117
|
+
#
|
118
|
+
# Enriched artifacts
|
119
|
+
#
|
120
|
+
# @return [Array<Mihari::Artifact>]
|
121
|
+
#
|
122
|
+
def enriched_artifacts
|
123
|
+
@enriched_artifacts ||= Parallel.map(unique_artifacts) do |artifact|
|
124
|
+
enrichers.each do |enricher|
|
125
|
+
artifact.enrich_by_enricher(enricher[:enricher])
|
126
|
+
end
|
127
|
+
|
128
|
+
artifact
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
115
132
|
#
|
116
133
|
# Normalized disallowed data values
|
117
134
|
#
|
data/lib/mihari/constants.rb
CHANGED
@@ -4,4 +4,6 @@ module Mihari
|
|
4
4
|
ALLOWED_DATA_TYPES = ["hash", "ip", "domain", "url", "mail"].freeze
|
5
5
|
|
6
6
|
DEFAULT_EMITTERS = ["database", "misp", "slack", "the_hive", "webhook"].map { |name| { emitter: name } }.freeze
|
7
|
+
|
8
|
+
DEFAULT_ENRICHERS = ["whois", "ipinfo", "shodan", "google_public_dns"].map { |name| { enricher: name } }.freeze
|
7
9
|
end
|
@@ -11,11 +11,15 @@ module Mihari
|
|
11
11
|
# @return [String, nil]
|
12
12
|
attr_reader :api_key
|
13
13
|
|
14
|
+
# @return [String, nil]
|
15
|
+
attr_reader :api_version
|
16
|
+
|
14
17
|
def initialize(*args, **kwargs)
|
15
18
|
super(*args, **kwargs)
|
16
19
|
|
17
20
|
@api_endpoint = kwargs[:api_endpoint] || Mihari.config.thehive_api_endpoint
|
18
21
|
@api_key = kwargs[:api_key] || Mihari.config.thehive_api_key
|
22
|
+
@api_version = kwargs[:api_version] || Mihari.config.thehive_api_version
|
19
23
|
end
|
20
24
|
|
21
25
|
# @return [Boolean]
|
@@ -26,14 +30,28 @@ module Mihari
|
|
26
30
|
def emit(title:, description:, artifacts:, tags: [], **_options)
|
27
31
|
return if artifacts.empty?
|
28
32
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
payload = payload(title: title, description: description, artifacts: artifacts, tags: tags)
|
34
|
+
api.alert.create(**payload)
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# Normalize API version for API client
|
39
|
+
#
|
40
|
+
# @param [String] version
|
41
|
+
#
|
42
|
+
# @return [String, nil]
|
43
|
+
#
|
44
|
+
def normalized_api_version
|
45
|
+
@normalized_api_version ||= [].tap do |out|
|
46
|
+
# v4 does not have version prefix in path (/api/)
|
47
|
+
# v5 has version prefix in path (/api/v1/)
|
48
|
+
table = {
|
49
|
+
"" => nil,
|
50
|
+
"v4" => nil,
|
51
|
+
"v5" => "v1"
|
52
|
+
}
|
53
|
+
out << table[api_version.to_s.downcase]
|
54
|
+
end.first
|
37
55
|
end
|
38
56
|
|
39
57
|
private
|
@@ -43,7 +61,7 @@ module Mihari
|
|
43
61
|
end
|
44
62
|
|
45
63
|
def api
|
46
|
-
@api ||= Hachi::API.new(api_endpoint: api_endpoint, api_key: api_key)
|
64
|
+
@api ||= Hachi::API.new(api_endpoint: api_endpoint, api_key: api_key, api_version: normalized_api_version)
|
47
65
|
end
|
48
66
|
|
49
67
|
#
|
@@ -64,6 +82,35 @@ module Mihari
|
|
64
82
|
!api_key.nil?
|
65
83
|
end
|
66
84
|
|
85
|
+
def payload(title:, description:, artifacts:, tags: [])
|
86
|
+
return v4_payload(title: title, description: description, artifacts: artifacts, tags: tags) if normalized_api_version.nil?
|
87
|
+
|
88
|
+
v5_payload(title: title, description: description, artifacts: artifacts, tags: tags)
|
89
|
+
end
|
90
|
+
|
91
|
+
def v4_payload(title:, description:, artifacts:, tags: [])
|
92
|
+
{
|
93
|
+
title: title,
|
94
|
+
description: description,
|
95
|
+
artifacts: artifacts.map { |artifact| { data: artifact.data, data_type: artifact.data_type, message: description } },
|
96
|
+
tags: tags,
|
97
|
+
type: "external",
|
98
|
+
source: "mihari"
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
def v5_payload(title:, description:, artifacts:, tags: [])
|
103
|
+
{
|
104
|
+
title: title,
|
105
|
+
description: description,
|
106
|
+
observables: artifacts.map { |artifact| { data: artifact.data, data_type: artifact.data_type, message: description } },
|
107
|
+
tags: tags,
|
108
|
+
type: "external",
|
109
|
+
source: "mihari",
|
110
|
+
source_ref: "1"
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
67
114
|
#
|
68
115
|
# Check whether an API endpoint is reachable or not
|
69
116
|
#
|
@@ -71,9 +118,21 @@ module Mihari
|
|
71
118
|
#
|
72
119
|
def ping?
|
73
120
|
base_url = api_endpoint.end_with?("/") ? api_endpoint[0..-2] : api_endpoint
|
74
|
-
|
121
|
+
|
122
|
+
if normalized_api_version.nil?
|
123
|
+
# for v4
|
124
|
+
base_url = api_endpoint.end_with?("/") ? api_endpoint[0..-2] : api_endpoint
|
125
|
+
url = "#{base_url}/index.html"
|
126
|
+
else
|
127
|
+
# for v5
|
128
|
+
url = "#{base_url}/api/v1/status/public"
|
129
|
+
end
|
75
130
|
|
76
131
|
http = Net::Ping::HTTP.new(url)
|
132
|
+
|
133
|
+
# use GET for v5
|
134
|
+
http.get_request = true if normalized_api_version
|
135
|
+
|
77
136
|
http.ping?
|
78
137
|
end
|
79
138
|
end
|
@@ -11,7 +11,7 @@ module Mihari
|
|
11
11
|
def emit(title:, description:, artifacts:, source:, tags:)
|
12
12
|
return if artifacts.empty?
|
13
13
|
|
14
|
-
headers = {
|
14
|
+
headers = { "content-type": "application/x-www-form-urlencoded" }
|
15
15
|
headers["content-type"] = "application/json" if use_json_body?
|
16
16
|
|
17
17
|
emitter = Emitters::HTTP.new(uri: Mihari.config.webhook_url)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "net/https"
|
4
|
+
|
5
|
+
module Mihari
|
6
|
+
module Enrichers
|
7
|
+
class GooglePublicDNS < Base
|
8
|
+
# @return [Boolean]
|
9
|
+
def valid?
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
#
|
15
|
+
# Query Google Public DNS
|
16
|
+
#
|
17
|
+
# @param [String] name
|
18
|
+
# @param [String] resource_type
|
19
|
+
#
|
20
|
+
# @return [Mihari::Structs::Shodan::GooglePublicDNS::Response, nil]
|
21
|
+
#
|
22
|
+
def query(name, resource_type)
|
23
|
+
url = "https://dns.google/resolve"
|
24
|
+
params = { name: name, type: resource_type }
|
25
|
+
res = HTTP.get(url, params: params)
|
26
|
+
|
27
|
+
data = JSON.parse(res.body.to_s)
|
28
|
+
|
29
|
+
Structs::GooglePublicDNS::Response.from_dynamic! data
|
30
|
+
rescue HTTPError
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "whois-parser"
|
4
|
+
|
5
|
+
module Mihari
|
6
|
+
module Enrichers
|
7
|
+
class Whois < Base
|
8
|
+
@memo = {}
|
9
|
+
|
10
|
+
# @return [Boolean]
|
11
|
+
def valid?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
#
|
17
|
+
# Query IAIA Whois API
|
18
|
+
#
|
19
|
+
# @param [String] name
|
20
|
+
#
|
21
|
+
# @return [Mihari::WhoisRecord, nil]
|
22
|
+
#
|
23
|
+
def query(domain)
|
24
|
+
domain = PublicSuffix.domain(domain)
|
25
|
+
|
26
|
+
# check memo
|
27
|
+
if @memo.key?(domain)
|
28
|
+
whois_record = @memo[domain]
|
29
|
+
# return clone of the record
|
30
|
+
return whois_record.dup
|
31
|
+
end
|
32
|
+
|
33
|
+
record = ::Whois.whois(domain)
|
34
|
+
parser = record.parser
|
35
|
+
|
36
|
+
return nil if parser.available?
|
37
|
+
|
38
|
+
whois_record = WhoisRecord.new(
|
39
|
+
domain: domain,
|
40
|
+
created_on: get_created_on(parser),
|
41
|
+
updated_on: get_updated_on(parser),
|
42
|
+
expires_on: get_expires_on(parser),
|
43
|
+
registrar: get_registrar(parser),
|
44
|
+
contacts: get_contacts(parser)
|
45
|
+
)
|
46
|
+
# set memo
|
47
|
+
@memo[domain] = whois_record
|
48
|
+
whois_record
|
49
|
+
rescue ::Whois::Error, ::Whois::ParserError, Timeout::Error
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def reset_cache
|
54
|
+
@memo = {}
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
#
|
60
|
+
# Get created_on
|
61
|
+
#
|
62
|
+
# @param [::Whois::Parser:] parser
|
63
|
+
#
|
64
|
+
# @return [Date, nil]
|
65
|
+
#
|
66
|
+
def get_created_on(parser)
|
67
|
+
parser.created_on
|
68
|
+
rescue ::Whois::AttributeNotImplemented
|
69
|
+
nil
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# Get updated_on
|
74
|
+
#
|
75
|
+
# @param [::Whois::Parser:] parser
|
76
|
+
#
|
77
|
+
# @return [Date, nil]
|
78
|
+
#
|
79
|
+
def get_updated_on(parser)
|
80
|
+
parser.updated_on
|
81
|
+
rescue ::Whois::AttributeNotImplemented
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
|
85
|
+
#
|
86
|
+
# Get expires_on
|
87
|
+
#
|
88
|
+
# @param [::Whois::Parser:] parser
|
89
|
+
#
|
90
|
+
# @return [Date, nil]
|
91
|
+
#
|
92
|
+
def get_expires_on(parser)
|
93
|
+
parser.expires_on
|
94
|
+
rescue ::Whois::AttributeNotImplemented
|
95
|
+
nil
|
96
|
+
end
|
97
|
+
|
98
|
+
#
|
99
|
+
# Get registrar
|
100
|
+
#
|
101
|
+
# @param [::Whois::Parser:] parser
|
102
|
+
#
|
103
|
+
# @return [Hash, nil]
|
104
|
+
#
|
105
|
+
def get_registrar(parser)
|
106
|
+
parser.registrar&.to_h
|
107
|
+
rescue ::Whois::AttributeNotImplemented
|
108
|
+
nil
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# Get contacts
|
113
|
+
#
|
114
|
+
# @param [::Whois::Parser:] parser
|
115
|
+
#
|
116
|
+
# @return [Array[Hash], nil]
|
117
|
+
#
|
118
|
+
def get_contacts(parser)
|
119
|
+
parser.contacts.map(&:to_h)
|
120
|
+
rescue ::Whois::AttributeNotImplemented
|
121
|
+
nil
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/mihari/http.rb
CHANGED
@@ -44,8 +44,8 @@ module Mihari
|
|
44
44
|
end
|
45
45
|
|
46
46
|
class << self
|
47
|
-
def get(uri, headers: {},
|
48
|
-
client = new(uri, headers: headers, payload:
|
47
|
+
def get(uri, headers: {}, params: {})
|
48
|
+
client = new(uri, headers: headers, payload: params)
|
49
49
|
client.get
|
50
50
|
end
|
51
51
|
|
@@ -135,6 +135,36 @@ module Mihari
|
|
135
135
|
enrich_cpes
|
136
136
|
end
|
137
137
|
|
138
|
+
ENRICH_METHODS_BY_ENRICHER = {
|
139
|
+
whois: [
|
140
|
+
:enrich_whois
|
141
|
+
],
|
142
|
+
ipinfo: [
|
143
|
+
:enrich_autonomous_system,
|
144
|
+
:enrich_geolocation
|
145
|
+
],
|
146
|
+
shodan: [
|
147
|
+
:enrich_ports,
|
148
|
+
:enrich_cpes,
|
149
|
+
:enrich_reverse_dns
|
150
|
+
],
|
151
|
+
google_public_dns: [
|
152
|
+
:enrich_dns
|
153
|
+
]
|
154
|
+
}.freeze
|
155
|
+
|
156
|
+
#
|
157
|
+
# Enrich by name of enricher
|
158
|
+
#
|
159
|
+
# @param [String] enricher
|
160
|
+
#
|
161
|
+
def enrich_by_enricher(enricher)
|
162
|
+
methods = ENRICH_METHODS_BY_ENRICHER[enricher.downcase.to_sym] || []
|
163
|
+
methods.each do |method|
|
164
|
+
send(method) if respond_to?(method)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
138
168
|
private
|
139
169
|
|
140
170
|
def normalize_as_domain(url_or_domain)
|
data/lib/mihari/models/cpe.rb
CHANGED
data/lib/mihari/models/dns.rb
CHANGED
@@ -13,14 +13,7 @@ module Mihari
|
|
13
13
|
# @return [Array<Mihari::DnsRecord>]
|
14
14
|
#
|
15
15
|
def build_by_domain(domain)
|
16
|
-
resource_types = [
|
17
|
-
Resolv::DNS::Resource::IN::A,
|
18
|
-
Resolv::DNS::Resource::IN::AAAA,
|
19
|
-
Resolv::DNS::Resource::IN::CNAME,
|
20
|
-
Resolv::DNS::Resource::IN::TXT,
|
21
|
-
Resolv::DNS::Resource::IN::NS
|
22
|
-
]
|
23
|
-
|
16
|
+
resource_types = %w[A AAAA CNAME TXT NS]
|
24
17
|
resource_types.map do |resource_type|
|
25
18
|
get_values domain, resource_type
|
26
19
|
rescue Resolv::ResolvError
|
@@ -31,20 +24,11 @@ module Mihari
|
|
31
24
|
private
|
32
25
|
|
33
26
|
def get_values(domain, resource_type)
|
34
|
-
|
35
|
-
|
27
|
+
response = Enrichers::GooglePublicDNS.query(domain, resource_type)
|
28
|
+
answers = response.answers || []
|
36
29
|
|
37
|
-
|
38
|
-
|
39
|
-
if resource.respond_to?(:address)
|
40
|
-
new(resource: resource_name, value: resource.address.to_s)
|
41
|
-
# CNAME, NS
|
42
|
-
elsif resource.respond_to?(:name)
|
43
|
-
new(resource: resource_name, value: resource.name.to_s)
|
44
|
-
# TXT
|
45
|
-
elsif resource.respond_to?(:data)
|
46
|
-
new(resource: resource_name, value: resource.data.to_s)
|
47
|
-
end
|
30
|
+
answers.filter_map do |answer|
|
31
|
+
new(resource: answer.resource_type, value: answer.data)
|
48
32
|
end
|
49
33
|
end
|
50
34
|
end
|
data/lib/mihari/models/whois.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "whois-parser"
|
4
|
-
|
5
3
|
module Mihari
|
6
4
|
class WhoisRecord < ActiveRecord::Base
|
7
5
|
belongs_to :artifact
|
@@ -17,100 +15,7 @@ module Mihari
|
|
17
15
|
# @return [WhoisRecord, nil]
|
18
16
|
#
|
19
17
|
def build_by_domain(domain)
|
20
|
-
|
21
|
-
|
22
|
-
# check memo
|
23
|
-
if @memo.key?(domain)
|
24
|
-
whois_record = @memo[domain]
|
25
|
-
# return clone of the record
|
26
|
-
return whois_record.dup
|
27
|
-
end
|
28
|
-
|
29
|
-
record = Whois.whois(domain)
|
30
|
-
parser = record.parser
|
31
|
-
|
32
|
-
return nil if parser.available?
|
33
|
-
|
34
|
-
whois_record = new(
|
35
|
-
domain: domain,
|
36
|
-
created_on: get_created_on(parser),
|
37
|
-
updated_on: get_updated_on(parser),
|
38
|
-
expires_on: get_expires_on(parser),
|
39
|
-
registrar: get_registrar(parser),
|
40
|
-
contacts: get_contacts(parser)
|
41
|
-
)
|
42
|
-
# set memo
|
43
|
-
@memo[domain] = whois_record
|
44
|
-
whois_record
|
45
|
-
rescue Whois::Error, Whois::ParserError, Timeout::Error
|
46
|
-
nil
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
#
|
52
|
-
# Get created_on
|
53
|
-
#
|
54
|
-
# @param [::Whois::Parser:] parser
|
55
|
-
#
|
56
|
-
# @return [Date, nil]
|
57
|
-
#
|
58
|
-
def get_created_on(parser)
|
59
|
-
parser.created_on
|
60
|
-
rescue ::Whois::AttributeNotImplemented
|
61
|
-
nil
|
62
|
-
end
|
63
|
-
|
64
|
-
#
|
65
|
-
# Get updated_on
|
66
|
-
#
|
67
|
-
# @param [::Whois::Parser:] parser
|
68
|
-
#
|
69
|
-
# @return [Date, nil]
|
70
|
-
#
|
71
|
-
def get_updated_on(parser)
|
72
|
-
parser.updated_on
|
73
|
-
rescue ::Whois::AttributeNotImplemented
|
74
|
-
nil
|
75
|
-
end
|
76
|
-
|
77
|
-
#
|
78
|
-
# Get expires_on
|
79
|
-
#
|
80
|
-
# @param [::Whois::Parser:] parser
|
81
|
-
#
|
82
|
-
# @return [Date, nil]
|
83
|
-
#
|
84
|
-
def get_expires_on(parser)
|
85
|
-
parser.expires_on
|
86
|
-
rescue ::Whois::AttributeNotImplemented
|
87
|
-
nil
|
88
|
-
end
|
89
|
-
|
90
|
-
#
|
91
|
-
# Get registrar
|
92
|
-
#
|
93
|
-
# @param [::Whois::Parser:] parser
|
94
|
-
#
|
95
|
-
# @return [Hash, nil]
|
96
|
-
#
|
97
|
-
def get_registrar(parser)
|
98
|
-
parser.registrar&.to_h
|
99
|
-
rescue ::Whois::AttributeNotImplemented
|
100
|
-
nil
|
101
|
-
end
|
102
|
-
|
103
|
-
#
|
104
|
-
# Get contacts
|
105
|
-
#
|
106
|
-
# @param [::Whois::Parser:] parser
|
107
|
-
#
|
108
|
-
# @return [Array[Hash], nil]
|
109
|
-
#
|
110
|
-
def get_contacts(parser)
|
111
|
-
parser.contacts.map(&:to_h)
|
112
|
-
rescue ::Whois::AttributeNotImplemented
|
113
|
-
nil
|
18
|
+
Enrichers::Whois.query domain
|
114
19
|
end
|
115
20
|
end
|
116
21
|
end
|
@@ -16,6 +16,7 @@ module Mihari
|
|
16
16
|
required(:emitter).value(Types::String.enum("the_hive"))
|
17
17
|
optional(:api_endpoint).value(:string)
|
18
18
|
optional(:api_key).value(:string)
|
19
|
+
optional(:api_version).value(Types::String.enum("v4", "v5")).default("v4")
|
19
20
|
end
|
20
21
|
|
21
22
|
Slack = Dry::Schema.Params do
|
data/lib/mihari/schemas/rule.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "mihari/schemas/analyzer"
|
4
4
|
require "mihari/schemas/emitter"
|
5
|
+
require "mihari/schemas/enricher"
|
5
6
|
|
6
7
|
module Mihari
|
7
8
|
module Schemas
|
@@ -20,6 +21,8 @@ module Mihari
|
|
20
21
|
|
21
22
|
optional(:emitters).value(:array).each { Emitter | MISP | TheHive | Slack | HTTP }
|
22
23
|
|
24
|
+
optional(:enrichers).value(:array).each(Enricher)
|
25
|
+
|
23
26
|
optional(:allowed_data_types).value(array[Types::DataTypes]).default(ALLOWED_DATA_TYPES)
|
24
27
|
optional(:disallowed_data_values).value(array[:string]).default([])
|
25
28
|
|
@@ -35,6 +38,9 @@ module Mihari
|
|
35
38
|
emitters = h[:emitters]
|
36
39
|
h[:emitters] = emitters || DEFAULT_EMITTERS
|
37
40
|
|
41
|
+
enrichers = h[:enrichers]
|
42
|
+
h[:enrichers] = enrichers || DEFAULT_ENRICHERS
|
43
|
+
|
38
44
|
h
|
39
45
|
end
|
40
46
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Structs
|
5
|
+
module GooglePublicDNS
|
6
|
+
INT_TYPE_TO_TYPE = {
|
7
|
+
1 => "A",
|
8
|
+
2 => "NS",
|
9
|
+
5 => "CNAME",
|
10
|
+
16 => "TXT",
|
11
|
+
28 => "AAAA"
|
12
|
+
}
|
13
|
+
|
14
|
+
class Answer < Dry::Struct
|
15
|
+
attribute :name, Types::String
|
16
|
+
attribute :data, Types::String
|
17
|
+
attribute :resource_type, Types::String
|
18
|
+
|
19
|
+
def self.from_dynamic!(d)
|
20
|
+
d = Types::Hash[d]
|
21
|
+
resource_type = INT_TYPE_TO_TYPE[d.fetch("type")]
|
22
|
+
new(
|
23
|
+
name: d.fetch("name"),
|
24
|
+
data: d.fetch("data"),
|
25
|
+
resource_type: resource_type
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Response < Dry::Struct
|
31
|
+
attribute :answers, Types.Array(Answer)
|
32
|
+
|
33
|
+
def self.from_dynamic!(d)
|
34
|
+
d = Types::Hash[d]
|
35
|
+
new(
|
36
|
+
answers: d.fetch("Answer", []).map { |x| Answer.from_dynamic!(x) }
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/mihari/structs/rule.rb
CHANGED
@@ -88,7 +88,7 @@ module Mihari
|
|
88
88
|
|
89
89
|
raise RuleValidationError, error_messages.join("\n") if errors?
|
90
90
|
|
91
|
-
raise RuleValidationError, "Something wrong with queries or
|
91
|
+
raise RuleValidationError, "Something wrong with queries, emitters or enrichers." unless @no_method_error.nil?
|
92
92
|
end
|
93
93
|
|
94
94
|
def [](key)
|
@@ -150,6 +150,7 @@ module Mihari
|
|
150
150
|
allowed_data_types: self[:allowed_data_types],
|
151
151
|
disallowed_data_values: self[:disallowed_data_values],
|
152
152
|
emitters: self[:emitters],
|
153
|
+
enrichers: self[:enrichers],
|
153
154
|
id: id
|
154
155
|
)
|
155
156
|
analyzer.ignore_old_artifacts = self[:ignore_old_artifacts]
|
@@ -4,7 +4,7 @@ module Mihari
|
|
4
4
|
module Structs
|
5
5
|
module VirusTotalIntelligence
|
6
6
|
class ContextAttributes < Dry::Struct
|
7
|
-
attribute :url, Types
|
7
|
+
attribute :url, Types::String.optional
|
8
8
|
|
9
9
|
def self.from_dynamic!(d)
|
10
10
|
d = Types::Hash[d]
|
@@ -25,7 +25,7 @@ module Mihari
|
|
25
25
|
when "file"
|
26
26
|
id
|
27
27
|
when "url"
|
28
|
-
|
28
|
+
context_attributes&.url
|
29
29
|
when "domain"
|
30
30
|
id
|
31
31
|
when "ip_address"
|
data/lib/mihari/types.rb
CHANGED
data/lib/mihari/version.rb
CHANGED
data/lib/mihari/web/app.rb
CHANGED
@@ -53,6 +53,9 @@ module Mihari
|
|
53
53
|
|
54
54
|
Rack::Handler::Puma.run(instance, Port: port, Host: host, Threads: threads, Verbose: verbose) do |_launcher|
|
55
55
|
Launchy.open(url) if ENV["RACK_ENV"] != "development"
|
56
|
+
rescue Launchy::CommandNotFoundError
|
57
|
+
# ref. https://github.com/ninoseki/mihari/issues/477
|
58
|
+
# do nothing
|
56
59
|
end
|
57
60
|
end
|
58
61
|
end
|
data/lib/mihari.rb
CHANGED
@@ -71,34 +71,55 @@ end
|
|
71
71
|
module Mihari
|
72
72
|
extend Dry::Configurable
|
73
73
|
|
74
|
-
setting :binaryedge_api_key, default: ENV
|
75
|
-
|
76
|
-
setting :
|
77
|
-
setting :
|
78
|
-
|
79
|
-
setting :
|
80
|
-
setting :
|
81
|
-
|
82
|
-
setting :
|
83
|
-
|
84
|
-
setting :
|
85
|
-
|
86
|
-
setting :
|
87
|
-
|
88
|
-
setting :
|
89
|
-
setting :
|
90
|
-
|
91
|
-
setting :
|
92
|
-
|
93
|
-
setting :
|
94
|
-
|
95
|
-
setting :
|
96
|
-
setting :
|
97
|
-
|
98
|
-
setting :
|
99
|
-
|
100
|
-
setting :
|
101
|
-
|
74
|
+
setting :binaryedge_api_key, default: ENV.fetch("BINARYEDGE_API_KEY", nil)
|
75
|
+
|
76
|
+
setting :censys_id, default: ENV.fetch("CENSYS_ID", nil)
|
77
|
+
setting :censys_secret, default: ENV.fetch("CENSYS_SECRET", nil)
|
78
|
+
|
79
|
+
setting :circl_passive_password, default: ENV.fetch("CIRCL_PASSIVE_PASSWORD", nil)
|
80
|
+
setting :circl_passive_username, default: ENV.fetch("CIRCL_PASSIVE_USERNAME", nil)
|
81
|
+
|
82
|
+
setting :database, default: ENV.fetch("DATABASE", "mihari.db")
|
83
|
+
|
84
|
+
setting :greynoise_api_key, default: ENV.fetch("GREYNOISE_API_KEY", nil)
|
85
|
+
|
86
|
+
setting :ipinfo_api_key, default: ENV.fetch("IPINFO_API_KEY", nil)
|
87
|
+
|
88
|
+
setting :misp_api_endpoint, default: ENV.fetch("MISP_API_ENDPOINT", nil)
|
89
|
+
setting :misp_api_key, default: ENV.fetch("MISP_API_KEY", nil)
|
90
|
+
|
91
|
+
setting :onyphe_api_key, default: ENV.fetch("ONYPHE_API_KEY", nil)
|
92
|
+
|
93
|
+
setting :otx_api_key, default: ENV.fetch("OTX_API_KEY", nil)
|
94
|
+
|
95
|
+
setting :passivetotal_api_key, default: ENV.fetch("PASSIVETOTAL_API_KEY", nil)
|
96
|
+
setting :passivetotal_username, default: ENV.fetch("PASSIVETOTAL_USERNAME", nil)
|
97
|
+
|
98
|
+
setting :pulsedive_api_key, default: ENV.fetch("PULSEDIVE_API_KEY", nil)
|
99
|
+
|
100
|
+
setting :securitytrails_api_key, default: ENV.fetch("SECURITYTRAILS_API_KEY", nil)
|
101
|
+
|
102
|
+
setting :shodan_api_key, default: ENV.fetch("SHODAN_API_KEY", nil)
|
103
|
+
|
104
|
+
setting :slack_channel, default: ENV.fetch("SLACK_CHANNEL", nil)
|
105
|
+
setting :slack_webhook_url, default: ENV.fetch("SLACK_WEBHOOK_URL", nil)
|
106
|
+
|
107
|
+
setting :spyse_api_key, default: ENV.fetch("SPYSE_API_KEY", nil)
|
108
|
+
|
109
|
+
setting :thehive_api_endpoint, default: ENV.fetch("THEHIVE_API_ENDPOINT", nil)
|
110
|
+
setting :thehive_api_key, default: ENV.fetch("THEHIVE_API_KEY", nil)
|
111
|
+
setting :thehive_api_version, default: ENV.fetch("THEHIVE_API_VERSION", nil)
|
112
|
+
|
113
|
+
setting :urlscan_api_key, default: ENV.fetch("URLSCAN_API_KEY", nil)
|
114
|
+
|
115
|
+
setting :virustotal_api_key, default: ENV.fetch("VIRUSTOTAL_API_KEY", nil)
|
116
|
+
|
117
|
+
setting :webhook_url, default: ENV.fetch("WEBHOOK_URL", nil)
|
118
|
+
setting :webhook_use_json_body, constructor: ->(value = ENV.fetch("WEBHOOK_USE_JSON_BODY", nil)) { truthy?(value) }
|
119
|
+
|
120
|
+
setting :zoomeye_api_key, default: ENV.fetch("ZOOMEYE_API_KEY", nil)
|
121
|
+
|
122
|
+
setting :sentry_dsn, default: ENV.fetch("SENTRY_DSN", nil)
|
102
123
|
|
103
124
|
class << self
|
104
125
|
include Memist::Memoizable
|
@@ -152,6 +173,7 @@ require "mihari/types"
|
|
152
173
|
# Structs
|
153
174
|
require "mihari/structs/alert"
|
154
175
|
require "mihari/structs/censys"
|
176
|
+
require "mihari/structs/google_public_dns"
|
155
177
|
require "mihari/structs/greynoise"
|
156
178
|
require "mihari/structs/ipinfo"
|
157
179
|
require "mihari/structs/onyphe"
|
@@ -168,8 +190,10 @@ require "mihari/schemas/rule"
|
|
168
190
|
|
169
191
|
# Enrichers
|
170
192
|
require "mihari/enrichers/base"
|
193
|
+
require "mihari/enrichers/google_public_dns"
|
171
194
|
require "mihari/enrichers/ipinfo"
|
172
195
|
require "mihari/enrichers/shodan"
|
196
|
+
require "mihari/enrichers/whois"
|
173
197
|
|
174
198
|
# Models
|
175
199
|
require "mihari/models/alert"
|
data/mihari.gemspec
CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
|
|
29
29
|
|
30
30
|
spec.add_development_dependency "bundler", "~> 2.3"
|
31
31
|
spec.add_development_dependency "coveralls_reborn", "~> 0.24"
|
32
|
-
spec.add_development_dependency "fakefs", "~> 1.
|
32
|
+
spec.add_development_dependency "fakefs", "~> 1.5"
|
33
33
|
spec.add_development_dependency "mysql2", "~> 0.5"
|
34
34
|
spec.add_development_dependency "overcommit", "~> 0.59"
|
35
35
|
spec.add_development_dependency "pg", "~> 1.3"
|
@@ -39,13 +39,13 @@ Gem::Specification.new do |spec|
|
|
39
39
|
spec.add_development_dependency "rerun", "~> 0.13"
|
40
40
|
spec.add_development_dependency "rspec", "~> 3.11"
|
41
41
|
spec.add_development_dependency "simplecov-lcov", "~> 0.8.0"
|
42
|
-
spec.add_development_dependency "standard", "~> 1.
|
43
|
-
spec.add_development_dependency "steep", "~> 0
|
42
|
+
spec.add_development_dependency "standard", "~> 1.12"
|
43
|
+
spec.add_development_dependency "steep", "~> 1.0"
|
44
44
|
spec.add_development_dependency "timecop", "~> 0.9"
|
45
45
|
spec.add_development_dependency "vcr", "~> 6.1"
|
46
46
|
spec.add_development_dependency "webmock", "~> 3.14"
|
47
47
|
|
48
|
-
spec.add_dependency "activerecord", "7.0.
|
48
|
+
spec.add_dependency "activerecord", "7.0.3"
|
49
49
|
spec.add_dependency "addressable", "2.8.0"
|
50
50
|
spec.add_dependency "awrence", "2.0.1"
|
51
51
|
spec.add_dependency "binaryedge", "0.1.0"
|
@@ -58,16 +58,16 @@ Gem::Specification.new do |spec|
|
|
58
58
|
spec.add_dependency "dry-container", "0.9.0"
|
59
59
|
spec.add_dependency "dry-files", "0.1.0"
|
60
60
|
spec.add_dependency "dry-initializer", "3.1.1"
|
61
|
-
spec.add_dependency "dry-schema", "1.9.
|
61
|
+
spec.add_dependency "dry-schema", "1.9.2"
|
62
62
|
spec.add_dependency "dry-struct", "1.4.0"
|
63
|
-
spec.add_dependency "dry-validation", "1.8.
|
64
|
-
spec.add_dependency "email_address", "0.2.
|
63
|
+
spec.add_dependency "dry-validation", "1.8.1"
|
64
|
+
spec.add_dependency "email_address", "0.2.3"
|
65
65
|
spec.add_dependency "grape", "1.6.2"
|
66
66
|
spec.add_dependency "grape-entity", "0.10.1"
|
67
67
|
spec.add_dependency "grape-swagger", "1.4.2"
|
68
68
|
spec.add_dependency "grape-swagger-entity", "0.5.1"
|
69
69
|
spec.add_dependency "greynoise", "0.1.1"
|
70
|
-
spec.add_dependency "hachi", "
|
70
|
+
spec.add_dependency "hachi", "2.0.0"
|
71
71
|
spec.add_dependency "insensitive_hash", "0.3.3"
|
72
72
|
spec.add_dependency "jr-cli", "0.5.1"
|
73
73
|
spec.add_dependency "launchy", "2.5.0"
|
@@ -84,12 +84,12 @@ Gem::Specification.new do |spec|
|
|
84
84
|
spec.add_dependency "public_suffix", "4.0.7"
|
85
85
|
spec.add_dependency "pulsedive", "0.1.5"
|
86
86
|
spec.add_dependency "puma", "5.6.4"
|
87
|
-
spec.add_dependency "rack", "2.2.3"
|
87
|
+
spec.add_dependency "rack", "2.2.3.1"
|
88
88
|
spec.add_dependency "rack-contrib", "2.3.0"
|
89
89
|
spec.add_dependency "rack-cors", "1.1.1"
|
90
90
|
spec.add_dependency "securitytrails", "1.0.0"
|
91
|
-
spec.add_dependency "semantic_logger", "4.
|
92
|
-
spec.add_dependency "sentry-ruby", "5.3.
|
91
|
+
spec.add_dependency "semantic_logger", "4.11.0"
|
92
|
+
spec.add_dependency "sentry-ruby", "5.3.1"
|
93
93
|
spec.add_dependency "shodanx", "0.2.1"
|
94
94
|
spec.add_dependency "slack-notifier", "2.4.0"
|
95
95
|
spec.add_dependency "spysex", "0.2.0"
|
@@ -5,11 +5,15 @@ module Mihari
|
|
5
5
|
|
6
6
|
attr_reader api_key: String?
|
7
7
|
|
8
|
+
attr_reader api_version: String?
|
9
|
+
|
8
10
|
# @return [true, false]
|
9
11
|
def valid?: () -> bool
|
10
12
|
|
11
13
|
def emit: (title: untyped title, description: untyped description, artifacts: untyped artifacts, ?tags: untyped tags, **untyped _options) -> (nil | untyped)
|
12
14
|
|
15
|
+
def normalized_api_version: () -> String?
|
16
|
+
|
13
17
|
private
|
14
18
|
|
15
19
|
def configuration_keys: () -> ::Array["thehive_api_endpoint" | "thehive_api_key"]
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Mihari
|
2
|
+
module Enrichers
|
3
|
+
class GooglePublicDNS < Base
|
4
|
+
# @return [Boolean]
|
5
|
+
def valid?: () -> true
|
6
|
+
|
7
|
+
#
|
8
|
+
# Query Google Public DNS
|
9
|
+
#
|
10
|
+
# @param [String] name
|
11
|
+
# @param [String] resource_type
|
12
|
+
#
|
13
|
+
# @return [Mihari::Structs::Shodan::GooglePublicDNS::Response, nil]
|
14
|
+
#
|
15
|
+
def self.query: (String name, String resource_type) -> Mihari::Structs::Shodan::GooglePublicDNS::Response?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Mihari
|
2
|
+
module Structs
|
3
|
+
module GooglePublicDNS
|
4
|
+
INT_TYPE_TO_TYPE: { 1 => "A", 2 => "NS", 5 => "CNAME", 16 => "TXT", 28 => "AAAA" }
|
5
|
+
|
6
|
+
class Answer < Dry::Struct
|
7
|
+
attr_reader name: String
|
8
|
+
attr_reader data: String
|
9
|
+
attr_reader resource_type: String
|
10
|
+
|
11
|
+
def self.from_dynamic!: (Hash[(String | Symbol), untyped] d) -> Mihari::Structs::GooglePublicDNS::Answer
|
12
|
+
end
|
13
|
+
|
14
|
+
class Response < Dry::Struct
|
15
|
+
attr_reader answers: Array[Mihari::Structs::GooglePublicDNS::Answer]
|
16
|
+
|
17
|
+
def self.from_dynamic!: (Hash[(String | Symbol), untyped] d) -> Mihari::Structs::GooglePublicDNS::Response
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/sig/lib/mihari.rbs
CHANGED
@@ -19,6 +19,7 @@ class Configuration
|
|
19
19
|
attr_accessor spyse_api_key (): String?
|
20
20
|
attr_accessor thehive_api_endpoint (): String?
|
21
21
|
attr_accessor thehive_api_key (): String?
|
22
|
+
attr_accessor thehive_api_version (): String?
|
22
23
|
attr_accessor urlscan_api_key (): String?
|
23
24
|
attr_accessor virustotal_api_key (): String?
|
24
25
|
attr_accessor zoomeye_api_key (): String?
|
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: 4.
|
4
|
+
version: 4.7.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: 2022-05
|
11
|
+
date: 2022-06-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '1.
|
47
|
+
version: '1.5'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '1.
|
54
|
+
version: '1.5'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: mysql2
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -184,28 +184,28 @@ dependencies:
|
|
184
184
|
requirements:
|
185
185
|
- - "~>"
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
version: '1.
|
187
|
+
version: '1.12'
|
188
188
|
type: :development
|
189
189
|
prerelease: false
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
191
191
|
requirements:
|
192
192
|
- - "~>"
|
193
193
|
- !ruby/object:Gem::Version
|
194
|
-
version: '1.
|
194
|
+
version: '1.12'
|
195
195
|
- !ruby/object:Gem::Dependency
|
196
196
|
name: steep
|
197
197
|
requirement: !ruby/object:Gem::Requirement
|
198
198
|
requirements:
|
199
199
|
- - "~>"
|
200
200
|
- !ruby/object:Gem::Version
|
201
|
-
version: '0
|
201
|
+
version: '1.0'
|
202
202
|
type: :development
|
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: '0
|
208
|
+
version: '1.0'
|
209
209
|
- !ruby/object:Gem::Dependency
|
210
210
|
name: timecop
|
211
211
|
requirement: !ruby/object:Gem::Requirement
|
@@ -254,14 +254,14 @@ dependencies:
|
|
254
254
|
requirements:
|
255
255
|
- - '='
|
256
256
|
- !ruby/object:Gem::Version
|
257
|
-
version: 7.0.
|
257
|
+
version: 7.0.3
|
258
258
|
type: :runtime
|
259
259
|
prerelease: false
|
260
260
|
version_requirements: !ruby/object:Gem::Requirement
|
261
261
|
requirements:
|
262
262
|
- - '='
|
263
263
|
- !ruby/object:Gem::Version
|
264
|
-
version: 7.0.
|
264
|
+
version: 7.0.3
|
265
265
|
- !ruby/object:Gem::Dependency
|
266
266
|
name: addressable
|
267
267
|
requirement: !ruby/object:Gem::Requirement
|
@@ -436,14 +436,14 @@ dependencies:
|
|
436
436
|
requirements:
|
437
437
|
- - '='
|
438
438
|
- !ruby/object:Gem::Version
|
439
|
-
version: 1.9.
|
439
|
+
version: 1.9.2
|
440
440
|
type: :runtime
|
441
441
|
prerelease: false
|
442
442
|
version_requirements: !ruby/object:Gem::Requirement
|
443
443
|
requirements:
|
444
444
|
- - '='
|
445
445
|
- !ruby/object:Gem::Version
|
446
|
-
version: 1.9.
|
446
|
+
version: 1.9.2
|
447
447
|
- !ruby/object:Gem::Dependency
|
448
448
|
name: dry-struct
|
449
449
|
requirement: !ruby/object:Gem::Requirement
|
@@ -464,28 +464,28 @@ dependencies:
|
|
464
464
|
requirements:
|
465
465
|
- - '='
|
466
466
|
- !ruby/object:Gem::Version
|
467
|
-
version: 1.8.
|
467
|
+
version: 1.8.1
|
468
468
|
type: :runtime
|
469
469
|
prerelease: false
|
470
470
|
version_requirements: !ruby/object:Gem::Requirement
|
471
471
|
requirements:
|
472
472
|
- - '='
|
473
473
|
- !ruby/object:Gem::Version
|
474
|
-
version: 1.8.
|
474
|
+
version: 1.8.1
|
475
475
|
- !ruby/object:Gem::Dependency
|
476
476
|
name: email_address
|
477
477
|
requirement: !ruby/object:Gem::Requirement
|
478
478
|
requirements:
|
479
479
|
- - '='
|
480
480
|
- !ruby/object:Gem::Version
|
481
|
-
version: 0.2.
|
481
|
+
version: 0.2.3
|
482
482
|
type: :runtime
|
483
483
|
prerelease: false
|
484
484
|
version_requirements: !ruby/object:Gem::Requirement
|
485
485
|
requirements:
|
486
486
|
- - '='
|
487
487
|
- !ruby/object:Gem::Version
|
488
|
-
version: 0.2.
|
488
|
+
version: 0.2.3
|
489
489
|
- !ruby/object:Gem::Dependency
|
490
490
|
name: grape
|
491
491
|
requirement: !ruby/object:Gem::Requirement
|
@@ -562,14 +562,14 @@ dependencies:
|
|
562
562
|
requirements:
|
563
563
|
- - '='
|
564
564
|
- !ruby/object:Gem::Version
|
565
|
-
version:
|
565
|
+
version: 2.0.0
|
566
566
|
type: :runtime
|
567
567
|
prerelease: false
|
568
568
|
version_requirements: !ruby/object:Gem::Requirement
|
569
569
|
requirements:
|
570
570
|
- - '='
|
571
571
|
- !ruby/object:Gem::Version
|
572
|
-
version:
|
572
|
+
version: 2.0.0
|
573
573
|
- !ruby/object:Gem::Dependency
|
574
574
|
name: insensitive_hash
|
575
575
|
requirement: !ruby/object:Gem::Requirement
|
@@ -800,14 +800,14 @@ dependencies:
|
|
800
800
|
requirements:
|
801
801
|
- - '='
|
802
802
|
- !ruby/object:Gem::Version
|
803
|
-
version: 2.2.3
|
803
|
+
version: 2.2.3.1
|
804
804
|
type: :runtime
|
805
805
|
prerelease: false
|
806
806
|
version_requirements: !ruby/object:Gem::Requirement
|
807
807
|
requirements:
|
808
808
|
- - '='
|
809
809
|
- !ruby/object:Gem::Version
|
810
|
-
version: 2.2.3
|
810
|
+
version: 2.2.3.1
|
811
811
|
- !ruby/object:Gem::Dependency
|
812
812
|
name: rack-contrib
|
813
813
|
requirement: !ruby/object:Gem::Requirement
|
@@ -856,28 +856,28 @@ dependencies:
|
|
856
856
|
requirements:
|
857
857
|
- - '='
|
858
858
|
- !ruby/object:Gem::Version
|
859
|
-
version: 4.
|
859
|
+
version: 4.11.0
|
860
860
|
type: :runtime
|
861
861
|
prerelease: false
|
862
862
|
version_requirements: !ruby/object:Gem::Requirement
|
863
863
|
requirements:
|
864
864
|
- - '='
|
865
865
|
- !ruby/object:Gem::Version
|
866
|
-
version: 4.
|
866
|
+
version: 4.11.0
|
867
867
|
- !ruby/object:Gem::Dependency
|
868
868
|
name: sentry-ruby
|
869
869
|
requirement: !ruby/object:Gem::Requirement
|
870
870
|
requirements:
|
871
871
|
- - '='
|
872
872
|
- !ruby/object:Gem::Version
|
873
|
-
version: 5.3.
|
873
|
+
version: 5.3.1
|
874
874
|
type: :runtime
|
875
875
|
prerelease: false
|
876
876
|
version_requirements: !ruby/object:Gem::Requirement
|
877
877
|
requirements:
|
878
878
|
- - '='
|
879
879
|
- !ruby/object:Gem::Version
|
880
|
-
version: 5.3.
|
880
|
+
version: 5.3.1
|
881
881
|
- !ruby/object:Gem::Dependency
|
882
882
|
name: shodanx
|
883
883
|
requirement: !ruby/object:Gem::Requirement
|
@@ -1110,8 +1110,10 @@ files:
|
|
1110
1110
|
- lib/mihari/emitters/the_hive.rb
|
1111
1111
|
- lib/mihari/emitters/webhook.rb
|
1112
1112
|
- lib/mihari/enrichers/base.rb
|
1113
|
+
- lib/mihari/enrichers/google_public_dns.rb
|
1113
1114
|
- lib/mihari/enrichers/ipinfo.rb
|
1114
1115
|
- lib/mihari/enrichers/shodan.rb
|
1116
|
+
- lib/mihari/enrichers/whois.rb
|
1115
1117
|
- lib/mihari/entities/alert.rb
|
1116
1118
|
- lib/mihari/entities/artifact.rb
|
1117
1119
|
- lib/mihari/entities/autonomous_system.rb
|
@@ -1153,11 +1155,13 @@ files:
|
|
1153
1155
|
- lib/mihari/models/whois.rb
|
1154
1156
|
- lib/mihari/schemas/analyzer.rb
|
1155
1157
|
- lib/mihari/schemas/emitter.rb
|
1158
|
+
- lib/mihari/schemas/enricher.rb
|
1156
1159
|
- lib/mihari/schemas/macros.rb
|
1157
1160
|
- lib/mihari/schemas/rule.rb
|
1158
1161
|
- lib/mihari/status.rb
|
1159
1162
|
- lib/mihari/structs/alert.rb
|
1160
1163
|
- lib/mihari/structs/censys.rb
|
1164
|
+
- lib/mihari/structs/google_public_dns.rb
|
1161
1165
|
- lib/mihari/structs/greynoise.rb
|
1162
1166
|
- lib/mihari/structs/ipinfo.rb
|
1163
1167
|
- lib/mihari/structs/onyphe.rb
|
@@ -1243,6 +1247,7 @@ files:
|
|
1243
1247
|
- sig/lib/mihari/emitters/the_hive.rbs
|
1244
1248
|
- sig/lib/mihari/emitters/webhook.rbs
|
1245
1249
|
- sig/lib/mihari/enrichers/base.rbs
|
1250
|
+
- sig/lib/mihari/enrichers/google_public_dns.rbs
|
1246
1251
|
- sig/lib/mihari/enrichers/ipinfo.rbs
|
1247
1252
|
- sig/lib/mihari/errors.rbs
|
1248
1253
|
- sig/lib/mihari/feed/parser.rbs
|
@@ -1272,6 +1277,7 @@ files:
|
|
1272
1277
|
- sig/lib/mihari/status.rbs
|
1273
1278
|
- sig/lib/mihari/structs/alert.rbs
|
1274
1279
|
- sig/lib/mihari/structs/censys.rbs
|
1280
|
+
- sig/lib/mihari/structs/google_public_dns.rbs
|
1275
1281
|
- sig/lib/mihari/structs/greynoise.rbs
|
1276
1282
|
- sig/lib/mihari/structs/ipinfo.rbs
|
1277
1283
|
- sig/lib/mihari/structs/onyphe.rbs
|