mihari 5.2.1 → 5.2.3

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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -0
  3. data/lib/mihari/analyzers/base.rb +20 -115
  4. data/lib/mihari/analyzers/binaryedge.rb +0 -1
  5. data/lib/mihari/analyzers/censys.rb +26 -3
  6. data/lib/mihari/analyzers/circl.rb +1 -1
  7. data/lib/mihari/analyzers/onyphe.rb +1 -1
  8. data/lib/mihari/analyzers/passivetotal.rb +1 -1
  9. data/lib/mihari/analyzers/rule.rb +122 -75
  10. data/lib/mihari/analyzers/shodan.rb +1 -1
  11. data/lib/mihari/analyzers/urlscan.rb +6 -9
  12. data/lib/mihari/analyzers/virustotal_intelligence.rb +1 -6
  13. data/lib/mihari/cli/main.rb +2 -2
  14. data/lib/mihari/clients/base.rb +1 -1
  15. data/lib/mihari/commands/database.rb +12 -11
  16. data/lib/mihari/commands/rule.rb +47 -45
  17. data/lib/mihari/commands/search.rb +88 -0
  18. data/lib/mihari/commands/version.rb +8 -6
  19. data/lib/mihari/commands/web.rb +26 -23
  20. data/lib/mihari/emitters/base.rb +14 -1
  21. data/lib/mihari/emitters/database.rb +3 -10
  22. data/lib/mihari/emitters/misp.rb +16 -5
  23. data/lib/mihari/emitters/slack.rb +13 -15
  24. data/lib/mihari/emitters/the_hive.rb +17 -19
  25. data/lib/mihari/emitters/webhook.rb +23 -23
  26. data/lib/mihari/enrichers/whois.rb +1 -0
  27. data/lib/mihari/feed/parser.rb +1 -0
  28. data/lib/mihari/feed/reader.rb +29 -14
  29. data/lib/mihari/mixins/configurable.rb +13 -4
  30. data/lib/mihari/mixins/error_notification.rb +0 -2
  31. data/lib/mihari/models/artifact.rb +1 -1
  32. data/lib/mihari/schemas/rule.rb +2 -17
  33. data/lib/mihari/structs/censys.rb +226 -56
  34. data/lib/mihari/structs/config.rb +48 -18
  35. data/lib/mihari/structs/google_public_dns.rb +56 -14
  36. data/lib/mihari/structs/greynoise.rb +122 -29
  37. data/lib/mihari/structs/ipinfo.rb +40 -0
  38. data/lib/mihari/structs/onyphe.rb +112 -26
  39. data/lib/mihari/structs/rule.rb +4 -2
  40. data/lib/mihari/structs/shodan.rb +189 -47
  41. data/lib/mihari/structs/urlscan.rb +123 -20
  42. data/lib/mihari/structs/virustotal_intelligence.rb +129 -26
  43. data/lib/mihari/type_checker.rb +10 -8
  44. data/lib/mihari/version.rb +1 -1
  45. data/lib/mihari.rb +1 -0
  46. data/mihari.gemspec +11 -10
  47. metadata +35 -36
  48. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -43
  49. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -15
  50. data/.github/workflows/test.yml +0 -90
  51. data/config/pre_commit.yml +0 -3
  52. data/docker/Dockerfile +0 -14
  53. data/examples/ipinfo_hosted_domains.rb +0 -45
  54. data/images/Tines-Full_Logo-Tines_Black.png +0 -0
  55. data/images/alert.png +0 -0
  56. data/images/logo.png +0 -0
  57. data/images/misp.png +0 -0
  58. data/images/overview.jpg +0 -0
  59. data/images/slack.png +0 -0
  60. data/images/tines.png +0 -0
  61. data/images/web_alerts.png +0 -0
  62. data/images/web_config.png +0 -0
  63. data/lib/mihari/commands/searcher.rb +0 -61
@@ -10,6 +10,27 @@ module Mihari
10
10
  attribute :country_code, Types::String
