ssh_scan 0.0.10.beta.2 → 0.0.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a689938f463c860bb90bb1d4f5772ff961d745d7
4
- data.tar.gz: a3945bd66434b5e9edd8348d1e65ab96c2214e4a
3
+ metadata.gz: 6403790d58c64fd35088e7052eb051074a153b48
4
+ data.tar.gz: 8ca8d5eaa79005c5479719672f55c44bbd806b58
5
5
  SHA512:
6
- metadata.gz: 5c6a0fde028fc24d8509c8ac3a6572c398c1ac5a85694115772bf1d5a3ee5b9ed8215409deb38ba6cb3682a361d764cb58816e45bf9a45a8a7882849eff33599
7
- data.tar.gz: 2a345e980a7c53f52834251a5da73e93838c82068629c81e40c75616524b4b4f31256b1077446fe1254b8a53bc9abed16b52b3fd264c8396b2096abfb04cd1ba
6
+ metadata.gz: 9ea2a32f03d07f1435f2582ef49bef0cb3b89a7ae60cfc7597c09989d5fa5c6dbda3eb1dd136a6fbc30fb960ff9ccb234ab15a646cf845d7fc2ead316cd268d6
7
+ data.tar.gz: 67e6065dbccd032dd3db6356397d24179db910570d3662f024ca3587ac4c7951d4ec4f6651671cebc548b2fbdae93f13025386c911fc386fb203f3b15d618429
data/.travis.yml CHANGED
@@ -8,6 +8,20 @@ matrix:
8
8
  - docker
9
9
  script:
10
10
  - docker build -t mozilla/ssh_scan .
11
+ - >
12
+ if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then \
13
+ docker login -u="$DOCKER_USER" -p="$DOCKER_PASS" ;\
14
+ docker push mozilla/ssh_scan:latest ;\
15
+ else \
16
+ exit 0 ;\
17
+ fi
18
+ - rvm: 2.3.0
19
+ script:
20
+ - gem install ssh_scan
21
+ - rvm: 2.3.0
22
+ script:
23
+ - chmod 755 ./spec/ssh_scan/integration.sh
24
+ - ./spec/ssh_scan/integration.sh
11
25
  - rvm: 2.2.0
12
26
  - rvm: 2.1.3
13
27
  - rvm: 2.0.0
data/README.md CHANGED
@@ -15,14 +15,21 @@ A SSH configuration and policy scanner
15
15
 
16
16
  ## Setup
17
17
 
18
- To install as a gem, type:
18
+ To install and run as a gem, type:
19
19
 
20
20
  ```bash
21
21
  gem install ssh_scan
22
22
  ssh_scan
23
23
  ```
24
24
 
25
- To install from source, type:
25
+ To run from a docker container, type:
26
+
27
+ ```bash
28
+ docker pull mozilla/ssh_scan
29
+ docker run -it mozilla/ssh_scan /app/bin/ssh_scan -t github.com
30
+ ```
31
+
32
+ To install and run from source, type:
26
33
 
