mihari 5.4.9 → 5.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/docs/analyzers/binaryedge.md +2 -2
- data/docs/analyzers/censys.md +3 -3
- data/docs/analyzers/circl.md +3 -3
- data/docs/analyzers/crtsh.md +2 -2
- data/docs/analyzers/dnstwister.md +1 -1
- data/docs/analyzers/feed.md +7 -7
- data/docs/analyzers/greynoise.md +2 -2
- data/docs/analyzers/hunterhow.md +4 -4
- data/docs/analyzers/index.md +13 -8
- data/docs/analyzers/onyphe.md +2 -2
- data/docs/analyzers/otx.md +2 -2
- data/docs/analyzers/passivetotal.md +3 -3
- data/docs/analyzers/pulsedive.md +2 -2
- data/docs/analyzers/securitytrails.md +2 -2
- data/docs/analyzers/shodan.md +2 -2
- data/docs/analyzers/urlscan.md +2 -2
- data/docs/analyzers/virustotal.md +2 -2
- data/docs/analyzers/virustotal_intelligence.md +2 -2
- data/docs/analyzers/zoomeye.md +3 -3
- data/docs/emitters/hive.md +3 -3
- data/docs/emitters/index.md +29 -0
- data/docs/emitters/misp.md +2 -2
- data/docs/emitters/slack.md +2 -2
- data/docs/emitters/webhook.md +4 -4
- data/docs/enrichers/index.md +29 -0
- data/docs/enrichers/ipinfo.md +7 -0
- data/docs/index.md +0 -2
- data/docs/installation.md +1 -1
- data/docs/rule.md +11 -11
- data/frontend/package-lock.json +294 -2772
- data/frontend/package.json +10 -10
- data/lib/mihari/analyzers/base.rb +15 -8
- data/lib/mihari/analyzers/binaryedge.rb +5 -1
- data/lib/mihari/analyzers/censys.rb +6 -1
- data/lib/mihari/analyzers/greynoise.rb +5 -1
- data/lib/mihari/analyzers/hunterhow.rb +5 -1
- data/lib/mihari/analyzers/onyphe.rb +5 -1
- data/lib/mihari/analyzers/rule.rb +43 -7
- data/lib/mihari/analyzers/shodan.rb +5 -1
- data/lib/mihari/analyzers/urlscan.rb +5 -1
- data/lib/mihari/analyzers/virustotal_intelligence.rb +5 -1
- data/lib/mihari/analyzers/zoomeye.rb +5 -1
- data/lib/mihari/clients/base.rb +7 -7
- data/lib/mihari/clients/binaryedge.rb +10 -4
- data/lib/mihari/clients/censys.rb +11 -4
- data/lib/mihari/clients/greynoise.rb +10 -4
- data/lib/mihari/clients/hunterhow.rb +10 -4
- data/lib/mihari/clients/misp.rb +3 -2
- data/lib/mihari/clients/onyphe.rb +10 -4
- data/lib/mihari/clients/shodan.rb +10 -4
- data/lib/mihari/clients/the_hive.rb +3 -2
- data/lib/mihari/clients/urlscan.rb +9 -3
- data/lib/mihari/clients/virustotal.rb +10 -4
- data/lib/mihari/clients/zoomeye.rb +11 -5
- data/lib/mihari/config.rb +8 -0
- data/lib/mihari/emitters/base.rb +49 -12
- data/lib/mihari/emitters/misp.rb +7 -6
- data/lib/mihari/emitters/slack.rb +24 -6
- data/lib/mihari/emitters/the_hive.rb +8 -7
- data/lib/mihari/emitters/webhook.rb +31 -29
- data/lib/mihari/enrichers/base.rb +53 -16
- data/lib/mihari/enrichers/google_public_dns.rb +33 -42
- data/lib/mihari/enrichers/ipinfo.rb +32 -34
- data/lib/mihari/enrichers/shodan.rb +18 -26
- data/lib/mihari/enrichers/whois.rb +121 -111
- data/lib/mihari/mixins/retriable.rb +4 -2
- data/lib/mihari/models/artifact.rb +37 -23
- data/lib/mihari/models/autonomous_system.rb +3 -2
- data/lib/mihari/models/cpe.rb +3 -2
- data/lib/mihari/models/dns.rb +3 -2
- data/lib/mihari/models/geolocation.rb +3 -2
- data/lib/mihari/models/port.rb +3 -2
- data/lib/mihari/models/reverse_dns.rb +3 -2
- data/lib/mihari/models/whois.rb +4 -3
- data/lib/mihari/schemas/analyzer.rb +2 -1
- data/lib/mihari/schemas/emitter.rb +39 -25
- data/lib/mihari/schemas/enricher.rb +28 -2
- data/lib/mihari/schemas/rule.rb +6 -2
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/endpoints/ip_addresses.rb +1 -1
- data/lib/mihari/web/public/assets/index-b5d817a3.js +1749 -0
- data/lib/mihari/web/public/index.html +1 -1
- data/lib/mihari/web/public/redoc-static.html +400 -400
- data/mihari.gemspec +2 -2
- data/mkdocs.yml +8 -6
- data/requirements.txt +1 -1
- metadata +7 -7
- data/lib/mihari/web/public/assets/index-a92abd57.js +0 -1740
@@ -5,122 +5,132 @@ require "whois-parser"
|
|
5
5
|
module Mihari
|
6
6
|
module Enrichers
|
7
7
|
class Whois < Base
|
8
|
-
# @
|
9
|
-
|
8
|
+
# @return [Hash]
|
9
|
+
attr_accessor :memo
|
10
10
|
|
11
|
-
#
|
12
|
-
|
13
|
-
|
11
|
+
#
|
12
|
+
# @param [Hash, nil] options
|
13
|
+
#
|
14
|
+
def initialize(options: nil)
|
15
|
+
super(options: options)
|
16
|
+
|
17
|
+
@memo = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# Query IAIA Whois API
|
22
|
+
#
|
23
|
+
# @param [String] name
|
24
|
+
#
|
25
|
+
# @return [Mihari::WhoisRecord, nil]
|
26
|
+
#
|
27
|
+
def query(domain)
|
28
|
+
domain = PublicSuffix.domain(domain)
|
29
|
+
|
30
|
+
# check memo
|
31
|
+
return memo[domain].dup if memo.key?(domain)
|
32
|
+
|
33
|
+
record = whois.lookup(domain)
|
34
|
+
parser = record.parser
|
35
|
+
return nil if parser.available?
|
36
|
+
|
37
|
+
whois_record = WhoisRecord.new(
|
38
|
+
domain: domain,
|
39
|
+
created_on: get_created_on(parser),
|
40
|
+
updated_on: get_updated_on(parser),
|
41
|
+
expires_on: get_expires_on(parser),
|
42
|
+
registrar: get_registrar(parser),
|
43
|
+
contacts: get_contacts(parser)
|
44
|
+
)
|
45
|
+
|
46
|
+
# set memo
|
47
|
+
memo[domain] = whois_record
|
48
|
+
|
49
|
+
whois_record
|
14
50
|
end
|
15
51
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
whois_record = @memo[domain]
|
32
|
-
# return clone of the record
|
33
|
-
return whois_record.dup
|
52
|
+
def reset_cache
|
53
|
+
@memo = {}
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
#
|
59
|
+
# @return [::Whois::Client]
|
60
|
+
#
|
61
|
+
def whois
|
62
|
+
@whois ||= [].tap do |out|
|
63
|
+
out << if timeout.nil?
|
64
|
+
::Whois::Client.new
|
65
|
+
else
|
66
|
+
::Whois::Client.new(timeout: timeout)
|
34
67
|
end
|
68
|
+
end.last
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Get created_on
|
73
|
+
#
|
74
|
+
# @param [::Whois::Parser:] parser
|
75
|
+
#
|
76
|
+
# @return [Date, nil]
|
77
|
+
#
|
78
|
+
def get_created_on(parser)
|
79
|
+
parser.created_on
|
80
|
+
rescue ::Whois::AttributeNotImplemented
|
81
|
+
nil
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# Get updated_on
|
86
|
+
#
|
87
|
+
# @param [::Whois::Parser:] parser
|
88
|
+
#
|
89
|
+
# @return [Date, nil]
|
90
|
+
#
|
91
|
+
def get_updated_on(parser)
|
92
|
+
parser.updated_on
|
93
|
+
rescue ::Whois::AttributeNotImplemented
|
94
|
+
nil
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# Get expires_on
|
99
|
+
#
|
100
|
+
# @param [::Whois::Parser:] parser
|
101
|
+
#
|
102
|
+
# @return [Date, nil]
|
103
|
+
#
|
104
|
+
def get_expires_on(parser)
|
105
|
+
parser.expires_on
|
106
|
+
rescue ::Whois::AttributeNotImplemented
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
|
110
|
+
#
|
111
|
+
# Get registrar
|
112
|
+
#
|
113
|
+
# @param [::Whois::Parser:] parser
|
114
|
+
#
|
115
|
+
# @return [Hash, nil]
|
116
|
+
#
|
117
|
+
def get_registrar(parser)
|
118
|
+
parser.registrar&.to_h
|
119
|
+
rescue ::Whois::AttributeNotImplemented
|
120
|
+
nil
|
121
|
+
end
|
35
122
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
contacts: get_contacts(parser)
|
48
|
-
)
|
49
|
-
# set memo
|
50
|
-
@memo[domain] = whois_record
|
51
|
-
whois_record
|
52
|
-
end
|
53
|
-
|
54
|
-
def reset_cache
|
55
|
-
@memo = {}
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
#
|
61
|
-
# Get created_on
|
62
|
-
#
|
63
|
-
# @param [::Whois::Parser:] parser
|
64
|
-
#
|
65
|
-
# @return [Date, nil]
|
66
|
-
#
|
67
|
-
def get_created_on(parser)
|
68
|
-
parser.created_on
|
69
|
-
rescue ::Whois::AttributeNotImplemented
|
70
|
-
nil
|
71
|
-
end
|
72
|
-
|
73
|
-
#
|
74
|
-
# Get updated_on
|
75
|
-
#
|
76
|
-
# @param [::Whois::Parser:] parser
|
77
|
-
#
|
78
|
-
# @return [Date, nil]
|
79
|
-
#
|
80
|
-
def get_updated_on(parser)
|
81
|
-
parser.updated_on
|
82
|
-
rescue ::Whois::AttributeNotImplemented
|
83
|
-
nil
|
84
|
-
end
|
85
|
-
|
86
|
-
#
|
87
|
-
# Get expires_on
|
88
|
-
#
|
89
|
-
# @param [::Whois::Parser:] parser
|
90
|
-
#
|
91
|
-
# @return [Date, nil]
|
92
|
-
#
|
93
|
-
def get_expires_on(parser)
|
94
|
-
parser.expires_on
|
95
|
-
rescue ::Whois::AttributeNotImplemented
|
96
|
-
nil
|
97
|
-
end
|
98
|
-
|
99
|
-
#
|
100
|
-
# Get registrar
|
101
|
-
#
|
102
|
-
# @param [::Whois::Parser:] parser
|
103
|
-
#
|
104
|
-
# @return [Hash, nil]
|
105
|
-
#
|
106
|
-
def get_registrar(parser)
|
107
|
-
parser.registrar&.to_h
|
108
|
-
rescue ::Whois::AttributeNotImplemented
|
109
|
-
nil
|
110
|
-
end
|
111
|
-
|
112
|
-
#
|
113
|
-
# Get contacts
|
114
|
-
#
|
115
|
-
# @param [::Whois::Parser:] parser
|
116
|
-
#
|
117
|
-
# @return [Array[Hash], nil]
|
118
|
-
#
|
119
|
-
def get_contacts(parser)
|
120
|
-
parser.contacts.map(&:to_h)
|
121
|
-
rescue ::Whois::AttributeNotImplemented
|
122
|
-
nil
|
123
|
-
end
|
123
|
+
#
|
124
|
+
# Get contacts
|
125
|
+
#
|
126
|
+
# @param [::Whois::Parser:] parser
|
127
|
+
#
|
128
|
+
# @return [Array[Hash], nil]
|
129
|
+
#
|
130
|
+
def get_contacts(parser)
|
131
|
+
parser.contacts.map(&:to_h)
|
132
|
+
rescue ::Whois::AttributeNotImplemented
|
133
|
+
nil
|
124
134
|
end
|
125
135
|
end
|
126
136
|
end
|
@@ -19,15 +19,17 @@ module Mihari
|
|
19
19
|
#
|
20
20
|
# @param [Integer] times
|
21
21
|
# @param [Integer] interval
|
22
|
+
# @param [Boolean] exponential_backoff
|
22
23
|
# @param [Array<StandardError>] on
|
23
24
|
#
|
24
|
-
def retry_on_error(times: 3, interval: 5, on: DEFAULT_ON)
|
25
|
+
def retry_on_error(times: 3, interval: 5, exponential_backoff: true, on: DEFAULT_ON)
|
25
26
|
try = 0
|
26
27
|
begin
|
27
28
|
try += 1
|
28
29
|
yield
|
29
30
|
rescue *on => e
|
30
|
-
|
31
|
+
sleep_seconds = exponential_backoff ? interval * (2**(try - 1)) : interval
|
32
|
+
sleep sleep_seconds
|
31
33
|
retry if try < times
|
32
34
|
raise e
|
33
35
|
end
|
@@ -73,64 +73,78 @@ module Mihari
|
|
73
73
|
#
|
74
74
|
# Enrich(add) whois record
|
75
75
|
#
|
76
|
-
|
76
|
+
# @param [Mihari::Enrichers::Whois] enricher
|
77
|
+
#
|
78
|
+
def enrich_whois(enricher = Enrichers::Whois.new)
|
77
79
|
return unless can_enrich_whois?
|
78
80
|
|
79
|
-
self.whois_record = WhoisRecord.build_by_domain(normalize_as_domain(data))
|
81
|
+
self.whois_record = WhoisRecord.build_by_domain(normalize_as_domain(data), enricher: enricher)
|
80
82
|
end
|
81
83
|
|
82
84
|
#
|
83
85
|
# Enrich(add) DNS records
|
84
86
|
#
|
85
|
-
|
87
|
+
# @param [Mihari::Enrichers::GooglePublicDNS] enricher
|
88
|
+
#
|
89
|
+
def enrich_dns(enricher = Enrichers::GooglePublicDNS.new)
|
86
90
|
return unless can_enrich_dns?
|
87
91
|
|
88
|
-
self.dns_records = DnsRecord.build_by_domain(normalize_as_domain(data))
|
92
|
+
self.dns_records = DnsRecord.build_by_domain(normalize_as_domain(data), enricher: enricher)
|
89
93
|
end
|
90
94
|
|
91
95
|
#
|
92
96
|
# Enrich(add) reverse DNS names
|
93
97
|
#
|
94
|
-
|
98
|
+
# @param [Mihari::Enrichers::Shodan] enricher
|
99
|
+
#
|
100
|
+
def enrich_reverse_dns(enricher = Enrichers::Shodan.new)
|
95
101
|
return unless can_enrich_revese_dns?
|
96
102
|
|
97
|
-
self.reverse_dns_names = ReverseDnsName.build_by_ip(data)
|
103
|
+
self.reverse_dns_names = ReverseDnsName.build_by_ip(data, enricher: enricher)
|
98
104
|
end
|
99
105
|
|
100
106
|
#
|
101
107
|
# Enrich(add) geolocation
|
102
108
|
#
|
103
|
-
|
109
|
+
# @param [Mihari::Enrichers::IPInfo] enricher
|
110
|
+
#
|
111
|
+
def enrich_geolocation(enricher = Enrichers::IPInfo.new)
|
104
112
|
return unless can_enrich_geolocation?
|
105
113
|
|
106
|
-
self.geolocation = Geolocation.build_by_ip(data)
|
114
|
+
self.geolocation = Geolocation.build_by_ip(data, enricher: enricher)
|
107
115
|
end
|
108
116
|
|
109
117
|
#
|
110
118
|
# Enrich AS
|
111
119
|
#
|
112
|
-
|
120
|
+
# @param [Mihari::Enrichers::IPInfo] enricher
|
121
|
+
#
|
122
|
+
def enrich_autonomous_system(enricher = Enrichers::IPInfo.new)
|
113
123
|
return unless can_enrich_autonomous_system?
|
114
124
|
|
115
|
-
self.autonomous_system = AutonomousSystem.build_by_ip(data)
|
125
|
+
self.autonomous_system = AutonomousSystem.build_by_ip(data, enricher: enricher)
|
116
126
|
end
|
117
127
|
|
118
128
|
#
|
119
129
|
# Enrich ports
|
120
130
|
#
|
121
|
-
|
131
|
+
# @param [Mihari::Enrichers::Shodan] enricher
|
132
|
+
#
|
133
|
+
def enrich_ports(enricher = Enrichers::Shodan.new)
|
122
134
|
return unless can_enrich_ports?
|
123
135
|
|
124
|
-
self.ports = Port.build_by_ip(data)
|
136
|
+
self.ports = Port.build_by_ip(data, enricher: enricher)
|
125
137
|
end
|
126
138
|
|
127
139
|
#
|
128
140
|
# Enrich CPEs
|
129
141
|
#
|
130
|
-
|
142
|
+
# @param [Mihari::Enrichers::Shodan] enricher
|
143
|
+
#
|
144
|
+
def enrich_cpes(enricher = Enrichers::Shodan.new)
|
131
145
|
return unless can_enrich_cpes?
|
132
146
|
|
133
|
-
self.cpes = CPE.build_by_ip(data)
|
147
|
+
self.cpes = CPE.build_by_ip(data, enricher: enricher)
|
134
148
|
end
|
135
149
|
|
136
150
|
#
|
@@ -147,32 +161,32 @@ module Mihari
|
|
147
161
|
end
|
148
162
|
|
149
163
|
ENRICH_METHODS_BY_ENRICHER = {
|
150
|
-
|
151
|
-
|
164
|
+
Enrichers::Whois => %i[
|
165
|
+
enrich_whois
|
152
166
|
],
|
153
|
-
|
167
|
+
Enrichers::IPInfo => %i[
|
154
168
|
enrich_autonomous_system
|
155
169
|
enrich_geolocation
|
156
170
|
],
|
157
|
-
|
171
|
+
Enrichers::Shodan => %i[
|
158
172
|
enrich_ports
|
159
173
|
enrich_cpes
|
160
174
|
enrich_reverse_dns
|
161
175
|
],
|
162
|
-
|
163
|
-
|
176
|
+
Enrichers::GooglePublicDNS => %i[
|
177
|
+
enrich_dns
|
164
178
|
]
|
165
179
|
}.freeze
|
166
180
|
|
167
181
|
#
|
168
182
|
# Enrich by name of enricher
|
169
183
|
#
|
170
|
-
# @param [
|
184
|
+
# @param [Mihari::Enrichers::Base] enricher
|
171
185
|
#
|
172
186
|
def enrich_by_enricher(enricher)
|
173
|
-
methods = ENRICH_METHODS_BY_ENRICHER[enricher.
|
187
|
+
methods = ENRICH_METHODS_BY_ENRICHER[enricher.class] || []
|
174
188
|
methods.each do |method|
|
175
|
-
send(method) if respond_to?(method)
|
189
|
+
send(method, enricher) if respond_to?(method)
|
176
190
|
end
|
177
191
|
end
|
178
192
|
|
@@ -11,11 +11,12 @@ module Mihari
|
|
11
11
|
# Build AS
|
12
12
|
#
|
13
13
|
# @param [String] ip
|
14
|
+
# @param [Mihari::Enrichers::IPInfo] enricher
|
14
15
|
#
|
15
16
|
# @return [Mihari::AutonomousSystem, nil]
|
16
17
|
#
|
17
|
-
def build_by_ip(ip)
|
18
|
-
result =
|
18
|
+
def build_by_ip(ip, enricher: Enrichers::IPInfo.new)
|
19
|
+
result = enricher.query_result(ip).bind do |res|
|
19
20
|
value = res&.asn
|
20
21
|
if value.nil?
|
21
22
|
Success nil
|
data/lib/mihari/models/cpe.rb
CHANGED
@@ -11,11 +11,12 @@ module Mihari
|
|
11
11
|
# Build CPEs
|
12
12
|
#
|
13
13
|
# @param [String] ip
|
14
|
+
# @param [Mihari::Enrichers::Shodan] enricher
|
14
15
|
#
|
15
16
|
# @return [Array<Mihari::CPE>]
|
16
17
|
#
|
17
|
-
def build_by_ip(ip)
|
18
|
-
result =
|
18
|
+
def build_by_ip(ip, enricher: Enrichers::Shodan.new)
|
19
|
+
result = enricher.query_result(ip).bind do |res|
|
19
20
|
if res.nil?
|
20
21
|
Success []
|
21
22
|
else
|
data/lib/mihari/models/dns.rb
CHANGED
@@ -11,11 +11,12 @@ module Mihari
|
|
11
11
|
# Build DNS records
|
12
12
|
#
|
13
13
|
# @param [String] domain
|
14
|
+
# @param [Mihari::Enrichers::Shodan] enricher
|
14
15
|
#
|
15
16
|
# @return [Array<Mihari::DnsRecord>]
|
16
17
|
#
|
17
|
-
def build_by_domain(domain)
|
18
|
-
result =
|
18
|
+
def build_by_domain(domain, enricher: Enrichers::GooglePublicDNS.new)
|
19
|
+
result = enricher.query_result(domain).bind do |responses|
|
19
20
|
Success(
|
20
21
|
responses.map do |res|
|
21
22
|
res.answers.map do |answer|
|
@@ -13,11 +13,12 @@ module Mihari
|
|
13
13
|
# Build Geolocation
|
14
14
|
#
|
15
15
|
# @param [String] ip
|
16
|
+
# @param [Mihari::Enrichers::IPinfo] enricher
|
16
17
|
#
|
17
18
|
# @return [Mihari::Geolocation, nil]
|
18
19
|
#
|
19
|
-
def build_by_ip(ip)
|
20
|
-
result =
|
20
|
+
def build_by_ip(ip, enricher: Enrichers::IPInfo.new)
|
21
|
+
result = enricher.query_result(ip).bind do |res|
|
21
22
|
value = res&.country_code
|
22
23
|
if value.nil?
|
23
24
|
Success nil
|
data/lib/mihari/models/port.rb
CHANGED
@@ -11,11 +11,12 @@ module Mihari
|
|
11
11
|
# Build ports
|
12
12
|
#
|
13
13
|
# @param [String] ip
|
14
|
+
# @param [Mihari::Enrichers::Shodan] enricher
|
14
15
|
#
|
15
16
|
# @return [Array<Mihari::Port>]
|
16
17
|
#
|
17
|
-
def build_by_ip(ip)
|
18
|
-
result =
|
18
|
+
def build_by_ip(ip, enricher: Enrichers::Shodan.new)
|
19
|
+
result = enricher.query_result(ip).bind do |res|
|
19
20
|
if res.nil?
|
20
21
|
Success []
|
21
22
|
else
|
@@ -11,11 +11,12 @@ module Mihari
|
|
11
11
|
# Build reverse DNS names
|
12
12
|
#
|
13
13
|
# @param [String] ip
|
14
|
+
# @param [Mihari::Enrichers::Shodan] enricher
|
14
15
|
#
|
15
16
|
# @return [Array<Mihari::ReverseDnsName>]
|
16
17
|
#
|
17
|
-
def build_by_ip(ip)
|
18
|
-
result =
|
18
|
+
def build_by_ip(ip, enricher: Enrichers::Shodan.new)
|
19
|
+
result = enricher.query_result(ip).bind do |res|
|
19
20
|
if res.nil?
|
20
21
|
Success []
|
21
22
|
else
|
data/lib/mihari/models/whois.rb
CHANGED
@@ -12,12 +12,13 @@ module Mihari
|
|
12
12
|
#
|
13
13
|
# Build whois record
|
14
14
|
#
|
15
|
-
# @param [
|
15
|
+
# @param [String] domain
|
16
|
+
# @param [Mihari::Enrichers::Whois] enricher
|
16
17
|
#
|
17
18
|
# @return [WhoisRecord, nil]
|
18
19
|
#
|
19
|
-
def build_by_domain(domain)
|
20
|
-
result =
|
20
|
+
def build_by_domain(domain, enricher: Enrichers::Whois.new)
|
21
|
+
result = enricher.query_result(domain)
|
21
22
|
result.value_or nil
|
22
23
|
end
|
23
24
|
end
|
@@ -3,10 +3,11 @@
|
|
3
3
|
module Mihari
|
4
4
|
module Schemas
|
5
5
|
AnalyzerOptions = Dry::Schema.Params do
|
6
|
-
optional(:
|
6
|
+
optional(:pagination_interval).value(:integer).default(Mihari.config.pagination_interval)
|
7
7
|
optional(:pagination_limit).value(:integer).default(Mihari.config.pagination_limit)
|
8
8
|
optional(:retry_times).value(:integer).default(Mihari.config.retry_times)
|
9
9
|
optional(:retry_interval).value(:integer).default(Mihari.config.retry_interval)
|
10
|
+
optional(:retry_exponential_backoff).value(:bool).default(Mihari.config.retry_exponential_backoff)
|
10
11
|
optional(:ignore_error).value(:bool).default(Mihari.config.ignore_error)
|
11
12
|
optional(:timeout).value(:integer)
|
12
13
|
end
|
@@ -2,35 +2,49 @@
|
|
2
2
|
|
3
3
|
module Mihari
|
4
4
|
module Schemas
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
module Emitters
|
6
|
+
EmitterOptions = Dry::Schema.Params do
|
7
|
+
optional(:retry_times).value(:integer).default(Mihari.config.retry_times)
|
8
|
+
optional(:retry_interval).value(:integer).default(Mihari.config.retry_interval)
|
9
|
+
optional(:retry_exponential_backoff).value(:bool).default(Mihari.config.retry_exponential_backoff)
|
10
|
+
optional(:timeout).value(:integer)
|
11
|
+
end
|
8
12
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
13
|
+
Database = Dry::Schema.Params do
|
14
|
+
required(:emitter).value(Types::String.enum("database"))
|
15
|
+
optional(:options).hash(EmitterOptions)
|
16
|
+
end
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
MISP = Dry::Schema.Params do
|
19
|
+
required(:emitter).value(Types::String.enum("misp"))
|
20
|
+
optional(:url).value(:string)
|
21
|
+
optional(:api_key).value(:string)
|
22
|
+
optional(:options).hash(EmitterOptions)
|
23
|
+
end
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
TheHive = Dry::Schema.Params do
|
26
|
+
required(:emitter).value(Types::String.enum("the_hive"))
|
27
|
+
optional(:url).value(:string)
|
28
|
+
optional(:api_key).value(:string)
|
29
|
+
optional(:api_version).value(Types::String.enum("v4", "v5")).default("v4")
|
30
|
+
optional(:options).hash(EmitterOptions)
|
31
|
+
end
|
32
|
+
|
33
|
+
Slack = Dry::Schema.Params do
|
34
|
+
required(:emitter).value(Types::String.enum("slack"))
|
35
|
+
optional(:webhook_url).value(:string)
|
36
|
+
optional(:channel).value(:string)
|
37
|
+
optional(:options).hash(EmitterOptions)
|
38
|
+
end
|
27
39
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
40
|
+
Webhook = Dry::Schema.Params do
|
41
|
+
required(:emitter).value(Types::String.enum("webhook"))
|
42
|
+
required(:url).value(:string)
|
43
|
+
optional(:method).value(Types::HTTPRequestMethods).default("POST")
|
44
|
+
optional(:headers).value(:hash).default({})
|
45
|
+
optional(:template).value(:string)
|
46
|
+
optional(:options).hash(EmitterOptions)
|
47
|
+
end
|
34
48
|
end
|
35
49
|
end
|
36
50
|
end
|
@@ -2,8 +2,34 @@
|
|
2
2
|
|
3
3
|
module Mihari
|
4
4
|
module Schemas
|
5
|
-
|
6
|
-
|
5
|
+
module Enrichers
|
6
|
+
EnricherOptions = Dry::Schema.Params do
|
7
|
+
optional(:retry_times).value(:integer).default(Mihari.config.retry_times)
|
8
|
+
optional(:retry_interval).value(:integer).default(Mihari.config.retry_interval)
|
9
|
+
optional(:retry_exponential_backoff).value(:bool).default(Mihari.config.retry_exponential_backoff)
|
10
|
+
optional(:timeout).value(:integer)
|
11
|
+
end
|
12
|
+
|
13
|
+
IPInfo = Dry::Schema.Params do
|
14
|
+
required(:enricher).value(Types::String.enum("ipinfo"))
|
15
|
+
optional(:api_key).value(:string)
|
16
|
+
optional(:options).hash(EnricherOptions)
|
17
|
+
end
|
18
|
+
|
19
|
+
Whois = Dry::Schema.Params do
|
20
|
+
required(:enricher).value(Types::String.enum("whois"))
|
21
|
+
optional(:options).hash(EnricherOptions)
|
22
|
+
end
|
23
|
+
|
24
|
+
Shodan = Dry::Schema.Params do
|
25
|
+
required(:enricher).value(Types::String.enum("shodan"))
|
26
|
+
optional(:options).hash(EnricherOptions)
|
27
|
+
end
|
28
|
+
|
29
|
+
GooglePublicDNS = Dry::Schema.Params do
|
30
|
+
required(:enricher).value(Types::String.enum("google_public_dns"))
|
31
|
+
optional(:options).hash(EnricherOptions)
|
32
|
+
end
|
7
33
|
end
|
8
34
|
end
|
9
35
|
end
|
data/lib/mihari/schemas/rule.rb
CHANGED
@@ -25,9 +25,13 @@ module Mihari
|
|
25
25
|
AnalyzerWithoutAPIKey | AnalyzerWithAPIKey | Censys | CIRCL | PassiveTotal | ZoomEye | Crtsh | Feed | HunterHow
|
26
26
|
end
|
27
27
|
|
28
|
-
optional(:emitters).value(:array).each
|
28
|
+
optional(:emitters).value(:array).each do
|
29
|
+
Emitters::Database | Emitters::MISP | Emitters::TheHive | Emitters::Slack | Emitters::Webhook
|
30
|
+
end.default(DEFAULT_EMITTERS)
|
29
31
|
|
30
|
-
optional(:enrichers).value(:array).each
|
32
|
+
optional(:enrichers).value(:array).each do
|
33
|
+
Enrichers::Whois | Enrichers::IPInfo | Enrichers::Shodan | Enrichers::GooglePublicDNS
|
34
|
+
end.default(DEFAULT_ENRICHERS)
|
31
35
|
|
32
36
|
optional(:data_types).value(array[Types::DataTypes]).default(DEFAULT_DATA_TYPES)
|
33
37
|
optional(:falsepositives).value(array[:string]).default([])
|
data/lib/mihari/version.rb
CHANGED
@@ -15,7 +15,7 @@ module Mihari
|
|
15
15
|
get "/:ip", requirements: { ip: %r{[^/]+} } do
|
16
16
|
ip = params[:ip].to_s
|
17
17
|
|
18
|
-
data = Enrichers::IPInfo.query(ip)
|
18
|
+
data = Enrichers::IPInfo.new.query(ip)
|
19
19
|
error!({ message: "IP:#{ip} is not found" }, 404) if data.nil?
|
20
20
|
|
21
21
|
present data, with: Entities::IPAddress
|