ssh_scan 0.0.14 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3d541b6a665e8adbd86013e68cea159cb42a514b
4
- data.tar.gz: cbbb3ba9b9e169091ca8db560ccfb06780781f39
3
+ metadata.gz: c5d764d9a2898d145c0f46eee1c59bb0c6e7bcde
4
+ data.tar.gz: 9bd1e38f1e4c715bf01a9526b85a5cf4d5c7961f
5
5
  SHA512:
6
- metadata.gz: 70218de598e768b46841299ebe891980ece0080792d2eac5fcf8d879e13c15c841a817bbf148968cf6ec2117d232c80c7f676eada7b1d812014109bfe5b31c34
7
- data.tar.gz: e1fe1bdb16ea13623741607d54e3102af8a4e26c0b94adaebbbc90736c5587a3b2b427057e866cf73e3a66ec7cb58c52a67f6f9ec39a196f6e3cd0bb3c35bb95
6
+ metadata.gz: d9dca78fe553facec68df4241f43ed13537ef08d5b39f9d50ddafa50e97ba0c24d76a836f527c677e7cd90092be970604a3729b0348e06dfd28daefb4aef34b1
7
+ data.tar.gz: 67329c5b6e9c652b4572c9d1085be7cf220d48cafe19cf4dfa2827d8849ea5e43afcc284f79638cd1fdb03fca79677b1b662c3bef64f61765e4ab51f442475a4
data/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
1
  *.gem
2
2
  *.rbc
3
+ *.db
3
4
  /.config
4
5
  /coverage/
5
6
  /InstalledFiles
@@ -34,3 +35,4 @@ build/
34
35
 
35
36
  # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
36
37
  .rvmrc
38
+ gh-pages/
data/README.md CHANGED
@@ -59,22 +59,23 @@ bundle install
59
59
 
60
60
  Run `ssh_scan -h` to get this
61
61
 