27
34
  ```bash
28
35
  # clone repo
@@ -50,14 +57,16 @@ bundle install
50
57
 
51
58
  Run `ssh_scan -h` to get this
52
59
 
53
- ssh_scan v0.0.9 (https://github.com/mozilla/ssh_scan)
60
+ ssh_scan v0.0.10 (https://github.com/mozilla/ssh_scan)
54
61
 
55
62
  Usage: ssh_scan [options]
56
63
  -t, --target [IP/Range/Hostname] IP/Ranges/Hostname to scan
57
64
  -f, --file [FilePath] File Path of the file containing IP/Range/Hostnames to scan
65
+ -T, --timeout [seconds] Timeout per connect after which ssh_scan gives up on the host
58
66
  -o, --output [FilePath] File to write JSON output to
59
67
  -p, --port [PORT] Port (Default: 22)
60
68
  -P, --policy [FILE] Custom policy file (Default: Mozilla Modern)
69
+ --threads [NUMBER] Number of worker threads (Default: 5)
61
70
  -u, --unit-test [FILE] Throw appropriate exit codes based on compliance status
62
71
  -v, --version Display just version info
63
72
  -h, --help Show this message
@@ -67,12 +76,14 @@ Run `ssh_scan -h` to get this
67
76
  ssh_scan -t 192.168.1.1
68
77
  ssh_scan -t server.example.com
69
78
  ssh_scan -t ::1
79
+ ssh_scan -t ::1 -T 5
70
80
  ssh_scan -f hosts.txt
71
81
  ssh_scan -o output.json
72
82
  ssh_scan -t 192.168.1.1 -p 22222
73
83
  ssh_scan -t 192.168.1.1 -P custom_policy.yml
74
84
  ssh_scan -t 192.168.1.1 --unit-test -P custom_policy.yml
75
85
 
86
+
76
87
  - See here for [example video](https://asciinema.org/a/7pliiw5zqhj7eqvz7q437u6vx)
77
88
  - See here for [example output](https://github.com/mozilla/ssh_scan/blob/master/examples/192.168.1.1.json)
78
89
  - See here for [example policies](https://github.com/mozilla/ssh_scan/blob/master/policies)
data/bin/ssh_scan CHANGED
@@ -12,8 +12,13 @@ options = {
12
12
  :targets => [],
13
13
  :port => 22,
14
14
  :policy => File.expand_path("../../policies/mozilla_modern.yml", __FILE__),
15
- :unit_test => false
15
+ :unit_test => false,
16
+ :timeout => 2,
17
+ :threads => 5,
16
18
  }
19
+
20
+ target_parser = SSHScan::TargetParser.new()
21
+
17
22
  opt_parser = OptionParser.new do |opts|
18
23
  opts.banner = "ssh_scan v#{SSHScan::VERSION} (https://github.com/mozilla/ssh_scan)\n\n" +
19
24
  "Usage: ssh_scan [options]"
@@ -21,11 +26,7 @@ opt_parser = OptionParser.new do |opts|
21
26
  opts.on("-t", "--target [IP/Range/Hostname]", Array,
22
27
  "IP/Ranges/Hostname to scan") do |ips|
23
28
  ips.each do |ip|
24
- if ip.fqdn?
25
- options[:targets] += [ip]
26
- else
27
- options[:targets] += NetAddr::CIDR.create(ip).enumerate
28
- end
29
+ options[:targets] += target_parser.enumerateIPRange(ip)
29
30
  end
30
31
  end
31
32
 
@@ -36,10 +37,17 @@ opt_parser = OptionParser.new do |opts|
36
37
  exit
37
38
  end
38
39
  File.open(file).each do |line|
39
- options[:targets] += line.chomp.split(',')
40
+ line.chomp.split(',').each do |ip|
41
+ options[:targets] += target_parser.enumerateIPRange(ip)
42
+ end
40
43
  end
41
44
  end
42
45
 
46
+ opts.on("-T", "--timeout [seconds]",
47
+ "Timeout per connect after which ssh_scan gives up on the host") do |timeout|
48
+ options[:timeout] = timeout.to_i
49
+ end
50
+
43
51
  opts.on("-o", "--output [FilePath]",
44
52
  "File to write JSON output to") do |file|
45
53
  $stdout.reopen(file, "w")
@@ -55,6 +63,11 @@ opt_parser = OptionParser.new do |opts|
55
63
  options[:policy] = policy
56
64
  end
57
65
 
66
+ opts.on("--threads [NUMBER]",
67
+ "Number of worker threads (Default: 5)") do |threads|
68
+ options[:threads] = threads.to_i
69
+ end
70
+
58
71
  opts.on("-u", "--unit-test [FILE]",
59
72
  "Throw appropriate exit codes based on compliance status") do
60
73
  options[:unit_test] = true
@@ -72,6 +85,7 @@ opt_parser = OptionParser.new do |opts|
72
85
  puts "\n ssh_scan -t 192.168.1.1"
73
86
  puts " ssh_scan -t server.example.com"
74
87
  puts " ssh_scan -t ::1"
88
+ puts " ssh_scan -t ::1 -T 5"
75
89
  puts " ssh_scan -f hosts.txt"
76
90
  puts " ssh_scan -o output.json"
77
91
  puts " ssh_scan -t 192.168.1.1 -p 22222"
@@ -87,27 +101,27 @@ opt_parser.parse!
87
101
  if options[:targets].nil?
88
102
  puts opt_parser.help
89
103
  puts "\nReason: no target specified"
90
- exit
104
+ exit 1
91
105
  end
92
106
 
93
107
  options[:targets].each do |target|
94
108
  unless target.ip_addr? || target.fqdn?
95
109
  puts opt_parser.help
96
110
  puts "\nReason: #{options[:targets]} is not a valid target"
97
- exit
111
+ exit 1
98
112
  end
99
113
  end
100
114
 
101
115
  unless (0..65535).include?(options[:port])
102
116
  puts opt_parser.help
103
117
  puts "\nReason: port supplied is not within acceptable range"
104
- exit
118
+ exit 1
105
119
  end
106
120
 
107
121
  unless File.exists?(options[:policy])
108
122
  puts opt_parser.help
109
123
  puts "\nReason: policy file supplied is not a file"
110
- exit
124
+ exit 1
111
125
  end
112
126
 
113
127
  options[:policy_file] = SSHScan::Policy.from_file(options[:policy])
@@ -118,10 +132,13 @@ results = scan_engine.scan(options)
118
132
 
119
133
  puts JSON.pretty_generate(results)
120
134
 
121
- results.each do |result|
122
- if result["compliance"] && result["compliance"][:compliant] == false
123
- exit 1 #non-zero means a false
124
- else
125
- exit 0 #non-zero means pass
135
+ if options[:unit_test] == true
136
+ results.each do |result|
137
+ if result["compliance"] &&
138
+ result["compliance"][:compliant] == false
139
+ exit 1 #non-zero means a false
140
+ else
141
+ exit 0 #non-zero means pass
142
+ end
126
143
  end
127
144
  end
@@ -2,11 +2,13 @@ require 'socket'
2
2
  require 'ssh_scan/constants'
3
3
  require 'ssh_scan/protocol'
4
4
  require 'ssh_scan/banner'
5
+ require 'ssh_scan/error'
5
6
 
6
7
  module SSHScan
7
8
  class Client
8
- def initialize(target, port)
9
+ def initialize(target, port, timeout = 3)
9
10
  @target = target
11
+ @timeout = timeout
10
12
 
11
13
  if @target.ip_addr?
12
14
  @ip = @target
@@ -21,13 +23,34 @@ module SSHScan
21
23
  end
22
24
 
23
25
  def connect()
24
- @sock = TCPSocket.new(@ip, @port)
25
- @raw_server_banner = @sock.gets.chomp
26
- @server_banner = SSHScan::Banner.read(@raw_server_banner)
27
- @sock.puts(@client_banner.to_s)
26
+ begin
27
+ @sock = Socket.tcp(@ip, @port, connect_timeout: @timeout)
28
+ rescue Errno::ETIMEDOUT => e
29
+ @error = SSHScan::Error::ConnectTimeout.new(e.message)
30
+ @sock = nil
31
+ rescue Errno::ECONNREFUSED => e
32
+ @error = SSHScan::Error::ConnectionRefused.new(e.message)
33
+ @sock = nil
34
+ else
35
+ @raw_server_banner = @sock.gets.chomp
36
+ @server_banner = SSHScan::Banner.read(@raw_server_banner)
37
+ @sock.puts(@client_banner.to_s)
38
+ end
28
39
  end
29
40
 
30
41
  def get_kex_result(kex_init_raw = @kex_init_raw)
42
+ # Common options for all cases
43
+ result = {}
44
+ result[:ssh_scan_version] = SSHScan::VERSION
45
+ result[:hostname] = @target.fqdn? ? @target : ""
46
+ result[:ip] = @ip
47
+ result[:port] = @port
48
+
49
+ if !@sock
50
+ result[:error] = @error
51
+ return result
52
+ end
53
+
31
54
  @sock.write(kex_init_raw)
32
55
  resp = @sock.read(4)
33
56
  resp += @sock.read(resp.unpack("N").first)
@@ -36,11 +59,6 @@ module SSHScan
36
59
  kex_exchange_init = SSHScan::KeyExchangeInit.read(resp)
37
60
 
38
61
  # Assemble and print results
39
- result = {}
40
- result[:ssh_scan_version] = SSHScan::VERSION
41
- result[:hostname] = @target.fqdn? ? @target : ""
42
- result[:ip] = @ip
43
- result[:port] = @port
44
62
  result[:server_banner] = @server_banner
45
63
  result[:ssh_version] = @server_banner.ssh_version
46
64
  result[:os] = @server_banner.os_guess.common
@@ -0,0 +1,9 @@
1
+ module SSHScan
2
+ module Error
3
+ class ClosedConnection < Exception
4
+ def to_s
5
+ "#{self.class.to_s.split('::')[-1]}"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ module SSHScan
2
+ module Error
3
+ class ConnectTimeout < Exception
4
+ def initialize(message)
5
+ @message = message
6
+ end
7
+ def to_s
8
+ "#{self.class.to_s.split('::')[-1]}: #{@message}"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module SSHScan
2
+ module Error
3
+ class ConnectionRefused < Exception
4
+ def initialize(message)
5
+ @message = message
6
+ end
7
+ def to_s
8
+ "#{self.class.to_s.split('::')[-1]}: #{@message}"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module SSHScan
2
+ module Error
3
+ class Disconnected < Exception
4
+ def initialize(message)
5
+ @message = message
6
+ end
7
+ def to_s
8
+ "#{self.class.to_s.split('::')[-1]}: #{@message}"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,4 @@
1
+ require 'ssh_scan/error/connect_timeout'
2
+ require 'ssh_scan/error/closed_connection'
3
+ require 'ssh_scan/error/connection_refused'
4
+ require 'ssh_scan/error/disconnected'
@@ -2,7 +2,7 @@ require 'yaml'
2
2
 
3
3
  module SSHScan
4
4
  class Policy
5
- attr_reader :name, :kex, :macs, :encryption, :compression
5
+ attr_reader :name, :kex, :macs, :encryption, :compression, :references
6
6
 
7
7
  def initialize(opts = {})
8
8
  @name = opts['name'] || []
@@ -10,6 +10,7 @@ module SSHScan
10
10
  @macs = opts['macs'] || []
11
11
  @encryption = opts['encryption'] || []
12
12
  @compression = opts['compression'] || []
13
+ @references = opts['references'] || []
13
14
  end
14
15
 
15
16
  def self.from_file(file)
@@ -120,7 +120,8 @@ module SSHScan
120
120
  {
121
121
  :policy => @policy.name,
122
122
  :compliant => compliant?,
123
- :recommendations => recommendations
123
+ :recommendations => recommendations,
124
+ :references => @policy.references,
124
125
  }
125
126
  end
126
127
  end
@@ -5,74 +5,103 @@ require 'net/ssh'
5
5
  module SSHScan
6
6
  class ScanEngine
7
7
 
8
- def scan(opts)
9
- targets = opts[:targets]
8
+ def scan_target(target, opts)
10
9
  port = opts[:port]
11
10
  policy = opts[:policy_file]
11
+ timeout = opts[:timeout]
12
12
 
13
- # Connect and get results (native)
14
- result = []
15
- targets.each_with_index do |target, index|
16
- client = SSHScan::Client.new(target, port)
17
- client.connect()
18
- result.push(client.get_kex_result())
19
-
20
- fingerprint_md5 = nil
21
- fingerprint_sha1 = nil
22
- fingerprint_sha256 = nil
23
-
24
- # Connect and get results (Net-SSH)
25
- begin
26
- net_ssh_session = Net::SSH::Transport::Session.new(target, :port => port)
27
- auth_session = Net::SSH::Authentication::Session.new(net_ssh_session, :auth_methods => ["none"])
28
- auth_session.authenticate("none", "test", "test")
29
- result[index]['auth_methods'] = auth_session.allowed_auth_methods
30
- host_key = net_ssh_session.host_keys.first
31
- net_ssh_session.close
13
+ client = SSHScan::Client.new(target, port, timeout)
14
+ client.connect()
15
+ result = client.get_kex_result()
16
+ return result if result.include?(:error)
32
17
 
33
- #only supporting RSA for the moment
34
- if host_key.is_a?(OpenSSL::PKey::RSA)
35
- data_string = OpenSSL::ASN1::Sequence([
36
- OpenSSL::ASN1::Integer.new(host_key.public_key.n),
37
- OpenSSL::ASN1::Integer.new(host_key.public_key.e)
38
- ])
18
+ # Connect and get results (Net-SSH)
19
+ begin
20
+ net_ssh_session = Net::SSH::Transport::Session.new(target, :port => port, :timeout => timeout)
21
+ raise SSHScan::Error::ClosedConnection.new if net_ssh_session.closed?
22
+ auth_session = Net::SSH::Authentication::Session.new(net_ssh_session, :auth_methods => ["none"])
23
+ auth_session.authenticate("none", "test", "test")
24
+ result['auth_methods'] = auth_session.allowed_auth_methods
25
+ host_key = net_ssh_session.host_keys.first
26
+ net_ssh_session.close
27
+ rescue Net::SSH::ConnectionTimeout => e
28
+ warn("WARNING: net-ssh timed out attempting to connect to service (fingerprints and auth_methods will not be available)")
29
+ result['auth_methods'] = []
30
+ result['fingerprints'] = {}
31
+ result[:error] = e
32
+ result[:error] = SSHScan::Error::ConnectTimeout.new(e.message)
33
+ rescue Net::SSH::Disconnect => e
34
+ warn("WARNING: net-ssh disconnected unexpectedly (fingerprints and auth_methods will not be available)")
35
+ result['auth_methods'] = []
36
+ result['fingerprints'] = {}
37
+ result[:error] = e
38
+ result[:error] = SSHScan::Error::Disconnected.new(e.message)
39
+ rescue Net::SSH::Exception => e
40
+ if e.to_s.match(/could not settle on encryption_client algorithm/)
41
+ warn("WARNING: net-ssh could not find a mutually acceptable encryption algorithm (fingerprints and auth_methods will not be available)")
42
+ result['auth_methods'] = []
43
+ result['fingerprints'] = {}
44
+ result[:error] = e
45
+ elsif e.to_s.match(/could not settle on host_key algorithm/)
46
+ warn("WARNING: net-ssh could not find a mutually acceptable host_key algorithm (fingerprints and auth_methods will not be available)")
47
+ result['auth_methods'] = []
48
+ result['fingerprints'] = {}
49
+ result[:error] = e
50
+ else
51
+ raise e
52
+ end
53
+ else
54
+ #only supporting RSA for the moment
55
+ if host_key.is_a?(OpenSSL::PKey::RSA)
56
+ data_string = OpenSSL::ASN1::Sequence([
57
+ OpenSSL::ASN1::Integer.new(host_key.public_key.n),
58
+ OpenSSL::ASN1::Integer.new(host_key.public_key.e)
59
+ ])
39
60
 
40
- fingerprint_md5 = OpenSSL::Digest::MD5.hexdigest(data_string.to_der).scan(/../).join(':')
41
- fingerprint_sha1 = OpenSSL::Digest::SHA1.hexdigest(data_string.to_der).scan(/../).join(':')
42
- fingerprint_sha256 = OpenSSL::Digest::SHA256.hexdigest(data_string.to_der).scan(/../).join(':')
61
+ fingerprint_md5 = OpenSSL::Digest::MD5.hexdigest(data_string.to_der).scan(/../).join(':')
62
+ fingerprint_sha1 = OpenSSL::Digest::SHA1.hexdigest(data_string.to_der).scan(/../).join(':')
63
+ fingerprint_sha256 = OpenSSL::Digest::SHA256.hexdigest(data_string.to_der).scan(/../).join(':')
43
64
 
44
- result[index]['fingerprints'] = {
45
- "md5" => fingerprint_md5,
46
- "sha1" => fingerprint_sha1,
47
- "sha256" => fingerprint_sha256,
48
- }
49
- else
50
- warn("WARNING: Host key support for #{host_key.class} is not provided yet (fingerprints will not be available)")
51
- result[index]['fingerprints'] = {}
65
+ result['fingerprints'] = {
66
+ "md5" => fingerprint_md5,
67
+ "sha1" => fingerprint_sha1,
68
+ "sha256" => fingerprint_sha256,
69
+ }
70
+ # Do this only when no errors were reported
71
+ unless policy.nil?
72
+ policy_mgr = SSHScan::PolicyManager.new(result, policy)
73
+ result['compliance'] = policy_mgr.compliance_results
52
74
  end
75
+ else
76
+ warn("WARNING: Host key support for #{host_key.class} is not provided yet (fingerprints will not be available)")
77
+ result['fingerprints'] = {}
78
+ end
79
+ end
80
+ return result
81
+ end
53
82
 
83
+ def scan(opts)
84
+ targets = opts[:targets]
85
+ threads = opts[:threads] || 5
54
86
 
55
- rescue Net::SSH::Exception => e
56
- if e.to_s.match(/could not settle on encryption_client algorithm/)
57
- warn("WARNING: net-ssh could not find a mutually acceptable encryption algorithm (fingerprints and auth_methods will not be available)")
58
- result[index]['auth_methods'] = []
59
- result[index]['fingerprints'] = {}
60
- elsif e.to_s.match(/could not settle on host_key algorithm/)
61
- warn("WARNING: net-ssh could not find a mutually acceptable host_key algorithm (fingerprints and auth_methods will not be available)")
62
- result[index]['auth_methods'] = []
63
- result[index]['fingerprints'] = {}
64
- else
65
- raise e
66
- end
67
- end
87
+ results = []
68
88
 
69
- # If policy defined, then add compliance results
70
- unless policy.nil?
71
- policy_mgr = SSHScan::PolicyManager.new(result[index], policy)
72
- result[index]['compliance'] = policy_mgr.compliance_results
89
+ work_queue = Queue.new
90
+ targets.each {|x| work_queue.push x }
91
+ workers = (0...threads).map do |worker_num|
92
+ Thread.new do
93
+ begin
94
+ while target = work_queue.pop(true)
95
+ results << scan_target(target, opts)
96
+ end
97
+ rescue ThreadError => e
98
+ raise e unless e.to_s.match(/queue empty/)
99
+ end
73
100
  end
74
101
  end
75
- return result
102
+ workers.map(&:join)
103
+
104
+ return results
76
105
  end
77
106
  end
78
107
  end
@@ -0,0 +1,29 @@
1
+ require 'netaddr'
2
+ require 'string_ext'
3
+
4
+ module SSHScan
5
+ class TargetParser
6
+ def enumerateIPRange(ip)
7
+ if ip.fqdn?
8
+ return [ip]
9
+ else
10
+ if ip.include? "-"
11
+ octets = ip.split('.')
12
+ range = octets.pop.split('-')
13
+ lower = NetAddr::CIDR.create(octets.join('.') + "." + range[0])
14
+ upper = NetAddr::CIDR.create(octets.join('.') + "." + range[1])
15
+ ip_array = NetAddr.range(lower, upper,:Inclusive => true)
16
+ return ip_array
17
+ elsif ip.include? "/"
18
+ cidr = NetAddr::CIDR.create(ip)
19
+ ip_array = cidr.enumerate
20
+ ip_array.delete(cidr.network)
21
+ ip_array.delete(cidr.last)
22
+ return ip_array
23
+ else
24
+ return [ip]
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,3 +1,3 @@
1
1
  module SSHScan
2
- VERSION = '0.0.10.beta.2'
2
+ VERSION = '0.0.10'
3
3
  end
data/lib/ssh_scan.rb CHANGED
@@ -8,6 +8,7 @@ require 'ssh_scan/policy'
8
8
  require 'ssh_scan/policy_manager'
9
9
  require 'ssh_scan/protocol'
10
10
  require 'ssh_scan/scan_engine'
11
+ require 'ssh_scan/target_parser'
11
12
 
12
13
  #Monkey Patches
13
14
  require 'string_ext'
@@ -12,3 +12,5 @@ macs:
12
12
  compression:
13
13
  - none
14
14
  - zlib@openssh.com
15
+ references:
16
+ - https://wiki.mozilla.org/Security/Guidelines/OpenSSH
@@ -23,3 +23,5 @@ macs:
23
23
  compression:
24
24
  - none
25
25
  - zlib@openssh.com
26
+ references:
27
+ - https://wiki.mozilla.org/Security/Guidelines/OpenSSH
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('net-ssh')
31
31
  s.add_dependency('netaddr')
32
+ s.add_dependency('timeout')
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,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ssh_scan
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10.beta.2
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Claudius
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-17 00:00:00.000000000 Z
11
+ date: 2016-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bindata
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: timeout
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: pry
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -128,6 +142,11 @@ files:
128
142
  - lib/ssh_scan/basic_server.rb
129
143
  - lib/ssh_scan/client.rb
130
144
  - lib/ssh_scan/constants.rb
145
+ - lib/ssh_scan/error.rb
146
+ - lib/ssh_scan/error/closed_connection.rb
147
+ - lib/ssh_scan/error/connect_timeout.rb
148
+ - lib/ssh_scan/error/connection_refused.rb
149
+ - lib/ssh_scan/error/disconnected.rb
131
150
  - lib/ssh_scan/os.rb
132
151
  - lib/ssh_scan/os/centos.rb
133
152
  - lib/ssh_scan/os/debian.rb
@@ -144,6 +163,7 @@ files:
144
163
  - lib/ssh_scan/ssh_lib/libssh.rb
145
164
  - lib/ssh_scan/ssh_lib/openssh.rb
146
165
  - lib/ssh_scan/ssh_lib/unknown.rb
166
+ - lib/ssh_scan/target_parser.rb
147
167
  - lib/ssh_scan/version.rb
148
168
  - lib/string_ext.rb
149
169
  - policies/mozilla_intermediate.yml
@@ -164,9 +184,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
164
184
  version: '0'
165
185
  required_rubygems_version: !ruby/object:Gem::Requirement
166
186
  requirements:
167
- - - ">"
187
+ - - ">="
168
188
  - !ruby/object:Gem::Version
169
- version: 1.3.1
189
+ version: '0'
170
190
  requirements: []
171
191
  rubyforge_project:
172
192
  rubygems_version: 2.6.2