mihari 1.3.1 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +44 -0
  3. data/README.md +23 -12
  4. data/Rakefile +1 -0
  5. data/docker/Dockerfile +3 -2
  6. data/{screenshots → images}/alert.png +0 -0
  7. data/{screenshots → images}/eyecatch.png +0 -0
  8. data/images/logo.png +0 -0
  9. data/{screenshots → images}/misp.png +0 -0
  10. data/{screenshots → images}/slack.png +0 -0
  11. data/lib/mihari/alert_viewer.rb +3 -3
  12. data/lib/mihari/analyzers/base.rb +1 -1
  13. data/lib/mihari/analyzers/basic.rb +3 -4
  14. data/lib/mihari/analyzers/binaryedge.rb +4 -7
  15. data/lib/mihari/analyzers/censys.rb +3 -7
  16. data/lib/mihari/analyzers/circl.rb +3 -5
  17. data/lib/mihari/analyzers/crtsh.rb +2 -6
  18. data/lib/mihari/analyzers/dnpedia.rb +3 -6
  19. data/lib/mihari/analyzers/dnstwister.rb +4 -9
  20. data/lib/mihari/analyzers/free_text.rb +2 -6
  21. data/lib/mihari/analyzers/http_hash.rb +3 -11
  22. data/lib/mihari/analyzers/onyphe.rb +3 -6
  23. data/lib/mihari/analyzers/otx.rb +4 -9
  24. data/lib/mihari/analyzers/passive_dns.rb +4 -9
  25. data/lib/mihari/analyzers/passive_ssl.rb +4 -9
  26. data/lib/mihari/analyzers/passivetotal.rb +9 -14
  27. data/lib/mihari/analyzers/pulsedive.rb +7 -12
  28. data/lib/mihari/analyzers/reverse_whois.rb +4 -9
  29. data/lib/mihari/analyzers/securitytrails.rb +12 -17
  30. data/lib/mihari/analyzers/securitytrails_domain_feed.rb +3 -7
  31. data/lib/mihari/analyzers/shodan.rb +9 -8
  32. data/lib/mihari/analyzers/spyse.rb +6 -11
  33. data/lib/mihari/analyzers/ssh_fingerprint.rb +2 -6
  34. data/lib/mihari/analyzers/urlscan.rb +21 -9
  35. data/lib/mihari/analyzers/virustotal.rb +6 -11
  36. data/lib/mihari/analyzers/zoomeye.rb +7 -11
  37. data/lib/mihari/cli.rb +14 -7
  38. data/lib/mihari/config.rb +1 -25
  39. data/lib/mihari/database.rb +1 -1
  40. data/lib/mihari/emitters/misp.rb +4 -2
  41. data/lib/mihari/emitters/slack.rb +18 -7
  42. data/lib/mihari/emitters/the_hive.rb +2 -2
  43. data/lib/mihari/errors.rb +2 -0
  44. data/lib/mihari/models/artifact.rb +1 -1
  45. data/lib/mihari/notifiers/exception_notifier.rb +5 -5
  46. data/lib/mihari/status.rb +1 -1
  47. data/lib/mihari/type_checker.rb +4 -4
  48. data/lib/mihari/version.rb +1 -1
  49. data/mihari.gemspec +23 -24
  50. metadata +44 -57
  51. data/.travis.yml +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6ece49c7c528579aec4fec009765915a2afe72df87eca5c39ccb59a416a200c4
4
- data.tar.gz: d4c595a7c38fb8e8b8350e38f90f572d8a74eef836817fea4ba21bb6893c3af3
3
+ metadata.gz: 951201ccebc7b6c4c117a687c1abce9ab24fa8d450f5a0f0badeeececa6db5cb
4
+ data.tar.gz: aed5f37c4031ffbc1a635ddd4fc979f4e40ab68a94ef880730bc48a2df600678
5
5
  SHA512:
