mihari 2.0.0 → 2.1.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/ISSUE_TEMPLATE/bug_report.md +43 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +15 -0
- data/.standard.yml +4 -0
- data/README.md +3 -1
- data/docker/Dockerfile +2 -1
- data/images/web_alerts.png +0 -0
- data/lib/mihari/analyzers/base.rb +1 -1
- data/lib/mihari/analyzers/securitytrails.rb +2 -2
- data/lib/mihari/cli.rb +61 -287
- data/lib/mihari/commands/binaryedge.rb +21 -0
- data/lib/mihari/commands/censys.rb +22 -0
- data/lib/mihari/commands/circl.rb +21 -0
- data/lib/mihari/commands/config.rb +21 -0
- data/lib/mihari/commands/crtsh.rb +22 -0
- data/lib/mihari/commands/dnpedia.rb +21 -0
- data/lib/mihari/commands/dnstwister.rb +19 -0
- data/lib/mihari/commands/free_text.rb +21 -0
- data/lib/mihari/commands/http_hash.rb +25 -0
- data/lib/mihari/commands/json.rb +36 -0
- data/lib/mihari/commands/onyphe.rb +19 -0
- data/lib/mihari/commands/otx.rb +21 -0
- data/lib/mihari/commands/passive_dns.rb +19 -0
- data/lib/mihari/commands/passive_ssl.rb +21 -0
- data/lib/mihari/commands/passivetotal.rb +21 -0
- data/lib/mihari/commands/pulsedive.rb +21 -0
- data/lib/mihari/commands/reverse_whois.rb +21 -0
- data/lib/mihari/commands/securitytrails.rb +20 -0
- data/lib/mihari/commands/securitytrails_domain_feed.rb +23 -0
- data/lib/mihari/commands/shodan.rb +19 -0
- data/lib/mihari/commands/spyse.rb +20 -0
- data/lib/mihari/commands/ssh_fingerprint.rb +21 -0
- data/lib/mihari/commands/urlscan.rb +23 -0
- data/lib/mihari/commands/virustotal.rb +19 -0
- data/lib/mihari/commands/web.rb +20 -0
- data/lib/mihari/commands/zoomeye.rb +20 -0
- data/lib/mihari/config.rb +12 -0
- data/lib/mihari/configurable.rb +1 -1
- data/lib/mihari/emitters/slack.rb +4 -4
- data/lib/mihari/emitters/the_hive.rb +1 -1
- data/lib/mihari/models/alert.rb +5 -5
- data/lib/mihari/notifiers/exception_notifier.rb +4 -4
- data/lib/mihari/status.rb +1 -1
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/app.rb +45 -5
- data/lib/mihari/web/public/index.html +2 -2
- data/lib/mihari/web/public/static/js/{app.58b32d15.js → app.280cbdb7.js} +4 -4
- data/lib/mihari/web/public/static/js/app.280cbdb7.js.map +1 -0
- data/mihari.gemspec +2 -0
- metadata +61 -4
- data/lib/mihari/web/public/static/js/app.58b32d15.js.map +0 -1
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module BinaryEdge
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "binaryedge [QUERY]", "BinaryEdge host search by a query"
|
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 binaryedge(query)
|
13
|
+
with_error_handling do
|
14
|
+
run_analyzer Analyzers::BinaryEdge, query: query, options: options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module Censys
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "censys [QUERY]", "Censys IPv4 search by a query"
|
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
|
+
method_option :type, type: :string, desc: "type to search (ipv4 / websites / certificates)", default: "ipv4"
|
13
|
+
def censys(query)
|
14
|
+
with_error_handling do
|
15
|
+
run_analyzer Analyzers::Censys, query: query, options: options
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module CIRCL
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "circl [DOMAIN|SHA1]", "CIRCL passive DNS/SSL lookup by a domain or SHA1 certificate fingerprint"
|
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 circl(query)
|
13
|
+
with_error_handling do
|
14
|
+
run_analyzer Analyzers::CIRCL, query: refang(query), options: options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Mihari
|
2
|
+
module Commands
|
3
|
+
module Config
|
4
|
+
def self.included(thor)
|
5
|
+
thor.class_eval do
|
6
|
+
desc "init_config", "Create a config file"
|
7
|
+
method_option :filename, type: :string, default: "mihari.yml"
|
8
|
+
def init_config
|
9
|
+
filename = options["filename"]
|
10
|
+
|
11
|
+
if File.exist?(filename) && !(yes? "#{filename} exists. Do you want to overwrite it? (y/n)")
|
12
|
+
return
|
13
|
+
end
|
14
|
+
|
15
|
+
Mihari::Config.initialize_yaml filename
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module Crtsh
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "crtsh [QUERY]", "crt.sh search by a query"
|
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
|
+
method_option :exclude_expired, type: :boolean, desc: "exclude expired certificates"
|
13
|
+
def crtsh(query)
|
14
|
+
with_error_handling do
|
15
|
+
run_analyzer Analyzers::Crtsh, query: query, options: options
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module DNPedia
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "dnpedia [QUERY]", "DNPedia domain search by a query"
|
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 dnpedia(query)
|
13
|
+
with_error_handling do
|
14
|
+
run_analyzer Analyzers::DNPedia, query: query, options: options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Mihari
|
2
|
+
module Commands
|
3
|
+
module DNSTwister
|
4
|
+
def self.included(thor)
|
5
|
+
thor.class_eval do
|
6
|
+
desc "dnstwister [DOMAIN]", "dnstwister lookup by a domain"
|
7
|
+
method_option :title, type: :string, desc: "title"
|
8
|
+
method_option :description, type: :string, desc: "description"
|
9
|
+
method_option :tags, type: :array, desc: "tags"
|
10
|
+
def dnstwister(domain)
|
11
|
+
with_error_handling do
|
12
|
+
run_analyzer Analyzers::DNSTwister, query: refang(domain), options: options
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module FreeText
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "free_text [TEXT]", "Cross search with search engines by a free text"
|
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 free_text(text)
|
13
|
+
with_error_handling do
|
14
|
+
run_analyzer Analyzers::FreeText, query: text, options: options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module HTTPHash
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "http_hash", "Cross search with search engines by a hash of an HTTP response (SHA256, MD5 and MurmurHash3)"
|
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
|
+
method_option :md5, type: :string, desc: "MD5 hash"
|
13
|
+
method_option :sha256, type: :string, desc: "SHA256 hash"
|
14
|
+
method_option :mmh3, type: :numeric, desc: "MurmurHash3 hash"
|
15
|
+
method_option :html, type: :string, desc: "path to an HTML file"
|
16
|
+
def http_hash
|
17
|
+
with_error_handling do
|
18
|
+
run_analyzer Analyzers::HTTPHash, query: nil, options: options
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Mihari
|
2
|
+
module Commands
|
3
|
+
module JSON
|
4
|
+
def self.included(thor)
|
5
|
+
thor.class_eval do
|
6
|
+
desc "import_from_json", "Give a JSON input via STDIN"
|
7
|
+
def import_from_json(input = nil)
|
8
|
+
with_error_handling do
|
9
|
+
json = input || $stdin.gets.chomp
|
10
|
+
raise ArgumentError, "Input not found: please give an input in a JSON format" unless json
|
11
|
+
|
12
|
+
json = parse_as_json(json)
|
13
|
+
raise ArgumentError, "Invalid input format: an input JSON data should have title, description and artifacts key" unless valid_json?(json)
|
14
|
+
|
15
|
+
title = json["title"]
|
16
|
+
description = json["description"]
|
17
|
+
artifacts = json["artifacts"]
|
18
|
+
tags = json["tags"] || []
|
19
|
+
|
20
|
+
basic = Analyzers::Basic.new(title: title, description: description, artifacts: artifacts, source: "json", tags: tags)
|
21
|
+
basic.run
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
no_commands do
|
26
|
+
def parse_as_json(input)
|
27
|
+
::JSON.parse input
|
28
|
+
rescue ::JSON::ParserError => _e
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Mihari
|
2
|
+
module Commands
|
3
|
+
module Onyphe
|
4
|
+
def self.included(thor)
|
5
|
+
thor.class_eval do
|
6
|
+
desc "onyphe [QUERY]", "Onyphe datascan search by a query"
|
7
|
+
method_option :title, type: :string, desc: "title"
|
8
|
+
method_option :description, type: :string, desc: "description"
|
9
|
+
method_option :tags, type: :array, desc: "tags"
|
10
|
+
def onyphe(query)
|
11
|
+
with_error_handling do
|
12
|
+
run_analyzer Analyzers::Onyphe, query: query, options: options
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module OTX
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "otx [IP|DOMAIN]", "OTX lookup by an IP or domain"
|
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 otx(domain)
|
13
|
+
with_error_handling do
|
14
|
+
run_analyzer Analyzers::OTX, query: refang(domain), options: options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Mihari
|
2
|
+
module Commands
|
3
|
+
module PassiveDNS
|
4
|
+
def self.included(thor)
|
5
|
+
thor.class_eval do
|
6
|
+
desc "passive_dns [IP|DOMAIN]", "Cross search with passive DNS services by an ip or domain"
|
7
|
+
method_option :title, type: :string, desc: "title"
|
8
|
+
method_option :description, type: :string, desc: "description"
|
9
|
+
method_option :tags, type: :array, desc: "tags"
|
10
|
+
def passive_dns(query)
|
11
|
+
with_error_handling do
|
12
|
+
run_analyzer Analyzers::PassiveDNS, query: refang(query), options: options
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module PassiveSSL
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "passive_ssl [SHA1]", "Cross search with passive SSL services by an SHA1 certificate fingerprint"
|
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 passive_ssl(query)
|
13
|
+
with_error_handling do
|
14
|
+
run_analyzer Analyzers::PassiveSSL, query: query, options: options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module PassiveTotal
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "passivetotal [IP|DOMAIN|EMAIL|SHA1]", "PassiveTotal lookup by an ip, domain, email or SHA1 certificate fingerprint"
|
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 passivetotal(indicator)
|
13
|
+
with_error_handling do
|
14
|
+
run_analyzer Analyzers::PassiveTotal, query: refang(indicator), options: options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module Pulsedive
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "pulsedive [IP|DOMAIN]", "Pulsedive lookup by an ip or domain"
|
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 pulsedive(indiactor)
|
13
|
+
with_error_handling do
|
14
|
+
run_analyzer Analyzers::Pulsedive, query: refang(indiactor), options: options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module ReverseWhois
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "reverse_whois [EMAIL]", "Cross search with reverse whois services by an email"
|
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 reverse_whois(query)
|
13
|
+
with_error_handling do
|
14
|
+
run_analyzer Analyzers::ReveseWhois, query: refang(query), options: options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Mihari
|
2
|
+
module Commands
|
3
|
+
module SecurityTrails
|
4
|
+
def self.included(thor)
|
5
|
+
thor.class_eval do
|
6
|
+
desc "securitytrails [IP|DOMAIN|EMAIL]", "SecurityTrails lookup by an ip, domain or email"
|
7
|
+
method_option :title, type: :string, desc: "title"
|
8
|
+
method_option :description, type: :string, desc: "description"
|
9
|
+
method_option :tags, type: :array, desc: "tags"
|
10
|
+
def securitytrails(indiactor)
|
11
|
+
with_error_handling do
|
12
|
+
run_analyzer Analyzers::SecurityTrails, query: refang(indiactor), options: options
|
13
|
+
end
|
14
|
+
end
|
15
|
+
map "st" => :securitytrails
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module SecurityTrailsDomainFeed
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "securitytrails_domain_feed [REGEXP]", "SecurityTrails new domain feed search by a regexp"
|
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
|
+
method_option :type, type: :string, default: "registered", desc: "A type of domain feed ('all', 'new' or 'registered')"
|
13
|
+
def securitytrails_domain_feed(regexp)
|
14
|
+
with_error_handling do
|
15
|
+
run_analyzer Analyzers::SecurityTrailsDomainFeed, query: regexp, options: options
|
16
|
+
end
|
17
|
+
end
|
18
|
+
map "st_domain_feed" => :securitytrails_domain_feedd
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|