mihari 2.0.0 → 2.3.1

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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +43 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +15 -0
  4. data/.rubocop.yml +6 -0
  5. data/.standard.yml +4 -0
  6. data/README.md +11 -1
  7. data/bin/console +1 -0
  8. data/docker/Dockerfile +3 -2
  9. data/examples/ipinfo_hosted_domains.rb +1 -1
  10. data/images/{eyecatch.png → overview.png} +0 -0
  11. data/images/tines.png +0 -0
  12. data/images/web_alerts.png +0 -0
  13. data/images/web_config.png +0 -0
  14. data/lib/mihari/analyzers/base.rb +11 -2
  15. data/lib/mihari/analyzers/circl.rb +3 -3
  16. data/lib/mihari/analyzers/onyphe.rb +2 -2
  17. data/lib/mihari/analyzers/securitytrails.rb +2 -2
  18. data/lib/mihari/analyzers/urlscan.rb +1 -6
  19. data/lib/mihari/analyzers/zoomeye.rb +2 -2
  20. data/lib/mihari/cli.rb +72 -289
  21. data/lib/mihari/commands/binaryedge.rb +21 -0
  22. data/lib/mihari/commands/censys.rb +22 -0
  23. data/lib/mihari/commands/circl.rb +21 -0
  24. data/lib/mihari/commands/config.rb +27 -0
  25. data/lib/mihari/commands/crtsh.rb +22 -0
  26. data/lib/mihari/commands/dnpedia.rb +21 -0
  27. data/lib/mihari/commands/dnstwister.rb +21 -0
  28. data/lib/mihari/commands/free_text.rb +21 -0
  29. data/lib/mihari/commands/http_hash.rb +25 -0
  30. data/lib/mihari/commands/json.rb +42 -0
  31. data/lib/mihari/commands/onyphe.rb +21 -0
  32. data/lib/mihari/commands/otx.rb +21 -0
  33. data/lib/mihari/commands/passive_dns.rb +21 -0
  34. data/lib/mihari/commands/passive_ssl.rb +21 -0
  35. data/lib/mihari/commands/passivetotal.rb +21 -0
  36. data/lib/mihari/commands/pulsedive.rb +21 -0
  37. data/lib/mihari/commands/reverse_whois.rb +21 -0
  38. data/lib/mihari/commands/securitytrails.rb +22 -0
  39. data/lib/mihari/commands/securitytrails_domain_feed.rb +23 -0
  40. data/lib/mihari/commands/shodan.rb +21 -0
  41. data/lib/mihari/commands/spyse.rb +22 -0
  42. data/lib/mihari/commands/ssh_fingerprint.rb +21 -0
  43. data/lib/mihari/commands/urlscan.rb +23 -0
  44. data/lib/mihari/commands/virustotal.rb +21 -0
  45. data/lib/mihari/commands/web.rb +22 -0
  46. data/lib/mihari/commands/zoomeye.rb +22 -0
  47. data/lib/mihari/config.rb +14 -3
  48. data/lib/mihari/configurable.rb +1 -1
  49. data/lib/mihari/emitters/slack.rb +4 -4
  50. data/lib/mihari/emitters/the_hive.rb +1 -1
  51. data/lib/mihari/models/alert.rb +5 -5
  52. data/lib/mihari/models/artifact.rb +13 -2
  53. data/lib/mihari/notifiers/exception_notifier.rb +4 -4
  54. data/lib/mihari/status.rb +2 -10
  55. data/lib/mihari/version.rb +1 -1
  56. data/lib/mihari/web/app.rb +25 -100
  57. data/lib/mihari/web/controllers/alerts_controller.rb +75 -0
  58. data/lib/mihari/web/controllers/artifacts_controller.rb +24 -0
  59. data/lib/mihari/web/controllers/base_controller.rb +22 -0
  60. data/lib/mihari/web/controllers/command_controller.rb +26 -0
  61. data/lib/mihari/web/controllers/config_controller.rb +13 -0
  62. data/lib/mihari/web/controllers/sources_controller.rb +12 -0
  63. data/lib/mihari/web/controllers/tags_controller.rb +28 -0
  64. data/lib/mihari/web/helpers/json.rb +53 -0
  65. data/lib/mihari/web/public/index.html +2 -2
  66. data/lib/mihari/web/public/redoc-static.html +519 -0
  67. data/lib/mihari/web/public/static/js/{app.58b32d15.js → app.cccddb2b.js} +4 -4
  68. data/lib/mihari/web/public/static/js/app.cccddb2b.js.map +1 -0
  69. data/mihari.gemspec +9 -3
  70. metadata +146 -23
  71. 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,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "colorize"