6
- metadata.gz: 6ea5989d78febe490473a21c2c1958e96ea2f920eee5eee90c4521ca774c5fbd35b10efb41270adb1f5344189461afc010a2b38aec2aeae86d901e5dd7aea9d1
7
- data.tar.gz: 3c18daec3b396ac0ec96cdb22cf444c8a12f1031189b68c90961bd24ccc8143e0682294b067ca21dd59115712f7d811aaf0352c6d27bf319dcce6e988b3362a9
6
+ metadata.gz: a81ff55bf880a3581ad52f6bf2d8652e1d7824119ed31daed81eb0e8f215d4d26a19a10d646b5497346e6795a320de18cd63fa817958081c2ba4393efad4c20a
7
+ data.tar.gz: b3fa4c9979fc22863d0e171d87918c320ec177b5e27c0820f4997919cb714d8c19516d37e15eccaed8b0a81102498820b4865864dcb56c650c186ef1bd057b56
@@ -0,0 +1,44 @@
1
+ name: Ruby CI
2
+
3
+ on: [pull_request]
4
+
5
+ jobs:
6
+ build:
7
+
8
+ runs-on: ubuntu-latest
9
+
10
+ services:
11
+ db:
12
+ image: postgres:12
13
+ env:
14
+ POSTGRES_USER: postgres
15
+ POSTGRES_PASSWORD: postgres
16
+ POSTGRES_DB: test
17
+ options: >-
18
+ --health-cmd pg_isready
19
+ --health-interval 10s
20
+ --health-timeout 5s
21
+ --health-retries 5
22
+ ports:
23
+ - 5432:5432
24
+
25
+ strategy:
26
+ fail-fast: false
27
+ matrix:
28
+ ruby: [2.7, '3.0']
29
+
30
+ steps:
31
+ - uses: actions/checkout@v2
32
+ - name: Set up Ruby 2.7
33
+ uses: ruby/setup-ruby@v1
34
+ with:
35
+ ruby-version: ${{ matrix.ruby }}
36
+ bundler-cache: true
37
+ - name: Build and test with Rake
38
+ env:
39
+ DATABASE: postgresql://postgres:postgres@localhost:5432/test
40
+ run: |
41
+ sudo apt-get -yqq install libpq-dev
42
+ gem install bundler
43
+ bundle install
44
+ bundle exec rake
data/README.md CHANGED
@@ -1,49 +1,59 @@
1
1
  # mihari
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/mihari.svg)](https://badge.fury.io/rb/mihari)
4
- [![Build Status](https://travis-ci.com/ninoseki/mihari.svg?branch=master)](https://travis-ci.com/ninoseki/mihari)
4
+ [![Ruby CI](https://github.com/ninoseki/mihari/actions/workflows/test.yml/badge.svg)](https://github.com/ninoseki/mihari/actions/workflows/test.yml)
5
5
  [![Docker Cloud Build Status](https://img.shields.io/docker/cloud/build/ninoseki/mihari)](https://hub.docker.com/r/ninoseki/mihari)
6
6
  [![Coverage Status](https://coveralls.io/repos/github/ninoseki/mihari/badge.svg?branch=master)](https://coveralls.io/github/ninoseki/mihari?branch=master)
7
7
  [![CodeFactor](https://www.codefactor.io/repository/github/ninoseki/mihari/badge)](https://www.codefactor.io/repository/github/ninoseki/mihari)
8
8
 
9
+ ![img](https://github.com/ninoseki/mihari/raw/master/images/logo.png)
10
+
9
11
  Mihari is a helper to run queries & manage results continuously. Mihari can be used for C2, landing page and phishing hunting.
10
12
 
11
13
  ## How it works
12
14
 
13
- - Mihari makes a query against Shodan, Censys, VirusTotal, SecurityTrails, etc. and extracts artifacts (IP addresses, domains, URLs and hashes) from the results.
15
+ - Mihari makes a query against Shodan, Censys, VirusTotal, SecurityTrails, etc. and extracts artifacts (IP addresses, domains, URLs and hashes).
14
16
  - Mihari checks whether a DB (SQLite3 or PostgreSQL) contains the artifacts or not.
15
17
  - If it doesn't contain the artifacts:
16
- - Mihari creates an alert on TheHive. (Optional)
17
- - Mihari sends a notification to Slack. (Optional)
18
- - Mihari creates an event on MISP. (Optional)
18
+ - Mihari creates an alert on TheHive.
19
+ - Mihari sends a notification to Slack.
20
+ - Mihari creates an event on MISP.
19
21
 
20
- ![img](https://github.com/ninoseki/mihari/raw/master/screenshots/eyecatch.png)
22
+ ![img](https://github.com/ninoseki/mihari/raw/master/images/eyecatch.png)
21
23
 
22
24
  ### Screenshots
23
25
 
24
26
  - TheHive alert example
25
27
 
26
- ![img](https://github.com/ninoseki/mihari/raw/master/screenshots/alert.png)
28
+ ![img](https://github.com/ninoseki/mihari/raw/master/images/alert.png)
27
29
 
28
30
  - Slack notification example
29
31
 
30
- ![img](https://github.com/ninoseki/mihari/raw/master/screenshots/slack.png)
32
+ ![img](https://github.com/ninoseki/mihari/raw/master/images/slack.png)
31
33
 
32
34
  - MISP event example
33
35
 
34
- ![img](https://github.com/ninoseki/mihari/raw/master/screenshots/misp.png)
36
+ ![img](https://github.com/ninoseki/mihari/raw/master/images/misp.png)
35
37
 
36
38
  ## Requirements
37
39
 
38
- - Ruby 2.6+
39
- - SQLite3
40
- - libpq
40
+ - Ruby (2.7 or 3.0)
41
+ - SQLite3 or PostgreSQL
41
42
 
42
43
  ```bash
43
44
  # For Debian / Ubuntu
44
45
  apt-get install sqlite3 libsqlite3-dev libpq-dev
45
46
  ```
46
47
 
48
+ ## Supported platforms & databases
49
+
50
+ | Name | Supported versions |
51
+ |------------|--------------------|
52
+ | PostgreSQL | v12 |
53
+ | SQLite | v3 |
54
+ | MISP | v2.4 |
55
+ | TheHive | v3.x & v4.x |
56
+
47
57
  ## Installation
48
58
 
49
59
  ```bash
@@ -69,6 +79,7 @@ Mihari supports the following services by default.
69
79
  - [Onyphe](https://onyphe.io)
70
80
  - [OTX](https://otx.alienvault.com/)
71
81
  - [PassiveTotal](https://community.riskiq.com/)
82
+ - [Pulsedive](https://pulsedive.com/)
72
83
  - [SecurityTrails](https://securitytrails.com/)
73
84
  - [Shodan](https://shodan.io)
74
85
  - [Spyse](https://spyse.com)
data/Rakefile CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "bundler/gem_tasks"
4
4
  require "rspec/core/rake_task"
5
+ require "standard/rake"
5
6
 
6
7
  RSpec::Core::RakeTask.new(:spec)
7
8
 
data/docker/Dockerfile CHANGED
@@ -1,4 +1,5 @@
1
- FROM ruby:2.7-alpine3.10
1
+ FROM ruby:3.0.0-alpine3.13
2
+
2
3
  RUN apk --no-cache add git build-base ruby-dev sqlite-dev postgresql-dev \
3
4
  && cd /tmp/ \
4
5
  && git clone https://github.com/ninoseki/mihari.git \
@@ -10,4 +11,4 @@ RUN apk --no-cache add git build-base ruby-dev sqlite-dev postgresql-dev \
10
11
 
11
12
  ENTRYPOINT ["mihari"]
12
13
 
13
- CMD ["--help"]
14
+ CMD ["--help"]
File without changes
File without changes
data/images/logo.png ADDED
Binary file
File without changes
File without changes
@@ -9,13 +9,13 @@ module Mihari
9
9
  relation = Alert.includes(:tags, :artifacts)
10
10
  relation = relation.where(title: title) if title
11
11
  relation = relation.where(source: source) if source
12
- relation = relation.where(tags: { name: tag } ) if tag
12
+ relation = relation.where(tags: {name: tag}) if tag
13
13
 
14
14
  alerts = relation.limit(limit).order(id: :desc)
15
15
  alerts.map do |alert|
16
16
  json = AlertSerializer.new(alert).as_json
17
- json[:artifacts] = (json.dig(:artifacts) || []).map { |artifact_| artifact_.dig(:data) }
18
- json[:tags] = (json.dig(:tags) || []).map { |tag_| tag_.dig(:name) }
17
+ json[:artifacts] = (json[:artifacts] || []).map { |artifact_| artifact_[:data] }
18
+ json[:tags] = (json[:tags] || []).map { |tag_| tag_[:name] }
19
19
  json
20
20
  end
21
21
  end
@@ -42,7 +42,7 @@ module Mihari
42
42
 
43
43
  def run_emitter(emitter)
44
44
  emitter.run(title: title, description: description, artifacts: unique_artifacts, source: source, tags: tags)
45
- rescue StandardError => e
45
+ rescue => e
46
46
  puts "Emission by #{emitter.class} is failed: #{e}"
47
47
  end
48
48
 
@@ -4,12 +4,11 @@ module Mihari
4
4
  module Analyzers
5
5
  class Basic < Base
6
6
  attr_accessor :title
7
- attr_reader :description
8
- attr_reader :artifacts
9
- attr_reader :source
10
- attr_reader :tags
7
+ attr_reader :description, :artifacts, :source, :tags
11
8
 
12
9
  def initialize(title:, description:, artifacts:, source:, tags: [])
10
+ super()
11
+
13
12
  @title = title
14
13
  @description = description
15
14
  @artifacts = artifacts
@@ -5,10 +5,7 @@ require "binaryedge"
5
5
  module Mihari
6
6
  module Analyzers
7
7
  class BinaryEdge < Base
8
- attr_reader :title
9
- attr_reader :description
10
- attr_reader :query
11
- attr_reader :tags
8
+ attr_reader :title, :description, :query, :tags
12
9
 
13
10
  def initialize(query, title: nil, description: nil, tags: [])
14
11
  super()
@@ -24,7 +21,7 @@ module Mihari
24
21
  return [] unless results || results.empty?
25
22
 
26
23
  results.map do |result|
27
- events = result.dig("events") || []
24
+ events = result["events"] || []
28
25
  events.map do |event|
29
26
  event.dig "target", "ip"
30
27
  end.compact
@@ -47,7 +44,7 @@ module Mihari
47
44
  responses = []
48
45
  (1..Float::INFINITY).each do |page|
49
46
  res = search_with_page(query, page: page)
50
- total = res.dig("total").to_i
47
+ total = res["total"].to_i
51
48
 
52
49
  responses << res
53
50
  break if total <= page * PAGE_SIZE
@@ -56,7 +53,7 @@ module Mihari
56
53
  end
57
54
 
58
55
  def config_keys
59
- %w(binaryedge_api_key)
56
+ %w[binaryedge_api_key]
60
57
  end
61
58
 
62
59
  def api
@@ -5,11 +5,7 @@ require "censu"
5
5
  module Mihari
6
6
  module Analyzers
7
7
  class Censys < Base
8
- attr_reader :title
9
- attr_reader :description
10
- attr_reader :query
11
- attr_reader :tags
12
- attr_reader :type
8
+ attr_reader :title, :description, :query, :tags, :type
13
9
 
14
10
  def initialize(query, title: nil, description: nil, tags: [], type: "ipv4")
15
11
  super()
@@ -37,7 +33,7 @@ module Mihari
37
33
  private
38
34
 
39
35
  def valid_type?
40
- %w(ipv4 websites certificates).include? type
36
+ %w[ipv4 websites certificates].include? type
41
37
  end
42
38
 
43
39
  def normalize(domain)
@@ -86,7 +82,7 @@ module Mihari
86
82
  end
87
83
 
88
84
  def config_keys
89
- %w(censys_id censys_secret)
85
+ %w[censys_id censys_secret]
90
86
  end
91
87
 
92
88
  def api
@@ -5,9 +5,7 @@ require "passive_circl"
5
5
  module Mihari
6
6
  module Analyzers
7
7
  class CIRCL < Base
8
- attr_reader :title
9
- attr_reader :description
10
- attr_reader :tags
8
+ attr_reader :title, :description, :tags
11
9
 
12
10
  def initialize(query, title: nil, description: nil, tags: [])
13
11
  super()
@@ -27,7 +25,7 @@ module Mihari
27
25
  private
28
26
 
29
27
  def config_keys
30
- %w(circl_passive_password circl_passive_username)
28
+ %w[circl_passive_password circl_passive_username]
31
29
  end
32
30
 
33
31
  def api
@@ -41,7 +39,7 @@ module Mihari
41
39
  when "hash"
42
40
  passive_ssl_lookup
43
41
  else
44
- raise InvalidInputError, "#{@query}(type: #{@type || 'unknown'}) is not supported."
42
+ raise InvalidInputError, "#{@query}(type: #{@type || "unknown"}) is not supported."
45
43
  end
46
44
  end
47
45
 
@@ -5,11 +5,7 @@ require "crtsh"
5
5
  module Mihari
6
6
  module Analyzers
7
7
  class Crtsh < Base
8
- attr_reader :title
9
- attr_reader :description
10
- attr_reader :query
11
- attr_reader :tags
12
- attr_reader :exclude_expired
8
+ attr_reader :title, :description, :query, :tags, :exclude_expired
13
9
 
14
10
  def initialize(query, title: nil, description: nil, tags: [], exclude_expired: nil)
15
11
  super()
@@ -24,7 +20,7 @@ module Mihari
24
20
 
25
21
  def artifacts
26
22
  results = search
27
- name_values = results.map { |result| result.dig("name_value") }.compact
23
+ name_values = results.map { |result| result["name_value"] }.compact
28
24
  name_values.map(&:lines).flatten.uniq.map(&:chomp)
29
25
  end
30
26
 
@@ -5,10 +5,7 @@ require "dnpedia"
5
5
  module Mihari
6
6
  module Analyzers
7
7
  class DNPedia < Base
8
- attr_reader :query
9
- attr_reader :title
10
- attr_reader :description
11
- attr_reader :tags
8
+ attr_reader :query, :title, :description, :tags
12
9
 
13
10
  def initialize(query, title: nil, description: nil, tags: [])
14
11
  super()
@@ -31,9 +28,9 @@ module Mihari
31
28
 
32
29
  def lookup
33
30
  res = api.search(query)
34
- rows = res.dig("rows") || []
31
+ rows = res["rows"] || []
35
32
  rows.map do |row|
36
- [row.dig("name"), row.dig("zoneid")].join(".")
33
+ [row["name"], row["zoneid"]].join(".")
37
34
  end
38
35
  end
39
36
  end
@@ -7,12 +7,7 @@ require "parallel"
7
7
  module Mihari
8
8
  module Analyzers
9
9
  class DNSTwister < Base
10
- attr_reader :query
11
- attr_reader :type
12
-
13
- attr_reader :title
14
- attr_reader :description
15
- attr_reader :tags
10
+ attr_reader :query, :type, :title, :description, :tags
16
11
 
17
12
  def initialize(query, title: nil, description: nil, tags: [])
18
13
  super()
@@ -47,11 +42,11 @@ module Mihari
47
42
  end
48
43
 
49
44
  def lookup
50
- raise InvalidInputError, "#{query}(type: #{type || 'unknown'}) is not supported." unless valid_type?
45
+ raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
51
46
 
52
47
  res = api.fuzz(query)
53
- fuzzy_domains = res.dig("fuzzy_domains") || []
54
- domains = fuzzy_domains.map { |domain| domain.dig("domain") }
48
+ fuzzy_domains = res["fuzzy_domains"] || []
49
+ domains = fuzzy_domains.map { |domain| domain["domain"] }
55
50
  Parallel.map(domains) do |domain|
56
51
  resolvable?(domain) ? domain : nil
57
52
  end.compact
@@ -5,15 +5,11 @@ require "parallel"
5
5
  module Mihari
6
6
  module Analyzers
7
7
  class FreeText < Base
8
- attr_reader :query
9
-
10
- attr_reader :title
11
- attr_reader :description
12
- attr_reader :tags
8
+ attr_reader :query, :title, :description, :tags
13
9
 
14
10
  ANALYZERS = [
15
11
  Mihari::Analyzers::BinaryEdge,
16
- Mihari::Analyzers::Censys,
12
+ Mihari::Analyzers::Censys
17
13
  ].freeze
18
14
 
19
15
  def initialize(query, title: nil, description: nil, tags: [])
@@ -5,15 +5,7 @@ require "parallel"
5
5
  module Mihari
6
6
  module Analyzers
7
7
  class HTTPHash < Base
8
- attr_reader :md5
9
- attr_reader :sha256
10
- attr_reader :mmh3
11
-
12
- attr_reader :html
13
-
14
- attr_reader :title
15
- attr_reader :description
16
- attr_reader :tags
8
+ attr_reader :md5, :sha256, :mmh3, :html, :title, :description, :tags
17
9
 
18
10
  def initialize(_query, md5: nil, sha256: nil, mmh3: nil, html: nil, title: nil, description: nil, tags: [])
19
11
  super()
@@ -57,7 +49,7 @@ module Mihari
57
49
  [
58
50
  md5 ? "md5:#{md5}" : nil,
59
51
  sha256 ? "sha256:#{sha256}" : nil,
60
- mmh3 ? "mmh3:#{mmh3}" : nil,
52
+ mmh3 ? "mmh3:#{mmh3}" : nil
61
53
  ].compact.join(",")
62
54
  end
63
55
 
@@ -92,7 +84,7 @@ module Mihari
92
84
  binary_edge,
93
85
  censys,
94
86
  onyphe,
95
- shodan,
87
+ shodan
96
88
  ].compact
97
89
  end
98
90