11
11
  attribute :asn, Types::String
12
12
 
13
+ #
14
+ # @return [String]
15
+ #
16
+ def country
17
+ attributes[:country]
18
+ end
19
+
20
+ #
21
+ # @return [String]
22
+ #
23
+ def country_code
24
+ attributes[:country_code]
25
+ end
26
+
27
+ #
28
+ # @return [String]
29
+ #
30
+ def asn
31
+ attributes[:asn]
32
+ end
33
+
13
34
  #
14
35
  # @return [Mihari::AutonomousSystem]
15
36
  #
@@ -27,13 +48,20 @@ module Mihari
27
48
  )
28
49
  end
29
50
 
30
- def self.from_dynamic!(d)
31
- d = Types::Hash[d]
32
- new(
33
- country: d.fetch("country"),
34
- country_code: d.fetch("country_code"),
35
- asn: d.fetch("asn")
36
- )
51
+ class << self
52
+ #
53
+ # @param [Hash] d
54
+ #
55
+ # @return [Metadata]
56
+ #
57
+ def from_dynamic!(d)
58
+ d = Types::Hash[d]
59
+ new(
60
+ country: d.fetch("country"),
61
+ country_code: d.fetch("country_code"),
62
+ asn: d.fetch("asn")
63
+ )
64
+ end
37
65
  end
38
66
  end
39
67
 
@@ -43,27 +71,52 @@ module Mihari
43
71
  attribute :metadata_, Types::Hash
44
72
 
45
73
  #
46
- # @param [String] source
74
+ # @return [String]
75
+ #
76
+ def ip
77
+ attributes[:ip]
78
+ end
79
+
80
+ #
81
+ # @return [Metadata]
82
+ #
83
+ def metadata
84
+ attributes[:metadata]
85
+ end
86
+
87
+ #
88
+ # @return [Hash]
89
+ #
90
+ def metadata_
91
+ attributes[:metadata_]
92
+ end
93
+
47
94
  #
48
95
  # @return [Mihari::Artifact]
49
96
  #
50
- def to_artifact(source = "GreyNoise")
97
+ def to_artifact
51
98
  Mihari::Artifact.new(
52
99
  data: ip,
53
- source: source,
54
100
  metadata: metadata_,
55
101
  autonomous_system: metadata.to_as,
56
102
  geolocation: metadata.to_geolocation
57
103
  )
58
104
  end
59
105
 
60
- def self.from_dynamic!(d)
61
- d = Types::Hash[d]
62
- new(
63
- ip: d.fetch("ip"),
64
- metadata: Metadata.from_dynamic!(d.fetch("metadata")),
65
- metadata_: d
66
- )
106
+ class << self
107
+ #
108
+ # @param [Hash] d
109
+ #
110
+ # @return [Datum]
111
+ #
112
+ def from_dynamic!(d)
113
+ d = Types::Hash[d]
114
+ new(
115
+ ip: d.fetch("ip"),
116
+ metadata: Metadata.from_dynamic!(d.fetch("metadata")),
117
+ metadata_: d
118
+ )
119
+ end
67
120
  end
68
121
  end
69
122
 
@@ -75,23 +128,63 @@ module Mihari
75
128
  attribute :query, Types::String
76
129
 
77
130
  #
78
- # @param [String] source
131
+ # @return [Boolean]
132
+ #
133
+ def complete
134
+ attributes[:complete]
135
+ end
136
+
137
+ #
138
+ # @return [Integer]
139
+ #
140
+ def count
141
+ attributes[:count]
142
+ end
143
+
144
+ #
145
+ # @return [Array<Datum>]
146
+ #
147
+ def data
148
+ attributes[:data]
149
+ end
150
+
151
+ #
152
+ # @return [String]
153
+ #
154
+ def message
155
+ attributes[:message]
156
+ end
157
+
158
+ #
159
+ # @return [String]
160
+ #
161
+ def query
162
+ attributes[:query]
163
+ end
164
+
79
165
  #
