mihari 7.0.0 → 7.0.2

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: c3f4b3b5ca761f5ca5e6f3697593f8253b1e6aa03f21924726ad5dc78ac3f011
4
- data.tar.gz: f673dd7775f31c2fa134102c8cf9707e0d6fc74467f496c86202de43db7b3c5a
3
+ metadata.gz: 184d0084b9ab68c359ddaa10436a2a6172fa09e71f0cc4492af57a1afcf924d8
4
+ data.tar.gz: 035620673b2351bd6c70a837c7e73f36819e320a868298b6e9a07271759bf6ed
5
5
  SHA512:
6
- metadata.gz: 0f139c2a0795bd6e741ce93681f8be47cb75fcb5b707d187d1fd2c758bfe2877388d0d5a25fe5920ec2e7565532c142b585b0029816899664426becea2f0776c
7
- data.tar.gz: 6dad7972edcba2090bfa12170539efcd51a20dc1ba94757383546ae630002d374e33dcdbc99675cc719801a80b92a11d2eff308a553d627050f8596d6a877c9a
6
+ metadata.gz: 8f16c21d9475313b8d6ef81cd12fe79c18964552f27633aa2c23fd530c92f9eece651af02fc51b3059f4e57acd6a7c5080607f2822488d26d56a0945c97c424b
7
+ data.tar.gz: 25640e747ea9113d294dcb910574d7958d0883187e03f0fa891f809b1bc997722bc9af48299685d4f67d51562a6a9d6cdbec0eb499d6e1afb38410e38a7c1936
data/Dockerfile CHANGED
@@ -2,10 +2,11 @@ FROM ruby:3.2.2-alpine3.19
2
2
 
3
3
  ARG MIHARI_VERSION=0.0.0
4
4
 
5
- RUN apk --no-cache add git build-base ruby-dev postgresql-dev && \
5
+ RUN apk --no-cache add build-base ruby-dev libpq-dev && \
6
+ echo 'gem: --no-document' >> /usr/local/etc/gemrc && \
6
7
  gem install pg && \
7
8
  gem install mihari -v ${MIHARI_VERSION} && \