62
- ssh_scan v0.0.10 (https://github.com/mozilla/ssh_scan)
62
+ ssh_scan v0.0.15 (https://github.com/mozilla/ssh_scan)
63
63
 
64
64
  Usage: ssh_scan [options]
65
65
  -t, --target [IP/Range/Hostname] IP/Ranges/Hostname to scan
66
66
  -f, --file [FilePath] File Path of the file containing IP/Range/Hostnames to scan
67
67
  -T, --timeout [seconds] Timeout per connect after which ssh_scan gives up on the host
68
- -o, --output [FilePath] File to write JSON output to
68
+ -L, --logger [Log File Path] Enable logger
69
69
  -O, --from_json [FilePath] File to read JSON output from
70
+ -o, --output [FilePath] File to write JSON output to
70
71
  -p, --port [PORT] Port (Default: 22)
71
72
  -P, --policy [FILE] Custom policy file (Default: Mozilla Modern)
72
73
  --threads [NUMBER] Number of worker threads (Default: 5)
74
+ --fingerprint-db [FILE] File location of fingerprint database (Default: ./fingerprints.db)
73
75
  -u, --unit-test [FILE] Throw appropriate exit codes based on compliance status
76
+ -V, --verbosity Set the logger level (Accepted Params: INFO, DEBUG, WARN, ERROR, FATAL)
74
77
  -v, --version Display just version info
75
78
  -h, --help Show this message
76
- -L, --logger[Log File Path] Enable logger and set the log file
77
- -V, --verbosity Set the logger level (Params: INFO, DEBUG, WARN, ERROR, FATAL)
78
79
 
79
80
  Examples:
80
81
 
data/bin/ssh_scan CHANGED
@@ -18,6 +18,7 @@ options = {
18
18
  :threads => 5,
19
19
  :verbosity => nil,
20
20
  :logger => Logger.new(STDERR),
21
+ :fingerprint_database => "./fingerprints.db"
21
22
  }
22
23
 
23
24
  target_parser = SSHScan::TargetParser.new()
@@ -107,13 +108,18 @@ opt_parser = OptionParser.new do |opts|
107
108
  options[:threads] = threads.to_i
108
109
  end
109
110
 
111
+ opts.on("--fingerprint-db [FILE]",
112
+ "File location of fingerprint database (Default: ./fingerprints.db)") do |fingerprint_db|
113
+ options[:fingerprint_database] = fingerprint_db
114
+ end
115
+
110
116
  opts.on("-u", "--unit-test [FILE]",
111
117
  "Throw appropriate exit codes based on compliance status") do
112
118
  options[:unit_test] = true
113
119
  end
114
120
 
115
121
  opts.on("-V", "--verbosity",
116
- "Set the logger level (Accpeted Params: INFO, DEBUG, WARN, ERROR, FATAL)") do |verbosity|
122
+ "Set the logger level (Accepted Params: INFO, DEBUG, WARN, ERROR, FATAL)") do |verbosity|
117
123
  options[:logger].level = case options[:verbosity]
118
124
  when "INFO" then Logger::INFO
119
125
  when "DEBUG" then Logger::DEBUG
@@ -183,6 +189,14 @@ unless File.exists?(options[:policy])
183
189
  exit 1
184
190
  end
185
191
 
192
+ # Check to see if we're running the latest released version
193
+ update = SSHScan::Update.new
194
+ if update.newer_gem_available?
195
+ options[:logger].warn("You're NOT using the latest version of ssh_scan, try 'gem update ssh_scan' to get the latest")
196
+ else
197
+ options[:logger].info("You're using the latest version of ssh_scan #{SSHScan::VERSION}")
198
+ end
199
+
186
200
  options[:policy_file] = SSHScan::Policy.from_file(options[:policy])
187
201
 
188
202
  # Perform scan and get results
data/lib/ssh_scan.rb CHANGED
@@ -11,6 +11,7 @@ require 'ssh_scan/policy_manager'
11
11
  require 'ssh_scan/protocol'
12
12
  require 'ssh_scan/scan_engine'
13
13
  require 'ssh_scan/target_parser'
14
+ require 'ssh_scan/update'
14
15
 
15
16
  #Monkey Patches
16
17
  require 'string_ext'
@@ -71,20 +71,32 @@ module SSHScan
71
71
  result[:ssh_lib] = @server_banner.ssh_lib_guess.common
72
72
  result[:ssh_lib_cpe] = @server_banner.ssh_lib_guess.cpe
73
73
 
74
- @sock.write(kex_init_raw)
75
- resp = @sock.read(4)
74
+ begin
75
+ @sock.write(kex_init_raw)
76
+ resp = @sock.read(4)
76
77
 
77
- if resp.nil?
78
- @error = SSHScan::Error::NoKexResponse.new("service did not respond to our kex init request")
79
- @sock = nil
80
- return result
81
- end
78
+ if resp.nil?
79
+ result[:error] = SSHScan::Error::NoKexResponse.new("service did not respond to our kex init request")
80
+ @sock = nil
81
+ return result
82
+ end
82
83
 
83
- resp += @sock.read(resp.unpack("N").first)
84
- @sock.close
84
+ resp += @sock.read(resp.unpack("N").first)
85
+ @sock.close
85
86
 
86
- kex_exchange_init = SSHScan::KeyExchangeInit.read(resp)
87
- result.merge!(kex_exchange_init.to_hash)
87
+ kex_exchange_init = SSHScan::KeyExchangeInit.read(resp)
88
+ result.merge!(kex_exchange_init.to_hash)
89
+ rescue Errno::ETIMEDOUT => e
90
+ @error = SSHScan::Error::ConnectTimeout.new(e.message)
91
+ @sock = nil
92
+ rescue Errno::ECONNREFUSED,
93
+ Errno::ENETUNREACH,
94
+ Errno::ECONNRESET,
95
+ Errno::EACCES,
96
+ Errno::EHOSTUNREACH => e
97
+ result[:error] = SSHScan::Error::NoKexResponse.new("service did not respond to our kex init request")
98
+ @sock = nil
99
+ end
88
100
 
89
101
  return result
90
102
  end
@@ -0,0 +1,39 @@
1
+ require 'sqlite3'
2
+
3
+ module SSHScan
4
+ class FingerprintDatabase
5
+ def initialize(database_name)
6
+ if File.exists?(database_name)
7
+ @db = ::SQLite3::Database.open(database_name)
8
+ else
9
+ @db = ::SQLite3::Database.new(database_name)
10
+ self.create_schema
11
+ end
12
+ end
13
+
14
+ def create_schema
15
+ @db.execute <<-SQL
16
+ create table fingerprints (
17
+ fingerprint varchar(100),
18
+ ip varchar(100)
19
+ );
20
+ SQL
21
+ end
22
+
23
+ def clear_fingerprints(ip)
24
+ @db.execute "delete from fingerprints where ip like ( ? )", [ip]
25
+ end
26
+
27
+ def add_fingerprint(fingerprint, ip)
28
+ @db.execute "insert into fingerprints values ( ?, ? )", [fingerprint, ip]
29
+ end
30
+
31
+ def find_fingerprints(fingerprint)
32
+ ips = []
33
+ @db.execute( "select * from fingerprints where fingerprint like ( ? )", [fingerprint] ) do |row|
34
+ ips << row[1]
35
+ end
36
+ return ips
37
+ end
38
+ end
39
+ end
@@ -146,7 +146,8 @@ module SSHScan
146
146
  "6.6p1-2ubuntu2.2",
147
147
  "6.6p1-2ubuntu2",
148
148
  "6.6p1-2ubuntu1",
149
- "6.2p2-6ubuntu1"],
149
+ "6.2p2-6ubuntu1",
150
+ "6.6.1p1 Ubuntu-8"],
150
151
  "14.10" => ["6.6p1-5build1"],
