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