8
- apk del --purge git build-base ruby-dev && \
9
+ apk del --purge build-base ruby-dev && \
9
10
  rm -rf /usr/local/bundle/cache/*
10
11
 
11
12
  ENTRYPOINT ["mihari"]
data/docker-compose.yml CHANGED
@@ -47,8 +47,7 @@ services:
47
47
  image: ghcr.io/ninoseki/mihari:latest
48
48
  environment:
49
49
  - DATABASE_URL=${DATABASE_URL:-postgresql://${POSTGRES_USER:-user}:${POSTGRES_PASSWORD:-password}@database:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-mihari}}
50
- - REDIS_URL=${REDIS_URL:-redis://redis:${REDIS_PORT:-6379}}
51
- - USE_SIDEKIQ=true
50
+ - SIDEKIQ_REDIS_URL=${REDIS_URL:-redis://redis:${REDIS_PORT:-6379}}
52
51
  env_file:
53
52
  - .env
54
53
  entrypoint: ["mihari", "sidekiq"]
@@ -9,20 +9,25 @@ module Mihari
9
9
  # @return [Boolean]
10
10
  attr_reader :exclude_expired
11
11
 
12
+ # @return [String, nil]
13
+ attr_reader :match
14
+
12
15
  #
13
16
  # @param [String] query
14
17
  # @param [Hash, nil] options
15
18
  # @param [Bool] exclude_expired
19
+ # @param [String, nil] match
16
20
  #
17
- def initialize(query, options: nil, exclude_expired: true)
21
+ def initialize(query, options: nil, exclude_expired: true, match: nil)
18
22
  super(query, options: options)
19
23
 
20
24
  @exclude_expired = exclude_expired
25
+ @match = match
21
26
  end
22
27
 
23
28
  def artifacts
24
29
  exclude = exclude_expired ? "expired" : nil
25
- client.search(query, exclude: exclude).map do |result|
30
+ client.search(query, exclude: exclude, match: match).map do |result|
26
31
  values = result["name_value"].to_s.lines.map(&:chomp).reject { |value| value.starts_with?("*.") }
27
32
  values.map { |value| Models::Artifact.new(data: value, metadata: result) }
28
33
  end.flatten
@@ -19,7 +19,7 @@ module Mihari
19
19
  # Search crt.sh by a given identity
20
20
  #
21
21
  # @param [String] identity
22
- # @param [String, nil] match "=", "ILIKE", "LIKE", "single", "any" or nil
22
+ # @param [String, nil] match "=", "ILIKE", "LIKE", "single", "any", "FTS" or nil
23
23
  # @param [String, nil] exclude "expired" or nil
24
24
  #
25
25
  # @return [Array<Hash>]
@@ -87,7 +87,7 @@ module Mihari
87
87
  def enrich_whois(enricher = Enrichers::Whois.new)
88
88
  return unless can_enrich_whois?
89
89
 
90
- self.whois_record = WhoisRecord.build_by_domain(normalize_as_domain(data), enricher: enricher)
90
+ self.whois_record = Services::WhoisRecordBuilder.call(domain, enricher: enricher)
91
91
  end
92
92
 
93
93
  #
@@ -98,7 +98,7 @@ module Mihari
98
98
  def enrich_dns(enricher = Enrichers::GooglePublicDNS.new)
99
99
  return unless can_enrich_dns?
100
100
 
101
- self.dns_records = DnsRecord.build_by_domain(normalize_as_domain(data), enricher: enricher)
101
+ self.dns_records = Services::DnsRecordBuilder.call(domain, enricher: enricher)
102
102
  end
103
103
 
104
104
  #
@@ -109,7 +109,7 @@ module Mihari
109
109
  def enrich_reverse_dns(enricher = Enrichers::Shodan.new)
110
110
  return unless can_enrich_reverse_dns?
111
111
 
112
- self.reverse_dns_names = ReverseDnsName.build_by_ip(data, enricher: enricher)
112
+ self.reverse_dns_names = Services::ReverseDnsNameBuilder.call(data, enricher: enricher)
113
113
  end
114
114
 
115
115
  #
@@ -120,7 +120,7 @@ module Mihari
120
120
  def enrich_geolocation(enricher = Enrichers::MMDB.new)
121
121
  return unless can_enrich_geolocation?
122
122
 
123
- self.geolocation = Geolocation.build_by_ip(data, enricher: enricher)
123
+ self.geolocation = Services::GeolocationBuilder.call(data, enricher: enricher)
124
124
  end
125
125
 
126
126
  #
@@ -131,7 +131,7 @@ module Mihari
131
131
  def enrich_autonomous_system(enricher = Enrichers::MMDB.new)
132
132
  return unless can_enrich_autonomous_system?
133
133
 
134
- self.autonomous_system = AutonomousSystem.build_by_ip(data, enricher: enricher)
134
+ self.autonomous_system = Services::AutonomousSystemBuilder.call(data, enricher: enricher)
135
135
  end
136
136
 
137
137
  #
@@ -142,7 +142,7 @@ module Mihari
142
142
  def enrich_ports(enricher = Enrichers::Shodan.new)
143
143
  return unless can_enrich_ports?
144
144
 
145
- self.ports = Port.build_by_ip(data, enricher: enricher)
145
+ self.ports = Services::PortBuilder.call(data, enricher: enricher)
146
146
  end
147
147
 
148
148
  #
@@ -153,7 +153,7 @@ module Mihari
153
153
  def enrich_cpes(enricher = Enrichers::Shodan.new)
154
154
  return unless can_enrich_cpes?
155
155
 
156
- self.cpes = CPE.build_by_ip(data, enricher: enricher)
156
+ self.cpes = Services::CPEBuilder.call(data, enricher: enricher)
157
157
  end
158
158
 
159
159
  #
@@ -225,10 +225,16 @@ module Mihari
225
225
  @shodan ||= Enrichers::Shodan.new
226
226
  end
227
227
 
228
- def normalize_as_domain(url_or_domain)
229
- return url_or_domain if data_type == "domain"
230
-
231
- Addressable::URI.parse(url_or_domain).host
228
+ #
229
+ # @return [String, nil]
230
+ #
231
+ def domain
232
+ case data_type
233
+ when "domain"
234
+ data
235
+ when "url"
236
+ Addressable::URI.parse(data).host
237
+ end
232
238
  end
233
239
 
234
240
  def can_enrich_whois?
@@ -7,22 +7,6 @@ module Mihari
7
7
  #
8
8
  class AutonomousSystem < ActiveRecord::Base
9
9
  belongs_to :artifact
10
-
11
- class << self
12
- #
13
- # Build AS
14
- #
15
- # @param [String] ip
16
- # @param [Mihari::Enrichers::MMDB] enricher
17
- #
18
- # @return [Mihari::AutonomousSystem, nil]
19
- #
20
- def build_by_ip(ip, enricher: Enrichers::MMDB.new)
21
- enricher.result(ip).fmap do |res|
22
- new(asn: res.asn) if res.asn
23
- end.value_or nil
24
- end
25
- end
26
10
  end
27
11
  end
28
12
  end
@@ -7,22 +7,6 @@ module Mihari
7
7
  #
8
8
  class CPE < ActiveRecord::Base
9
9
  belongs_to :artifact
10
-
11
- class << self
12
- #
13
- # Build CPEs
14
- #
15
- # @param [String] ip
16
- # @param [Mihari::Enrichers::Shodan] enricher
17
- #
18
- # @return [Array<Mihari::CPE>]
19
- #
20
- def build_by_ip(ip, enricher: Enrichers::Shodan.new)
21
- enricher.result(ip).fmap do |res|
22
- (res&.cpes || []).map { |cpe| new(cpe: cpe) }
23
- end.value_or []
24
- end
25
- end
26
10
  end
27
11
  end
28
12
  end
@@ -7,22 +7,6 @@ module Mihari
7
7
  #
8
8
  class DnsRecord < ActiveRecord::Base
9
9
  belongs_to :artifact
10
-
11
- class << self
12
- #
13
- # Build DNS records
14
- #
15
- # @param [String] domain
16
- # @param [Mihari::Enrichers::Shodan] enricher
17
- #
18
- # @return [Array<Mihari::Models::DnsRecord>]
19
- #
20
- def build_by_domain(domain, enricher: Enrichers::GooglePublicDNS.new)
21
- enricher.result(domain).fmap do |res|
22
- res.answers.map { |answer| new(resource: answer.resource_type, value: answer.data) }
23
- end.value_or([])
24
- end
25
- end
26
10
  end
27
11
  end
28
12
  end
@@ -9,25 +9,6 @@ module Mihari
9
9
  #
10
10
  class Geolocation < ActiveRecord::Base
11
11
  belongs_to :artifact
12
-
13
- class << self
14
- #
15
- # Build Geolocation
16
- #
17
- # @param [String] ip
18
- # @param [Mihari::Enrichers::MMDB] enricher
19
- #
20
- # @return [Mihari::Geolocation, nil]
21
- #
22
- def build_by_ip(ip, enricher: Enrichers::MMDB.new)
23
- enricher.result(ip).fmap do |res|
24
- if res.country_code
25
- new(country: NormalizeCountry(res.country_code, to: :short),
26
- country_code: res.country_code)
27
- end
28
- end.value_or nil
29
- end
30
- end
31
12
  end
32
13
  end
33
14
  end
@@ -7,24 +7,6 @@ module Mihari
7
7
  #
8
8
  class ReverseDnsName < ActiveRecord::Base
9
9
  belongs_to :artifact
10
-
11
- class << self
12
- include Dry::Monads[:result]
13
-
14
- #
15
- # Build reverse DNS names
16
- #
17
- # @param [String] ip
18
- # @param [Mihari::Enrichers::Shodan] enricher
19
- #
20
- # @return [Array<Mihari::Models::ReverseDnsName>]
21
- #
22
- def build_by_ip(ip, enricher: Enrichers::Shodan.new)
23
- enricher.result(ip).fmap do |res|
24
- (res&.hostnames || []).map { |name| new(name: name) }
25
- end.value_or []
26
- end
27
- end
28
10
  end
29
11
  end
30
12
  end
@@ -7,20 +7,6 @@ module Mihari
7
7
  #
8
8
  class WhoisRecord < ActiveRecord::Base
9
9
  belongs_to :artifact
10
-
11
- class << self
12
- #
13
- # Build whois record
14
- #
15
- # @param [String] domain
16
- # @param [Mihari::Enrichers::Whois] enricher
17
- #
18
- # @return [WhoisRecord, nil]
19
- #
20
- def build_by_domain(domain, enricher: Enrichers::Whois.new)
21
- enricher.result(domain).value_or nil
22
- end
23
- end
24
10
  end
25
11
  end
26
12
  end
@@ -91,6 +91,7 @@ module Mihari
91
91
  required(:analyzer).value(Types::String.enum(*Mihari::Analyzers::Crtsh.class_keys))
92
92
  required(:query).value(:string)
93
93
  optional(:exclude_expired).value(:bool).default(true)
94
+ optional(:match).value(Types::String.enum("=", "ILIKE", "LIKE", "single", "any", "FTS")).default(nil)
94
95
  optional(:options).hash(AnalyzerOptions)
95
96
  end
96
97
 
@@ -6,35 +6,152 @@ module Mihari
6
6
  # Rule builder
7
7
  #
8
8
  class RuleBuilder < Service
9
- # @return [String]
10
- attr_reader :path_or_id
11
-
12
9
  #
13
10
  # @param [String] path_or_id
14
11
  #
15
- # @return [Hash]
12
+ # @return [Mihari::Rule]
16
13
  #
17
- def data
18
- result = Try { Mihari::Models::Rule.find path_or_id }.to_result
19
- return result.value! if result.success?
14
+ def call(path_or_id)
15
+ res = Try { Rule.from_model Mihari::Models::Rule.find(path_or_id) }
16
+ return res.value! if res.value?
20
17
 
21
18
  raise ArgumentError, "#{path_or_id} not found" unless Pathname(path_or_id).exist?
22
19
 
23
- YAML.safe_load(
24
- ERB.new(File.read(path_or_id)).result,
25
- permitted_classes: [Date, Symbol]
26
- )
20
+ Rule.from_yaml ERB.new(File.read(path_or_id)).result
27
21
  end
22
+ end
28
23
 
24
+ #
25
+ # Autonomous system builder
26
+ #
27
+ class AutonomousSystemBuilder < Service
29
28
  #
30
- # @param [String] path_or_id
29
+ # @param [String] ip
30
+ # @param [Mihari::Enrichers::MMDB] enricher
31
31
  #
32
- # @return [Mihari::Rule]
32
+ # @return [Mihari::Models::AutonomousSystem, nil]
33
33
  #
34
- def call(path_or_id)
35
- @path_or_id = path_or_id
34
+ def call(ip, enricher: Enrichers::MMDB.new)
35
+ enricher.result(ip).fmap do |res|
36
+ Models::AutonomousSystem.new(asn: res.asn) if res.asn
37
+ end.value_or nil
38
+ end
39
+ end
40
+
41
+ #
42
+ # CPE builder
43
+ #
44
+ class CPEBuilder < Service
45
+ #
46
+ # Build CPEs
47
+ #
48
+ # @param [String] ip
49
+ # @param [Mihari::Enrichers::Shodan] enricher
50
+ #
51
+ # @return [Array<Mihari::Models::CPE>]
52
+ #
53
+ def call(ip, enricher: Enrichers::Shodan.new)
54
+ enricher.result(ip).fmap do |res|
55
+ (res&.cpes || []).map { |cpe| Models::CPE.new(cpe: cpe) }
56
+ end.value_or []
57
+ end
58
+ end
59
+
60
+ #
61
+ # DNS record builder
62
+ #
63
+ class DnsRecordBuilder < Service
64
+ #
65
+ # Build DNS records
66
+ #
67
+ # @param [String] domain
68
+ # @param [Mihari::Enrichers::Shodan] enricher
69
+ #
70
+ # @return [Array<Mihari::Models::DnsRecord>]
71
+ #
72
+ def call(domain, enricher: Enrichers::GooglePublicDNS.new)
73
+ enricher.result(domain).fmap do |res|
74
+ res.answers.map { |answer| Models::DnsRecord.new(resource: answer.resource_type, value: answer.data) }
75
+ end.value_or []
76
+ end
77
+ end
78
+
79
+ #
80
+ # Geolocation builder
81
+ #
82
+ class GeolocationBuilder < Service
83
+ #
84
+ # Build Geolocation
85
+ #
86
+ # @param [String] ip
87
+ # @param [Mihari::Enrichers::MMDB] enricher
88
+ #
89
+ # @return [Mihari::Models::Geolocation, nil]
90
+ #
91
+ def call(ip, enricher: Enrichers::MMDB.new)
92
+ enricher.result(ip).fmap do |res|
93
+ if res.country_code
94
+ Models::Geolocation.new(
95
+ country: NormalizeCountry(res.country_code, to: :short),
96
+ country_code: res.country_code
97
+ )
98
+ end
99
+ end.value_or nil
100
+ end
101
+ end
102
+
103
+ #
104
+ # Port builder
105
+ #
106
+ class PortBuilder < Service
107
+ #
108
+ # Build ports
109
+ #
110
+ # @param [String] ip
111
+ # @param [Mihari::Enrichers::Shodan] enricher
112
+ #
113
+ # @return [Array<Mihari::Models::Port>]
114
+ #
115
+ def call(ip, enricher: Enrichers::Shodan.new)
116
+ enricher.result(ip).fmap do |res|
117
+ (res&.ports || []).map { |port| Models::Port.new(port: port) }
118
+ end.value_or []
119
+ end
120
+ end
36
121
 
37
- Rule.new(**data)
122
+ #
123
+ # Reverse DNS name builder
124
+ #
125
+ class ReverseDnsNameBuilder < Service
126
+ #
127
+ # Build reverse DNS names
128
+ #
129
+ # @param [String] ip
130
+ # @param [Mihari::Enrichers::Shodan] enricher
131
+ #
132
+ # @return [Array<Mihari::Models::ReverseDnsName>]
133
+ #
134
+ def call(ip, enricher: Enrichers::Shodan.new)
135
+ enricher.result(ip).fmap do |res|
136
+ (res&.hostnames || []).map { |name| Models::ReverseDnsName.new(name: name) }
137
+ end.value_or []
138
+ end
139
+ end
140
+
141
+ #
142
+ # Whois record builder
143
+ #
144
+ class WhoisRecordBuilder < Service
145
+ #
146
+ # Build whois record
147
+ #
148
+ # @param [String] domain
149
+ # @param [Mihari::Enrichers::Whois] enricher
150
+ #
151
+ # @return [Mihari::Models::WhoisRecord, nil]
152
+ #
153
+ def call(domain, enricher: Enrichers::Whois.new)
154
+ enricher.result(domain).value_or nil
38
155
  end
39
156
  end
40
157
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- VERSION = "7.0.0"
4
+ VERSION = "7.0.2"
5
5
  end
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: 7.0.0
4
+ version: 7.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Manabu Niseki
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-12-31 00:00:00.000000000 Z
11
+ date: 2024-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: better_errors