mihari 3.9.2 → 3.10.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/greynoise.rb +65 -0
- data/lib/mihari/analyzers/rule.rb +1 -0
- data/lib/mihari/analyzers/shodan.rb +3 -1
- data/lib/mihari/cli/analyzer.rb +2 -0
- data/lib/mihari/commands/greynoise.rb +21 -0
- data/lib/mihari/schemas/configuration.rb +3 -2
- data/lib/mihari/structs/greynoise.rb +55 -0
- data/lib/mihari/structs/shodan.rb +2 -2
- data/lib/mihari/types.rb +1 -0
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/public/index.html +1 -1
- data/lib/mihari/web/public/static/js/app.0a0cc502.js +21 -0
- data/lib/mihari/web/public/static/js/app.0a0cc502.js.map +1 -0
- data/lib/mihari.rb +5 -2
- data/mihari.gemspec +1 -0
- data/sig/lib/mihari/structs/greynoise.rbs +30 -0
- data/sig/lib/mihari/structs/shodan.rbs +1 -1
- metadata +22 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c4d53239fe8be60cdc674dc22c14f801147a71144649cec83f4fd3caaf2c99fa
|
4
|
+
data.tar.gz: 71b9b3746164b1f3eec9b98a807a6940e85a9184991efd7dd9abe5bd9b3f3578
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6bee10443bd55e0ac483e8495c508bcce95dc56073aeb99f6c1566f38fb73707140baa838c07212c39795017d109aef8e9478f560bc3d04a21cbb949a48c9b61
|
7
|
+
data.tar.gz: c35f757168a737c37dcbf9a54d0408eabdfbf807a7a57db77c59c10f9a5b803d6731c615f3360db93b05647ee5e6cdcd35518baf4a7a7efe8d73e198d7f2664e
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "greynoise"
|
4
|
+
|
5
|
+
module Mihari
|
6
|
+
module Analyzers
|
7
|
+
class GreyNoise < Base
|
8
|
+
param :query
|
9
|
+
option :title, default: proc { "GreyNoise search" }
|
10
|
+
option :description, default: proc { "query = #{query}" }
|
11
|
+
option :tags, default: proc { [] }
|
12
|
+
|
13
|
+
def artifacts
|
14
|
+
res = Structs::GreyNoise::Response.from_dynamic!(search)
|
15
|
+
res.data.map do |datum|
|
16
|
+
build_artifact datum
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
PAGE_SIZE = 10_000
|
23
|
+
|
24
|
+
def configuration_keys
|
25
|
+
%w[greynoise_api_key]
|
26
|
+
end
|
27
|
+
|
28
|
+
def api
|
29
|
+
@api ||= ::GreyNoise::API.new(key: Mihari.config.greynoise_api_key)
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Search
|
34
|
+
#
|
35
|
+
# @return [Hash]
|
36
|
+
#
|
37
|
+
def search
|
38
|
+
api.experimental.gnql(query, size: PAGE_SIZE)
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Build an artifact from a GreyNoise search API response
|
43
|
+
#
|
44
|
+
# @param [Structs::GreyNoise::Datum] datum
|
45
|
+
#
|
46
|
+
# @return [Artifact]
|
47
|
+
#
|
48
|
+
def build_artifact(datum)
|
49
|
+
as = AutonomousSystem.new(asn: normalize_asn(datum.metadata.asn))
|
50
|
+
|
51
|
+
geolocation = Geolocation.new(
|
52
|
+
country: datum.metadata.country,
|
53
|
+
country_code: datum.metadata.country_code
|
54
|
+
)
|
55
|
+
|
56
|
+
Artifact.new(
|
57
|
+
data: datum.ip,
|
58
|
+
source: source,
|
59
|
+
autonomous_system: as,
|
60
|
+
geolocation: geolocation
|
61
|
+
)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -78,7 +78,9 @@ module Mihari
|
|
78
78
|
# @return [Artifact]
|
79
79
|
#
|
80
80
|
def build_artifact(match)
|
81
|
-
as =
|
81
|
+
as = nil
|
82
|
+
as = AutonomousSystem.new(asn: normalize_asn(match.asn)) unless match.asn.nil?
|
83
|
+
|
82
84
|
geolocation = Geolocation.new(
|
83
85
|
country: match.location.country_name,
|
84
86
|
country_code: match.location.country_code
|
data/lib/mihari/cli/analyzer.rb
CHANGED
@@ -6,6 +6,7 @@ require "mihari/commands/circl"
|
|
6
6
|
require "mihari/commands/crtsh"
|
7
7
|
require "mihari/commands/dnpedia"
|
8
8
|
require "mihari/commands/dnstwister"
|
9
|
+
require "mihari/commands/greynoise"
|
9
10
|
require "mihari/commands/onyphe"
|
10
11
|
require "mihari/commands/otx"
|
11
12
|
require "mihari/commands/passivetotal"
|
@@ -33,6 +34,7 @@ module Mihari
|
|
33
34
|
include Mihari::Commands::Crtsh
|
34
35
|
include Mihari::Commands::DNPedia
|
35
36
|
include Mihari::Commands::DNSTwister
|
37
|
+
include Mihari::Commands::GreyNoise
|
36
38
|
include Mihari::Commands::JSON
|
37
39
|
include Mihari::Commands::Onyphe
|
38
40
|
include Mihari::Commands::OTX
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module GreyNoise
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "greynoise [QUERY]", "GreyNoise search"
|
9
|
+
method_option :title, type: :string, desc: "title"
|
10
|
+
method_option :description, type: :string, desc: "description"
|
11
|
+
method_option :tags, type: :array, desc: "tags"
|
12
|
+
def greynoise(query)
|
13
|
+
with_error_handling do
|
14
|
+
run_analyzer Analyzers::GreyNoise, query: query, options: options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -13,6 +13,8 @@ module Mihari
|
|
13
13
|
optional(:censys_secret).value(:string)
|
14
14
|
optional(:circl_passive_password).value(:string)
|
15
15
|
optional(:circl_passive_username).value(:string)
|
16
|
+
optional(:database).value(:string)
|
17
|
+
optional(:greynoise_api_key).value(:string)
|
16
18
|
optional(:ipinfo_api_key).value(:string)
|
17
19
|
optional(:misp_api_endpoint).value(:string)
|
18
20
|
optional(:misp_api_key).value(:string)
|
@@ -30,10 +32,9 @@ module Mihari
|
|
30
32
|
optional(:thehive_api_key).value(:string)
|
31
33
|
optional(:urlscan_api_key).value(:string)
|
32
34
|
optional(:virustotal_api_key).value(:string)
|
33
|
-
optional(:zoomeye_api_key).value(:string)
|
34
35
|
optional(:webhook_url).value(:string)
|
35
36
|
optional(:webhook_use_json_body).value(:bool)
|
36
|
-
optional(:
|
37
|
+
optional(:zoomeye_api_key).value(:string)
|
37
38
|
end
|
38
39
|
|
39
40
|
class ConfigurationContract < Dry::Validation::Contract
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "json"
|
2
|
+
require "dry/struct"
|
3
|
+
|
4
|
+
module Mihari
|
5
|
+
module Structs
|
6
|
+
module GreyNoise
|
7
|
+
class Metadata < Dry::Struct
|
8
|
+
attribute :country, Types::String
|
9
|
+
attribute :country_code, Types::String
|
10
|
+
attribute :asn, Types::String
|
11
|
+
|
12
|
+
def self.from_dynamic!(d)
|
13
|
+
d = Types::Hash[d]
|
14
|
+
new(
|
15
|
+
country: d.fetch("country"),
|
16
|
+
country_code: d.fetch("country_code"),
|
17
|
+
asn: d.fetch("asn")
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Datum < Dry::Struct
|
23
|
+
attribute :ip, Types::String
|
24
|
+
attribute :metadata, Metadata
|
25
|
+
|
26
|
+
def self.from_dynamic!(d)
|
27
|
+
d = Types::Hash[d]
|
28
|
+
new(
|
29
|
+
ip: d.fetch("ip"),
|
30
|
+
metadata: Metadata.from_dynamic!(d.fetch("metadata"))
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Response < Dry::Struct
|
36
|
+
attribute :complete, Types::Bool
|
37
|
+
attribute :count, Types::Int
|
38
|
+
attribute :data, Types.Array(Datum)
|
39
|
+
attribute :message, Types::String
|
40
|
+
attribute :query, Types::String
|
41
|
+
|
42
|
+
def self.from_dynamic!(d)
|
43
|
+
d = Types::Hash[d]
|
44
|
+
new(
|
45
|
+
complete: d.fetch("complete"),
|
46
|
+
count: d.fetch("count"),
|
47
|
+
data: d.fetch("data").map { |x| Datum.from_dynamic!(x) },
|
48
|
+
message: d.fetch("message"),
|
49
|
+
query: d.fetch("query")
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -18,7 +18,7 @@ module Mihari
|
|
18
18
|
end
|
19
19
|
|
20
20
|
class Match < Dry::Struct
|
21
|
-
attribute :asn, Types::String
|
21
|
+
attribute :asn, Types::String.optional
|
22
22
|
attribute :hostnames, Types.Array(Types::String)
|
23
23
|
attribute :location, Location
|
24
24
|
attribute :domains, Types.Array(Types::String)
|
@@ -27,7 +27,7 @@ module Mihari
|
|
27
27
|
def self.from_dynamic!(d)
|
28
28
|
d = Types::Hash[d]
|
29
29
|
new(
|
30
|
-
asn: d
|
30
|
+
asn: d["asn"],
|
31
31
|
hostnames: d.fetch("hostnames"),
|
32
32
|
location: Location.from_dynamic!(d.fetch("location")),
|
33
33
|
domains: d.fetch("domains"),
|
data/lib/mihari/types.rb
CHANGED
data/lib/mihari/version.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/static/favicon.ico"><title>Mihari</title><link href="/static/js/app.
|
1
|
+
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/static/favicon.ico"><title>Mihari</title><link href="/static/js/app.0a0cc502.js" rel="preload" as="script"></head><body><noscript><strong>We're sorry but Mihari doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="/static/js/app.0a0cc502.js"></script></body></html>
|