80
166
  # @return [Array<Mihari::Artifact>]
81
167
  #
82
- def to_artifacts(source = "GreyNoise")
83
- data.map { |datum| datum.to_artifact(source) }
168
+ def to_artifacts
169
+ data.map { |datum| datum.to_artifact }
84
170
  end
85
171
 
86
- def self.from_dynamic!(d)
87
- d = Types::Hash[d]
88
- new(
89
- complete: d.fetch("complete"),
90
- count: d.fetch("count"),
91
- data: d.fetch("data").map { |x| Datum.from_dynamic!(x) },
92
- message: d.fetch("message"),
93
- query: d.fetch("query")
94
- )
172
+ class << self
173
+ #
174
+ # @param [Hash] d
175
+ #
176
+ # @return [Response]
177
+ #
178
+ def from_dynamic!(d)
179
+ d = Types::Hash[d]
180
+ new(
181
+ complete: d.fetch("complete"),
182
+ count: d.fetch("count"),
183
+ data: d.fetch("data").map { |x| Datum.from_dynamic!(x) },
184
+ message: d.fetch("message"),
185
+ query: d.fetch("query")
186
+ )
187
+ end
95
188
  end
96
189
  end
97
190
  end
@@ -10,9 +10,49 @@ module Mihari
10
10
  attribute :country_code, Types::String.optional
11
11
  attribute :asn, Types::Integer.optional
12
12
 
13
+ #
14
+ # @return [String]
15
+ #
16
+ def ip
17
+ attributes[:ip]
18
+ end
19
+
20
+ #
21
+ # @return [String, nil]
22
+ #
23
+ def hostname
24
+ attributes[:hostname]
25
+ end
26
+
27
+ #
28
+ # @return [String, nil]
29
+ #
30
+ def loc
31
+ attributes[:loc]
32
+ end
33
+
34
+ #
35
+ # @return [String, nil]
36
+ #
37
+ def country_code
38
+ attributes[:country_code]
39
+ end
40
+
41
+ #
42
+ # @return [Integer, nil]
43
+ #
44
+ def asn
45
+ attributes[:asn]
46
+ end
47
+
13
48
  class << self
14
49
  include Mixins::AutonomousSystem
15
50
 
51
+ #
52
+ # @param [Hash] d
53
+ #
54
+ # @return [Response]
55
+ #
16
56
  def from_dynamic!(d)
17
57
  d = d.deep_stringify_keys
18
58
  d = Types::Hash[d]
@@ -12,14 +12,39 @@ module Mihari
12
12
  attribute :metadata, Types::Hash
13
13
 
14
14
  #
15
- # @param [String] source
15
+ # @return [String]
16
+ #
17
+ def asn
18
+ attributes[:asn]
19
+ end
20
+
21
+ #
22
+ # @return [String, nil]
23
+ #
24
+ def country_code
25
+ attributes[:country_code]
26
+ end
27
+
28
+ #
29
+ # @return [String]
30
+ #
31
+ def ip
32
+ attributes[:ip]
33
+ end
34
+
35
+ #
36
+ # @return [Hash]
37
+ #
38
+ def metadata
39
+ attributes[:metadata]
40
+ end
41
+
16
42
  #
17
43
  # @return [Mihari::Artifact]
18
44
  #
