ssh_scan 0.0.10.beta.2 → 0.0.10

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: 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