151
152
  "15.04" =>
152
153
  ["6.7p1-5ubuntu1.4",
@@ -1,6 +1,7 @@
1
1
  require 'socket'
2
2
  require 'ssh_scan/client'
3
3
  require 'ssh_scan/crypto'
4
+ require 'ssh_scan/fingerprint_database'
4
5
  require 'net/ssh'
5
6
 
6
7
  module SSHScan
@@ -11,7 +12,6 @@ module SSHScan
11
12
  if port.nil?
12
13
  port = 22
13
14
  end
14
- policy = opts[:policy_file]
15
15
  timeout = opts[:timeout]
16
16
  result = []
17
17
 
@@ -46,7 +46,12 @@ module SSHScan
46
46
 
47
47
  # Connect and get results (Net-SSH)
48
48
  begin
49
- net_ssh_session = Net::SSH::Transport::Session.new(target, :port => port, :timeout => timeout)
49
+ net_ssh_session = Net::SSH::Transport::Session.new(
50
+ target,
51
+ :port => port,
52
+ :timeout => timeout,
53
+ :paranoid => Net::SSH::Verifiers::Null.new
54
+ )
50
55
  raise SSHScan::Error::ClosedConnection.new if net_ssh_session.closed?
51
56
  auth_session = Net::SSH::Authentication::Session.new(net_ssh_session, :auth_methods => ["none"])
52
57
  auth_session.authenticate("none", "test", "test")
@@ -76,25 +81,8 @@ module SSHScan
76
81
  end
77
82
  end
78
83
 
79
- # Do this only when no errors were reported
80
- if !policy.nil? &&
81
- !result[:key_algorithms].nil? &&
82
- !result[:server_host_key_algorithms].nil? &&
83
- !result[:encryption_algorithms_client_to_server].nil? &&
84
- !result[:encryption_algorithms_server_to_client].nil? &&
85
- !result[:mac_algorithms_client_to_server].nil? &&
86
- !result[:mac_algorithms_server_to_client].nil? &&
87
- !result[:compression_algorithms_client_to_server].nil? &&
88
- !result[:compression_algorithms_server_to_client].nil? &&
89
- !result[:languages_client_to_server].nil? &&
90
- !result[:languages_server_to_client].nil?
91
- policy_mgr = SSHScan::PolicyManager.new(result, policy)
92
- result['compliance'] = policy_mgr.compliance_results
93
- end
94
-
95
84
  # Add scan times
96
85
  end_time = Time.now
97
-
98
86
  result['start_time'] = start_time.to_s
99
87
  result['end_time'] = end_time.to_s
100
88
  result['scan_duration_seconds'] = end_time - start_time
@@ -126,6 +114,51 @@ module SSHScan
126
114
  end
127
115
  workers.map(&:join)
128
116
 
117
+ # Add all the fingerprints to our peristent FingerprintDatabase
118
+ fingerprint_db = SSHScan::FingerprintDatabase.new(opts[:fingerprint_database])
119
+ results.each do |result|
120
+ fingerprint_db.clear_fingerprints(result[:ip])
121
+ if result['fingerprints']
122
+ result['fingerprints'].values.each do |fingerprint|
123
+ fingerprint_db.add_fingerprint(fingerprint, result[:ip])
124
+ end
125
+ end
126
+ end
127
+
128
+ # Decorate all the results with duplicate keys
129
+ results.each do |result|
130
+ if result['fingerprints']
131
+ ip = result[:ip]
132
+ result['duplicate_host_key_ips'] = []
133
+ result['fingerprints'].values.each do |fingerprint|
134
+ fingerprint_db.find_fingerprints(fingerprint).each do |other_ip|
135
+ next if ip == other_ip
136
+ result['duplicate_host_key_ips'] << other_ip
137
+ end
138
+ end
139
+ result['duplicate_host_key_ips'].uniq!
140
+ end
141
+ end
142
+
143
+ # Decorate all the results with compliance information
144
+ results.each do |result|
145
+ # Do this only when we have all the information we need
146
+ if !opts[:policy_file].nil? &&
147
+ !result[:key_algorithms].nil? &&
148
+ !result[:server_host_key_algorithms].nil? &&
149
+ !result[:encryption_algorithms_client_to_server].nil? &&
150
+ !result[:encryption_algorithms_server_to_client].nil? &&
151
+ !result[:mac_algorithms_client_to_server].nil? &&
152
+ !result[:mac_algorithms_server_to_client].nil? &&
153
+ !result[:compression_algorithms_client_to_server].nil? &&
154
+ !result[:compression_algorithms_server_to_client].nil? &&
155
+ !result[:languages_client_to_server].nil? &&
156
+ !result[:languages_server_to_client].nil?
157
+ policy_mgr = SSHScan::PolicyManager.new(result, opts[:policy_file])
158
+ result['compliance'] = policy_mgr.compliance_results
159
+ end
160
+ end
161
+
129
162
  return results
130
163
  end
131
164
  end
@@ -0,0 +1,64 @@
1
+ require 'ssh_scan/os'
2
+ require 'ssh_scan/ssh_lib'
3
+ require 'ssh_scan/version'
4
+ require 'net/http'
5
+
6
+ module SSHScan
7
+ class Update
8
+ def next_patch_version(version = SSHScan::VERSION)
9
+ major, minor, patch = version.split(".")
10
+ patch_num = patch.to_i
11
+ patch_num += 1
12
+
13
+ return [major, minor, patch_num.to_s].join(".")
14
+ end
15
+
16
+ def next_minor_version(version = SSHScan::VERSION)
17
+ major, minor, patch = version.split(".")
18
+ minor_num = minor.to_i
19
+ minor_num += 1
20
+
21
+ return [major, minor_num.to_s, "0"].join(".")
22
+ end
23
+
24
+ def next_major_version(version = SSHScan::VERSION)
25
+ major, minor, patch = version.split(".")
26
+ major_num = major.to_i
27
+ major_num += 1
28
+
29
+ return [major_num.to_s, "0", "0"].join(".")
30
+ end
31
+
32
+ def gem_exists?(version = SSHScan::VERSION)
33
+ uri = URI("https://rubygems.org/gems/ssh_scan/versions/#{version}")
34
+
35
+ begin
36
+ res = Net::HTTP.get_response(uri)
37
+ rescue
38
+ return false
39
+ end
40
+
41
+ if res.code != "200"
42
+ return false
43
+ else
44
+ return true
45
+ end
46
+ end
47
+
48
+ def newer_gem_available?(version = SSHScan::VERSION)
49
+ if gem_exists?(next_patch_version(version))
50
+ return true
51
+ end
52
+
53
+ if gem_exists?(next_minor_version(version))
54
+ return true
55
+ end
56
+
57
+ if gem_exists?(next_major_version(version))
58
+ return true
59
+ end
60
+
61
+ return false
62
+ end
63
+ end
64
+ end
@@ -1,3 +1,3 @@
1
1
  module SSHScan
2
- VERSION = '0.0.14'
2
+ VERSION = '0.0.15'
3
3
  end
data/ssh_scan.gemspec CHANGED
@@ -29,6 +29,7 @@ Gem::Specification.new do |s|
29
29
  s.add_dependency('bindata', '~> 2.0')
30
30
  s.add_dependency('netaddr')
31
31
  s.add_dependency('net-ssh')
32
+ s.add_dependency('sqlite3')
32
33
  s.add_development_dependency('pry')
33
34
  s.add_development_dependency('rspec', '~> 3.0')
34
35
  s.add_development_dependency('rspec-its', '~> 1.2')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ssh_scan
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.14
4
+ version: 0.0.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Claudius
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-09-16 00:00:00.000000000 Z
12
+ date: 2016-09-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bindata
@@ -53,6 +53,20 @@ dependencies:
53
53
  - - ">="
54
54
  - !ruby/object:Gem::Version
55
55
  version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: sqlite3
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
56
70
  - !ruby/object:Gem::Dependency
57
71
  name: pry
58
72
  requirement: !ruby/object:Gem::Requirement
@@ -136,6 +150,7 @@ files:
136
150
  - lib/ssh_scan/error/disconnected.rb
137
151
  - lib/ssh_scan/error/no_banner.rb
138
152
  - lib/ssh_scan/error/no_kex_response.rb
153
+ - lib/ssh_scan/fingerprint_database.rb
139
154
  - lib/ssh_scan/os.rb
140
155
  - lib/ssh_scan/os/centos.rb
141
156
  - lib/ssh_scan/os/cisco.rb
@@ -160,6 +175,7 @@ files:
160
175
  - lib/ssh_scan/ssh_lib/rosssh.rb
161
176
  - lib/ssh_scan/ssh_lib/unknown.rb
162
177
  - lib/ssh_scan/target_parser.rb
178
+ - lib/ssh_scan/update.rb
163
179
  - lib/ssh_scan/version.rb
164
180
  - lib/string_ext.rb
165
181
  - policies/mozilla_intermediate.yml