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 +4 -4
- data/.travis.yml +14 -0
- data/README.md +14 -3
- data/bin/ssh_scan +33 -16
- data/lib/ssh_scan/client.rb +28 -10
- data/lib/ssh_scan/error/closed_connection.rb +9 -0
- data/lib/ssh_scan/error/connect_timeout.rb +12 -0
- data/lib/ssh_scan/error/connection_refused.rb +12 -0
- data/lib/ssh_scan/error/disconnected.rb +12 -0
- data/lib/ssh_scan/error.rb +4 -0
- data/lib/ssh_scan/policy.rb +2 -1
- data/lib/ssh_scan/policy_manager.rb +2 -1
- data/lib/ssh_scan/scan_engine.rb +85 -56
- data/lib/ssh_scan/target_parser.rb +29 -0
- data/lib/ssh_scan/version.rb +1 -1
- data/lib/ssh_scan.rb +1 -0
- data/policies/mozilla_intermediate.yml +2 -0
- data/policies/mozilla_modern.yml +2 -0
- data/ssh_scan.gemspec +1 -0
- metadata +24 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6403790d58c64fd35088e7052eb051074a153b48
|
4
|
+
data.tar.gz: 8ca8d5eaa79005c5479719672f55c44bbd806b58
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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.
|
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
|
-
|
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
|
-
|
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
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
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
|
data/lib/ssh_scan/client.rb
CHANGED
@@ -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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
data/lib/ssh_scan/policy.rb
CHANGED
@@ -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)
|
data/lib/ssh_scan/scan_engine.rb
CHANGED
@@ -5,74 +5,103 @@ require 'net/ssh'
|
|
5
5
|
module SSHScan
|
6
6
|
class ScanEngine
|
7
7
|
|
8
|
-
def
|
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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|
-
|
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
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
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
|
-
|
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
|
data/lib/ssh_scan/version.rb
CHANGED
data/lib/ssh_scan.rb
CHANGED
data/policies/mozilla_modern.yml
CHANGED
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
|
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-
|
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:
|
189
|
+
version: '0'
|
170
190
|
requirements: []
|
171
191
|
rubyforge_project:
|
172
192
|
rubygems_version: 2.6.2
|