mihari 3.8.1 → 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/.github/workflows/test.yml +6 -7
- data/config.ru +1 -1
- 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/commands/search.rb +3 -2
- data/lib/mihari/commands/web.rb +9 -5
- data/lib/mihari/database.rb +1 -1
- data/lib/mihari/errors.rb +2 -0
- data/lib/mihari/mixins/configuration.rb +12 -2
- data/lib/mihari/models/alert.rb +29 -54
- data/lib/mihari/models/artifact.rb +3 -0
- data/lib/mihari/schemas/configuration.rb +3 -2
- data/lib/mihari/structs/alert.rb +45 -0
- data/lib/mihari/structs/greynoise.rb +55 -0
- data/lib/mihari/structs/ipinfo.rb +3 -4
- data/lib/mihari/structs/shodan.rb +2 -2
- data/lib/mihari/types.rb +2 -0
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/api.rb +43 -0
- data/lib/mihari/web/app.rb +48 -30
- data/lib/mihari/web/endpoints/alerts.rb +74 -0
- data/lib/mihari/web/endpoints/artifacts.rb +92 -0
- data/lib/mihari/web/endpoints/command.rb +32 -0
- data/lib/mihari/web/endpoints/configs.rb +22 -0
- data/lib/mihari/web/endpoints/ip_addresses.rb +27 -0
- data/lib/mihari/web/endpoints/sources.rb +18 -0
- data/lib/mihari/web/endpoints/tags.rb +38 -0
- data/lib/mihari/web/entities/alert.rb +23 -0
- data/lib/mihari/web/entities/artifact.rb +24 -0
- data/lib/mihari/web/entities/autonomous_system.rb +9 -0
- data/lib/mihari/web/entities/command.rb +14 -0
- data/lib/mihari/web/entities/config.rb +16 -0
- data/lib/mihari/web/entities/dns.rb +10 -0
- data/lib/mihari/web/entities/geolocation.rb +10 -0
- data/lib/mihari/web/entities/ip_address.rb +13 -0
- data/lib/mihari/web/entities/message.rb +9 -0
- data/lib/mihari/web/entities/reverse_dns.rb +9 -0
- data/lib/mihari/web/entities/source.rb +9 -0
- data/lib/mihari/web/entities/tag.rb +13 -0
- data/lib/mihari/web/entities/whois.rb +16 -0
- data/lib/mihari/web/public/grape.rb +73 -0
- data/lib/mihari/web/public/index.html +1 -1
- data/lib/mihari/web/public/redoc-static.html +53 -27
- 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/web/public/static/js/app.14008741.js +21 -0
- data/lib/mihari/web/public/static/js/app.14008741.js.map +1 -0
- data/lib/mihari/web/public/static/js/app.378da3dc.js +50 -0
- data/lib/mihari/web/public/static/js/app.378da3dc.js.map +1 -0
- data/lib/mihari/web/public/static/js/app.6b636b62.js +50 -0
- data/lib/mihari/web/public/static/js/app.6b636b62.js.map +1 -0
- data/lib/mihari.rb +8 -14
- data/mihari.gemspec +10 -6
- data/sig/lib/mihari/analyzers/rule.rbs +1 -1
- data/sig/lib/mihari/models/alert.rbs +3 -31
- data/sig/lib/mihari/structs/alert.rbs +27 -0
- data/sig/lib/mihari/structs/greynoise.rbs +30 -0
- data/sig/lib/mihari/structs/shodan.rbs +1 -1
- data/sig/lib/mihari/web/app.rbs +2 -2
- metadata +150 -76
- data/lib/mihari/serializers/alert.rb +0 -14
- data/lib/mihari/serializers/artifact.rb +0 -18
- data/lib/mihari/serializers/autonomous_system.rb +0 -9
- data/lib/mihari/serializers/dns.rb +0 -11
- data/lib/mihari/serializers/geolocation.rb +0 -11
- data/lib/mihari/serializers/reverse_dns.rb +0 -11
- data/lib/mihari/serializers/tag.rb +0 -11
- data/lib/mihari/serializers/whois.rb +0 -11
- data/lib/mihari/web/controllers/alerts_controller.rb +0 -74
- data/lib/mihari/web/controllers/analyzers_controller.rb +0 -38
- data/lib/mihari/web/controllers/artifacts_controller.rb +0 -94
- data/lib/mihari/web/controllers/base_controller.rb +0 -22
- data/lib/mihari/web/controllers/command_controller.rb +0 -26
- data/lib/mihari/web/controllers/config_controller.rb +0 -13
- data/lib/mihari/web/controllers/ip_address_controller.rb +0 -21
- data/lib/mihari/web/controllers/sources_controller.rb +0 -12
- data/lib/mihari/web/controllers/tags_controller.rb +0 -30
- data/lib/mihari/web/helpers/json.rb +0 -53
@@ -1,11 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "active_model_serializers"
|
4
|
-
|
5
|
-
module Mihari
|
6
|
-
module Serializers
|
7
|
-
class WhoisRecordSerializer < ActiveModel::Serializer
|
8
|
-
attributes :domain, :created_on, :updated_on, :expires_on, :registrar, :contacts
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mihari
|
4
|
-
module Controllers
|
5
|
-
class AlertsController < BaseController
|
6
|
-
get "/api/alerts" do
|
7
|
-
param :page, Integer
|
8
|
-
param :artifact, String
|
9
|
-
param :description, String
|
10
|
-
param :source, String
|
11
|
-
param :tag, String
|
12
|
-
|
13
|
-
param :from_at, DateTime
|
14
|
-
param :fromAt, DateTime
|
15
|
-
param :to_at, DateTime
|
16
|
-
param :toAt, DateTime
|
17
|
-
|
18
|
-
page = params["page"] || 1
|
19
|
-
page = page.to_i
|
20
|
-
limit = 10
|
21
|
-
|
22
|
-
artifact_data = params["artifact"]
|
23
|
-
description = params["description"]
|
24
|
-
source = params["source"]
|
25
|
-
tag_name = params["tag"]
|
26
|
-
title = params["title"]
|
27
|
-
|
28
|
-
from_at = params["from_at"] || params["fromAt"]
|
29
|
-
to_at = params["to_at"] || params["toAt"]
|
30
|
-
|
31
|
-
alerts = Mihari::Alert.search(
|
32
|
-
artifact_data: artifact_data,
|
33
|
-
description: description,
|
34
|
-
from_at: from_at,
|
35
|
-
limit: limit,
|
36
|
-
page: page,
|
37
|
-
source: source,
|
38
|
-
tag_name: tag_name,
|
39
|
-
title: title,
|
40
|
-
to_at: to_at
|
41
|
-
)
|
42
|
-
total = Mihari::Alert.count(
|
43
|
-
artifact_data: artifact_data,
|
44
|
-
description: description,
|
45
|
-
from_at: from_at,
|
46
|
-
source: source,
|
47
|
-
tag_name: tag_name,
|
48
|
-
title: title,
|
49
|
-
to_at: to_at
|
50
|
-
)
|
51
|
-
|
52
|
-
json({ alerts: alerts, total: total, current_page: page, page_size: limit })
|
53
|
-
end
|
54
|
-
|
55
|
-
delete "/api/alerts/:id" do
|
56
|
-
param :id, Integer, required: true
|
57
|
-
|
58
|
-
id = params["id"].to_i
|
59
|
-
|
60
|
-
begin
|
61
|
-
alert = Mihari::Alert.find(id)
|
62
|
-
alert.destroy
|
63
|
-
|
64
|
-
status 204
|
65
|
-
body ""
|
66
|
-
rescue ActiveRecord::RecordNotFound
|
67
|
-
status 404
|
68
|
-
|
69
|
-
json({ message: "ID:#{id} is not found" })
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mihari
|
4
|
-
module Controllers
|
5
|
-
class AnalyzersController < BaseController
|
6
|
-
post "/api/analyzer" do
|
7
|
-
contract = Mihari::Schemas::AnalyzerRunContract.new
|
8
|
-
result = contract.call(params)
|
9
|
-
|
10
|
-
unless result.errors.empty?
|
11
|
-
status 400
|
12
|
-
|
13
|
-
return json(result.errors.to_h)
|
14
|
-
end
|
15
|
-
|
16
|
-
args = result.to_h
|
17
|
-
|
18
|
-
ignore_old_artifacts = args[:ignoreOldArtifacts]
|
19
|
-
ignore_threshold = args[:ignoreThreshold]
|
20
|
-
|
21
|
-
analyzer = Mihari::Analyzers::Basic.new(
|
22
|
-
title: args[:title],
|
23
|
-
description: args[:description],
|
24
|
-
source: args[:source],
|
25
|
-
artifacts: args[:artifacts],
|
26
|
-
tags: args[:tags]
|
27
|
-
)
|
28
|
-
analyzer.ignore_old_artifacts = ignore_old_artifacts
|
29
|
-
analyzer.ignore_threshold = ignore_threshold
|
30
|
-
|
31
|
-
analyzer.run
|
32
|
-
|
33
|
-
status 201
|
34
|
-
body ""
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
@@ -1,94 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mihari
|
4
|
-
module Controllers
|
5
|
-
class ArtifactsController < BaseController
|
6
|
-
get "/api/artifacts/:id" do
|
7
|
-
param :id, Integer, required: true
|
8
|
-
|
9
|
-
id = params["id"].to_i
|
10
|
-
|
11
|
-
begin
|
12
|
-
artifact = Mihari::Artifact.includes(
|
13
|
-
:autonomous_system,
|
14
|
-
:geolocation,
|
15
|
-
:whois_record,
|
16
|
-
:dns_records,
|
17
|
-
:reverse_dns_names
|
18
|
-
).find(id)
|
19
|
-
rescue ActiveRecord::RecordNotFound
|
20
|
-
status 404
|
21
|
-
|
22
|
-
return json({ message: "ID:#{id} is not found" })
|
23
|
-
end
|
24
|
-
|
25
|
-
# TODO: improve queries
|
26
|
-
alert_ids = Mihari::Artifact.where(data: artifact.data).pluck(:alert_id)
|
27
|
-
tag_ids = Mihari::Tagging.where(alert_id: alert_ids).pluck(:tag_id)
|
28
|
-
tag_names = Mihari::Tag.where(id: tag_ids).distinct.pluck(:name)
|
29
|
-
|
30
|
-
artifact_json = Serializers::ArtifactSerializer.new(artifact).as_json
|
31
|
-
|
32
|
-
# convert reverse DNS names into an array of string
|
33
|
-
# also change it as nil if it is empty
|
34
|
-
reverse_dns_names = (artifact_json[:reverse_dns_names] || []).filter_map { |v| v[:name] }
|
35
|
-
reverse_dns_names = nil if reverse_dns_names.empty?
|
36
|
-
artifact_json[:reverse_dns_names] = reverse_dns_names
|
37
|
-
|
38
|
-
# change DNS records as nil if it is empty
|
39
|
-
dns_records = artifact_json[:dns_records] || []
|
40
|
-
dns_records = nil if dns_records.empty?
|
41
|
-
artifact_json[:dns_records] = dns_records
|
42
|
-
|
43
|
-
# set tags
|
44
|
-
artifact_json[:tags] = tag_names
|
45
|
-
|
46
|
-
json artifact_json
|
47
|
-
end
|
48
|
-
|
49
|
-
get "/api/artifacts/:id/enrich" do
|
50
|
-
param :id, Integer, required: true
|
51
|
-
|
52
|
-
id = params["id"].to_i
|
53
|
-
|
54
|
-
begin
|
55
|
-
artifact = Mihari::Artifact.includes(
|
56
|
-
:autonomous_system,
|
57
|
-
:geolocation,
|
58
|
-
:whois_record,
|
59
|
-
:dns_records,
|
60
|
-
:reverse_dns_names
|
61
|
-
).find(id)
|
62
|
-
rescue ActiveRecord::RecordNotFound
|
63
|
-
status 404
|
64
|
-
|
65
|
-
return json({ message: "ID:#{id} is not found" })
|
66
|
-
end
|
67
|
-
|
68
|
-
artifact.enrich_all
|
69
|
-
artifact.save
|
70
|
-
|
71
|
-
status 201
|
72
|
-
body ""
|
73
|
-
end
|
74
|
-
|
75
|
-
delete "/api/artifacts/:id" do
|
76
|
-
param :id, Integer, required: true
|
77
|
-
|
78
|
-
id = params["id"].to_i
|
79
|
-
|
80
|
-
begin
|
81
|
-
alert = Mihari::Artifact.find(id)
|
82
|
-
alert.destroy
|
83
|
-
|
84
|
-
status 204
|
85
|
-
body ""
|
86
|
-
rescue ActiveRecord::RecordNotFound
|
87
|
-
status 404
|
88
|
-
|
89
|
-
json({ message: "ID:#{id} is not found" })
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "rack/contrib/json_body_parser"
|
4
|
-
require "sinatra"
|
5
|
-
require "sinatra/param"
|
6
|
-
|
7
|
-
module Mihari
|
8
|
-
module Controllers
|
9
|
-
class BaseController < Sinatra::Base
|
10
|
-
helpers Sinatra::Param
|
11
|
-
|
12
|
-
use Rack::JSONBodyParser
|
13
|
-
|
14
|
-
set :show_exceptions, false
|
15
|
-
set :raise_sinatra_param_exceptions, true
|
16
|
-
|
17
|
-
error Sinatra::Param::InvalidParameterError do
|
18
|
-
json({ error: "#{env["sinatra.error"].param} is invalid" })
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "safe_shell"
|
4
|
-
|
5
|
-
module Mihari
|
6
|
-
module Controllers
|
7
|
-
class CommandController < BaseController
|
8
|
-
post "/api/command" do
|
9
|
-
param :command, String, required: true
|
10
|
-
|
11
|
-
command = params["command"]
|
12
|
-
if command.nil?
|
13
|
-
status 400
|
14
|
-
return json({ message: "command is required" })
|
15
|
-
end
|
16
|
-
|
17
|
-
command = command.split
|
18
|
-
|
19
|
-
output = SafeShell.execute("mihari", *command)
|
20
|
-
success = $?.success?
|
21
|
-
|
22
|
-
json({ output: output, success: success })
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mihari
|
4
|
-
module Controllers
|
5
|
-
class IPAddressController < BaseController
|
6
|
-
get "/api/ip_addresses/:ip" do
|
7
|
-
param :ip, String, required: true
|
8
|
-
|
9
|
-
ip = params["ip"].to_s
|
10
|
-
|
11
|
-
data = Enrichers::IPInfo.query(ip)
|
12
|
-
if data.nil?
|
13
|
-
status 404
|
14
|
-
json({ message: "IP:#{ip} is not found" })
|
15
|
-
else
|
16
|
-
json data.to_hash
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mihari
|
4
|
-
module Controllers
|
5
|
-
class TagsController < BaseController
|
6
|
-
get "/api/tags" do
|
7
|
-
tags = Mihari::Tag.distinct.pluck(:name)
|
8
|
-
json tags
|
9
|
-
end
|
10
|
-
|
11
|
-
delete "/api/tags/:name" do
|
12
|
-
param :name, String, required: true
|
13
|
-
|
14
|
-
name = params["name"].to_s
|
15
|
-
|
16
|
-
begin
|
17
|
-
Mihari::Tag.where(name: name).destroy_all
|
18
|
-
|
19
|
-
status 204
|
20
|
-
body ""
|
21
|
-
rescue ActiveRecord::RecordNotFound
|
22
|
-
status 404
|
23
|
-
|
24
|
-
message = { message: "Name:#{name} is not found" }
|
25
|
-
json message
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "awrence"
|
4
|
-
require "multi_json"
|
5
|
-
require "sinatra/base"
|
6
|
-
|
7
|
-
module Sinatra
|
8
|
-
module JSON
|
9
|
-
class << self
|
10
|
-
def encode(object)
|
11
|
-
::MultiJson.dump(object)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def json(object, options = {})
|
16
|
-
object = object.to_camelback_keys
|
17
|
-
|
18
|
-
content_type resolve_content_type(options)
|
19
|
-
resolve_encoder_action object, resolve_encoder(options)
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def resolve_content_type(options = {})
|
25
|
-
options[:content_type] || settings.json_content_type
|
26
|
-
end
|
27
|
-
|
28
|
-
def resolve_encoder(options = {})
|
29
|
-
options[:json_encoder] || settings.json_encoder
|
30
|
-
end
|
31
|
-
|
32
|
-
def resolve_encoder_action(object, encoder)
|
33
|
-
[:encode, :generate].each do |method|
|
34
|
-
return encoder.send(method, object) if encoder.respond_to? method
|
35
|
-
end
|
36
|
-
|
37
|
-
if encoder.is_a? Symbol
|
38
|
-
object.__send__(encoder)
|
39
|
-
else
|
40
|
-
fail "#{encoder} does not respond to #generate nor #encode"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
Base.set :json_encoder do
|
46
|
-
::MultiJson
|
47
|
-
end
|
48
|
-
|
49
|
-
Base.set :json_content_type, :json
|
50
|
-
|
51
|
-
# Load the JSON helpers in modular style automatically
|
52
|
-
Base.helpers JSON
|
53
|
-
end
|