4
+
5
+ module Mihari
6
+ module Commands
7
+ module Config
8
+ def self.included(thor)
9
+ thor.class_eval do
10
+ desc "init_config", "Create a config file"
11
+ method_option :filename, type: :string, default: "mihari.yml"
12
+ def init_config
13
+ filename = options["filename"]
14
+
15
+ warning = "#{filename} exists. Do you want to overwrite it? (y/n)"
16
+ if File.exist?(filename) && !(yes? warning)
17
+ return
18
+ end
19
+
20
+ Mihari::Config.initialize_yaml filename
21
+ puts "The config file is initialized as #{filename}.".colorize(:blue)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ 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,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Commands
5
+ module DNSTwister
6
+ def self.included(thor)
7
+ thor.class_eval do
8
+ desc "dnstwister [DOMAIN]", "dnstwister lookup by a 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 dnstwister(domain)
13
+ with_error_handling do
14
+ run_analyzer Analyzers::DNSTwister, query: refang(domain), 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 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,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Commands
5
+ module JSON
6
+ def self.included(thor)
7
+ thor.class_eval do
8
+ desc "import_from_json", "Give a JSON input via STDIN"
9
+ def import_from_json(input = nil)
10
+ with_error_handling do
11
+ json = input || $stdin.gets.chomp
12
+ raise ArgumentError, "Input not found: please give an input in a JSON format" unless json
13
+
14
+ json = parse_as_json(json)
15
+ raise ArgumentError, "Invalid input format: an input JSON data should have title, description and artifacts key" unless valid_json?(json)
16
+
17
+ title = json["title"]
18
+ description = json["description"]
19
+ artifacts = json["artifacts"]
20
+ tags = json["tags"] || []
21
+
22
+ basic = Analyzers::Basic.new(title: title, description: description, artifacts: artifacts, source: "json", tags: tags)
23
+
24
+ basic.ignore_old_artifacts = options["ignore_old_artifacts"] || false
25
+ basic.ignore_threshold = options["ignore_threshold"] || 0
26
+
27
+ basic.run
28
+ end
29
+ end
30
+
31
+ no_commands do
32
+ def parse_as_json(input)
33
+ ::JSON.parse input
34
+ rescue ::JSON::ParserError => _e
35
+ nil
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Commands
5
+ module Onyphe
6
+ def self.included(thor)
7
+ thor.class_eval do
8
+ desc "onyphe [QUERY]", "Onyphe datascan 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 onyphe(query)
13
+ with_error_handling do
14
+ run_analyzer Analyzers::Onyphe, 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 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,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Commands
5
+ module PassiveDNS
6
+ def self.included(thor)
7
+ thor.class_eval do
8
+ desc "passive_dns [IP|DOMAIN]", "Cross search with passive DNS services 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 passive_dns(query)
13
+ with_error_handling do
14
+ run_analyzer Analyzers::PassiveDNS, query: refang(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 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,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Commands
5
+ module SecurityTrails
6
+ def self.included(thor)
7
+ thor.class_eval do
8
+ desc "securitytrails [IP|DOMAIN|EMAIL]", "SecurityTrails lookup by an ip, domain or 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 securitytrails(indiactor)
13
+ with_error_handling do
14
+ run_analyzer Analyzers::SecurityTrails, query: refang(indiactor), options: options
15
+ end
16
+ end
17
+ map "st" => :securitytrails
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end