19
- def to_artifact(source = "Onyphe")
45
+ def to_artifact
20
46
  Mihari::Artifact.new(
21
47
  data: ip,
22
- source: source,
23
48
  metadata: metadata,
24
49
  autonomous_system: to_as,
25
50
  geolocation: to_geolocation
@@ -45,15 +70,22 @@ module Mihari
45
70
  Mihari::AutonomousSystem.new(asn: normalize_asn(asn))
46
71
  end
47
72
 
48
- def self.from_dynamic!(d)
49
- d = Types::Hash[d]
50
- new(
51
- asn: d.fetch("asn"),
52
- ip: d.fetch("ip"),
53
- # Onyphe's country = 2-letter country code
54
- country_code: d["country"],
55
- metadata: d
56
- )
73
+ class << self
74
+ #
75
+ # @param [Hash] d
76
+ #
77
+ # @return [Result]
78
+ #
79
+ def from_dynamic!(d)
80
+ d = Types::Hash[d]
81
+ new(
82
+ asn: d.fetch("asn"),
83
+ ip: d.fetch("ip"),
84
+ # Onyphe's country = 2-letter country code
85
+ country_code: d["country"],
86
+ metadata: d
87
+ )
88
+ end
57
89
  end
58
90
  end
59
91
 
@@ -67,25 +99,79 @@ module Mihari
67
99
  attribute :total, Types::Int
68
100
 
69
101
  #
70
- # @param [String] source
102
+ # @return [Integer]
103
+ #
104
+ def count
105
+ attributes[:count]
106
+ end
107
+
108
+ #
109
+ # @return [Integer]
110
+ #
111
+ def error
112
+ attributes[:error]
113
+ end
114
+
115
+ #
116
+ # @return [Integer]
117
+ #
118
+ def max_page
119
+ attributes[:max_page]
120
+ end
121
+
122
+ #
123
+ # @return [Integer]
124
+ #
125
+ def page
126
+ attributes[:page]
127
+ end
128
+
129
+ #
130
+ # @return [Array<Result>]
131
+ #
132
+ def results
133
+ attributes[:results]
134
+ end
135
+
136
+ #
137
+ # @return [String]
138
+ #
139
+ def status
140
+ attributes[:status]
141
+ end
142
+
143
+ #
144
+ # @return [Integer]
145
+ #
146
+ def total
147
+ attributes[:total]
148
+ end
149
+
71
150
  #
72
151
  # @return [Array<Mihari::Artifact>]
73
152
  #
74
- def to_artifacts(source = "Onyphe")
75
- results.map { |result| result.to_artifact(source) }
153
+ def to_artifacts
154
+ results.map(&:to_artifact)
76
155
  end
77
156
 
78
- def self.from_dynamic!(d)
79
- d = Types::Hash[d]
80
- new(
81
- count: d.fetch("count"),
82
- error: d.fetch("error"),
83
- max_page: d.fetch("max_page"),
84
- page: d.fetch("page").to_i,
85
- results: d.fetch("results").map { |x| Result.from_dynamic!(x) },
86
- status: d.fetch("status"),
87
- total: d.fetch("total")
88
- )
157
+ class << self
158
+ #
159
+ # @param [Hash] d
160
+ #
161
+ # @return [Response]
162
+ #
163
+ def from_dynamic!(d)
164
+ d = Types::Hash[d]
165
+ new(
166
+ count: d.fetch("count"),
167
+ error: d.fetch("error"),
168
+ max_page: d.fetch("max_page"),
169
+ page: d.fetch("page").to_i,
170
+ results: d.fetch("results").map { |x| Result.from_dynamic!(x) },
171
+ status: d.fetch("status"),
172
+ total: d.fetch("total")
173
+ )
174
+ end
89
175
  end
90
176
  end
91
177
  end
@@ -10,6 +10,8 @@ require "yaml"
10
10
  module Mihari
11
11
  module Structs
12
12
  class Rule
13
+ include Mixins::FalsePositive
14
+
13
15
  # @return [Hash]
14
16
  attr_reader :data
15
17
 
@@ -109,10 +111,10 @@ module Mihari
109
111
  end
110
112
 
111
113
  #
112
- # @return [Array<String>]
114
+ # @return [Array<String, RegExp>]
113
115
  #
114
116
  def falsepositives
115
- @falsepositives ||= data[:falsepositives]
117
+ @falsepositives ||= data[:falsepositives].map { |fp| normalize_falsepositive fp }
116
118
  end
117
119
 
118
120
  #