ssh_scan 0.0.16 → 0.0.17.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +15 -1
- data/.travis.yml +2 -0
- data/Gemfile +1 -0
- data/README.md +35 -33
- data/Rakefile +40 -16
- data/bin/ssh_scan +91 -53
- data/bin/ssh_scan_worker +14 -0
- data/lib/ssh_scan.rb +0 -1
- data/lib/ssh_scan/client.rb +10 -4
- data/lib/ssh_scan/constants.rb +67 -18
- data/lib/ssh_scan/crypto.rb +3 -18
- data/lib/ssh_scan/error/closed_connection.rb +1 -1
- data/lib/ssh_scan/error/connect_timeout.rb +1 -1
- data/lib/ssh_scan/error/connection_refused.rb +1 -1
- data/lib/ssh_scan/error/disconnected.rb +1 -1
- data/lib/ssh_scan/error/no_banner.rb +1 -1
- data/lib/ssh_scan/error/no_kex_response.rb +1 -1
- data/lib/ssh_scan/os/raspbian.rb +2 -4
- data/lib/ssh_scan/os/ubuntu.rb +103 -58
- data/lib/ssh_scan/policy.rb +2 -1
- data/lib/ssh_scan/policy_manager.rb +67 -18
- data/lib/ssh_scan/protocol.rb +53 -21
- data/lib/ssh_scan/scan_engine.rb +78 -44
- data/lib/ssh_scan/ssh_lib/dropbear.rb +2 -4
- data/lib/ssh_scan/target_parser.rb +3 -3
- data/lib/ssh_scan/update.rb +3 -3
- data/lib/ssh_scan/version.rb +1 -2
- data/lib/ssh_scan/worker.rb +119 -0
- data/lib/string_ext.rb +2 -1
- data/ssh_scan.gemspec +4 -8
- metadata +28 -96
- data/bin/ssh_scan_api +0 -36
- data/lib/ssh_scan/api.rb +0 -124
- data/lib/ssh_scan/fingerprint_database.rb +0 -39
- data/policies/mozilla_intermediate.yml +0 -19
- data/policies/mozilla_modern.yml +0 -30
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 377880ac09b5bd925aeb32066409dd9e4c8edc7e
|
4
|
+
data.tar.gz: c3b70dcfae67ffd84ddf0d028c67486bbf71256e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16055032c71dda26d38356da8622cd827fd6fd5dd6409325b6f66af1d38c80dff0a80e86f0416807da6663e0d2dfe7472c2f78db178a766434517e46121d67f0
|
7
|
+
data.tar.gz: 913c4870b8768f85c7ada637c76060ddc045dc64e53ef1dc8d52d717a3743b52b93793d518b55b8f55056b9eafc8501443d6514cf6c63567f9c850a4a12a348d
|
data/.gitignore
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
*.gem
|
2
2
|
*.rbc
|
3
3
|
*.db
|
4
|
+
*.key
|
5
|
+
*.crt
|
6
|
+
*.cert
|
4
7
|
/.config
|
5
8
|
/coverage/
|
6
9
|
/InstalledFiles
|
@@ -29,10 +32,21 @@ build/
|
|
29
32
|
|
30
33
|
# for a library or gem, you might want to ignore these files since the code is
|
31
34
|
# intended to run in multiple environments; otherwise, check them in:
|
32
|
-
|
35
|
+
Gemfile.lock
|
33
36
|
# .ruby-version
|
34
37
|
# .ruby-gemset
|
35
38
|
|
36
39
|
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
37
40
|
.rvmrc
|
38
41
|
gh-pages/
|
42
|
+
|
43
|
+
# https ssl certificates
|
44
|
+
cert.pem
|
45
|
+
key.pem
|
46
|
+
|
47
|
+
# API Database
|
48
|
+
#ssh_scan
|
49
|
+
|
50
|
+
# Config files
|
51
|
+
bin/ssh_scan_api_example_config.yml
|
52
|
+
bin/ssh_scan_worker_example_config.yml
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
[![Code Climate](https://codeclimate.com/github/mozilla/ssh_scan.png)](https://codeclimate.com/github/mozilla/ssh_scan)
|
5
5
|
[![Gem Version](https://badge.fury.io/rb/ssh_scan.svg)](https://badge.fury.io/rb/ssh_scan)
|
6
6
|
[![Join the chat at https://gitter.im/mozilla-ssh_scan/Lobby](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mozilla-ssh_scan/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
7
|
-
|
7
|
+
[![Coverage Status](https://coveralls.io/repos/github/mozilla/ssh_scan/badge.svg?branch=master)](https://coveralls.io/github/mozilla/ssh_scan?branch=master)
|
8
8
|
|
9
9
|
A SSH configuration and policy scanner
|
10
10
|
|
@@ -59,38 +59,40 @@ bundle install
|
|
59
59
|
|
60
60
|
Run `ssh_scan -h` to get this
|
61
61
|
|
62
|
-
ssh_scan v0.0.
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
62
|
+
ssh_scan v0.0.17 (https://github.com/mozilla/ssh_scan)
|
63
|
+
|
64
|
+
Usage: ssh_scan [options]
|
65
|
+
-t, --target [IP/Range/Hostname] IP/Ranges/Hostname to scan
|
66
|
+
-f, --file [FilePath] File Path of the file containing IP/Range/Hostnames to scan
|
67
|
+
-T, --timeout [seconds] Timeout per connect after which ssh_scan gives up on the host
|
68
|
+
-L, --logger [Log File Path] Enable logger
|
69
|
+
-O, --from_json [FilePath] File to read JSON output from
|
70
|
+
-o, --output [FilePath] File to write JSON output to
|
71
|
+
-p, --port [PORT] Port (Default: 22)
|
72
|
+
-P, --policy [FILE] Custom policy file (Default: Mozilla Modern)
|
73
|
+
--threads [NUMBER] Number of worker threads (Default: 5)
|
74
|
+
--fingerprint-db [FILE] File location of fingerprint database (Default: ./fingerprints.db)
|
75
|
+
--suppress-update-status Do not check for updates
|
76
|
+
-u, --unit-test [FILE] Throw appropriate exit codes based on compliance status
|
77
|
+
-V [STD_LOGGING_LEVEL], File to write JSON output to
|
78
|
+
--verbosity
|
79
|
+
-v, --version Display just version info
|
80
|
+
-l, --listen Listen and serve API requests
|
81
|
+
-h, --help Show this message
|
82
|
+
|
83
|
+
Examples:
|
84
|
+
|
85
|
+
ssh_scan -t 192.168.1.1
|
86
|
+
ssh_scan -t server.example.com
|
87
|
+
ssh_scan -t ::1
|
88
|
+
ssh_scan -t ::1 -T 5
|
89
|
+
ssh_scan -f hosts.txt
|
90
|
+
ssh_scan -o output.json
|
91
|
+
ssh_scan -O output.json -o rescan_output.json
|
92
|
+
ssh_scan -t 192.168.1.1 -p 22222
|
93
|
+
ssh_scan -t 192.168.1.1 -p 22222 -L output.log -V INFO
|
94
|
+
ssh_scan -t 192.168.1.1 -P custom_policy.yml
|
95
|
+
ssh_scan -t 192.168.1.1 --unit-test -P custom_policy.yml
|
94
96
|
|
95
97
|
- See here for [example video](https://asciinema.org/a/7pliiw5zqhj7eqvz7q437u6vx)
|
96
98
|
- See here for [example output](https://github.com/mozilla/ssh_scan/blob/master/examples/192.168.1.1.json)
|
data/Rakefile
CHANGED
@@ -22,14 +22,20 @@ TRAVELING_RUBY_VERSION = "20150210-2.1.5"
|
|
22
22
|
SQLITE3_VERSION = "1.3.9" # Must match Gemfile
|
23
23
|
|
24
24
|
desc "Package your app"
|
25
|
-
task :package => [
|
25
|
+
task :package => [
|
26
|
+
'package:linux:x86',
|
27
|
+
'package:linux:x86_64',
|
28
|
+
'package:osx',
|
29
|
+
'package:win32'
|
30
|
+
]
|
26
31
|
|
27
32
|
namespace :package do
|
28
33
|
namespace :linux do
|
29
34
|
desc "Package your app for Linux x86"
|
30
35
|
task :x86 => [:bundle_install,
|
31
36
|
"packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-linux-x86.tar.gz",
|
32
|
-
"packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-linux-x86-sqlite3
|
37
|
+
"packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-linux-x86-sqlite3\
|
38
|
+
-#{SQLITE3_VERSION}.tar.gz"
|
33
39
|
] do
|
34
40
|
create_package("linux-x86")
|
35
41
|
end
|
@@ -37,7 +43,8 @@ namespace :package do
|
|
37
43
|
desc "Package your app for Linux x86_64"
|
38
44
|
task :x86_64 => [:bundle_install,
|
39
45
|
"packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-linux-x86_64.tar.gz",
|
40
|
-
"packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-linux-x86_64-sqlite3
|
46
|
+
"packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-linux-x86_64-sqlite3\
|
47
|
+
-#{SQLITE3_VERSION}.tar.gz"
|
41
48
|
] do
|
42
49
|
create_package("linux-x86_64")
|
43
50
|
end
|
@@ -46,20 +53,23 @@ namespace :package do
|
|
46
53
|
desc "Package your app for OS X"
|
47
54
|
task :osx => [:bundle_install,
|
48
55
|
"packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-osx.tar.gz",
|
49
|
-
"packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-osx-sqlite3
|
56
|
+
"packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-osx-sqlite3\
|
57
|
+
-#{SQLITE3_VERSION}.tar.gz"
|
50
58
|
] do
|
51
59
|
create_package("osx")
|
52
60
|
end
|
53
61
|
|
54
62
|
desc "Package your app for Windows x86"
|
55
|
-
task :win32 => [:bundle_install, "packaging/traveling-ruby
|
63
|
+
task :win32 => [:bundle_install, "packaging/traveling-ruby\
|
64
|
+
-#{TRAVELING_RUBY_VERSION}-win32.tar.gz"] do
|
56
65
|
create_package("win32", :windows)
|
57
66
|
end
|
58
67
|
|
59
68
|
desc "Install gems to local directory"
|
60
69
|
task :bundle_install do
|
61
70
|
if RUBY_VERSION !~ /^2\.3\./
|
62
|
-
abort "You can only 'bundle install' using Ruby 2.3, because
|
71
|
+
abort "You can only 'bundle install' using Ruby 2.3, because \
|
72
|
+
that's what Traveling Ruby uses."
|
63
73
|
end
|
64
74
|
sh "rm -rf packaging/tmp"
|
65
75
|
sh "mkdir packaging/tmp"
|
@@ -69,7 +79,8 @@ namespace :package do
|
|
69
79
|
sh "cp -R bin/* packaging/tmp/bin"
|
70
80
|
sh "cp Gemfile Gemfile.lock #{PACKAGE_NAME}.gemspec packaging/tmp/"
|
71
81
|
Bundler.with_clean_env do
|
72
|
-
sh "cd packaging/tmp && env BUNDLE_IGNORE_CONFIG=1 bundle install
|
82
|
+
sh "cd packaging/tmp && env BUNDLE_IGNORE_CONFIG=1 bundle install \
|
83
|
+
--path ../vendor --without development"
|
73
84
|
end
|
74
85
|
sh "rm -rf packaging/tmp"
|
75
86
|
sh "rm -f packaging/vendor/*/*/cache/*"
|
@@ -96,15 +107,18 @@ file "packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-win32.tar.gz" do
|
|
96
107
|
download_runtime("win32")
|
97
108
|
end
|
98
109
|
|
99
|
-
file "packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-linux-x86-sqlite3
|
110
|
+
file "packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-linux-x86-sqlite3\
|
111
|
+
-#{SQLITE3_VERSION}.tar.gz" do
|
100
112
|
download_native_extension("linux-x86", "sqlite3-#{SQLITE3_VERSION}")
|
101
113
|
end
|
102
114
|
|
103
|
-
file "packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-linux-x86_64-sqlite3
|
115
|
+
file "packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-linux-x86_64-sqlite3\
|
116
|
+
-#{SQLITE3_VERSION}.tar.gz" do
|
104
117
|
download_native_extension("linux-x86_64", "sqlite3-#{SQLITE3_VERSION}")
|
105
118
|
end
|
106
119
|
|
107
|
-
file "packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-osx-sqlite3
|
120
|
+
file "packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-osx-sqlite3\
|
121
|
+
-#{SQLITE3_VERSION}.tar.gz" do
|
108
122
|
download_native_extension("osx", "sqlite3-#{SQLITE3_VERSION}")
|
109
123
|
end
|
110
124
|
|
@@ -115,7 +129,8 @@ def create_package(target, os_type = :unix)
|
|
115
129
|
sh "mkdir -p #{package_dir}/lib/app"
|
116
130
|
sh "cp bin/#{PACKAGE_NAME} #{package_dir}/lib/app/"
|
117
131
|
sh "mkdir #{package_dir}/lib/ruby"
|
118
|
-
sh "tar -xzf packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-#{target}
|
132
|
+
sh "tar -xzf packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-#{target}\
|
133
|
+
.tar.gz -C #{package_dir}/lib/ruby"
|
119
134
|
if os_type == :unix
|
120
135
|
sh "cp packaging/wrapper.sh #{package_dir}/#{PACKAGE_NAME}"
|
121
136
|
else
|
@@ -127,8 +142,14 @@ def create_package(target, os_type = :unix)
|
|
127
142
|
sh "cp Gemfile Gemfile.lock #{PACKAGE_NAME}.gemspec #{package_dir}/lib/vendor/"
|
128
143
|
sh "mkdir #{package_dir}/lib/vendor/.bundle"
|
129
144
|
sh "cp packaging/bundler-config #{package_dir}/lib/vendor/.bundle/config"
|
130
|
-
|
131
|
-
"-
|
145
|
+
if os_type == :unix
|
146
|
+
sh "tar -xzf packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-#{target}-\
|
147
|
+
sqlite3-#{SQLITE3_VERSION}.tar.gz " +
|
148
|
+
"-C #{package_dir}/lib/vendor/ruby"
|
149
|
+
else
|
150
|
+
sh "tar -xzf packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}-#{target}\
|
151
|
+
.tar.gz " + "-C #{package_dir}/lib/vendor/ruby"
|
152
|
+
end
|
132
153
|
if !ENV['DIR_ONLY']
|
133
154
|
if os_type == :unix
|
134
155
|
sh "tar -czf #{package_dir}.tar.gz #{package_dir}"
|
@@ -142,10 +163,13 @@ end
|
|
142
163
|
|
143
164
|
def download_runtime(target)
|
144
165
|
sh "cd packaging && curl -L -O --fail " +
|
145
|
-
"https://d6r77u77i8pq3.cloudfront.net/releases/traveling-ruby
|
166
|
+
"https://d6r77u77i8pq3.cloudfront.net/releases/traveling-ruby-\
|
167
|
+
#{TRAVELING_RUBY_VERSION}-#{target}.tar.gz"
|
146
168
|
end
|
147
169
|
|
148
170
|
def download_native_extension(target, gem_name_and_version)
|
149
|
-
sh "curl -L --fail -o packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}
|
150
|
-
|
171
|
+
sh "curl -L --fail -o packaging/traveling-ruby-#{TRAVELING_RUBY_VERSION}\
|
172
|
+
-#{target}-#{gem_name_and_version}.tar.gz " +
|
173
|
+
"https://d6r77u77i8pq3.cloudfront.net/releases/traveling-ruby-gems-\
|
174
|
+
#{TRAVELING_RUBY_VERSION}-#{target}/#{gem_name_and_version}.tar.gz"
|
151
175
|
end
|
data/bin/ssh_scan
CHANGED
@@ -11,61 +11,83 @@ require 'logger'
|
|
11
11
|
|
12
12
|
#Default options
|
13
13
|
options = {
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
14
|
+
"sockets" => [],
|
15
|
+
"policy" => File.join(Dir.pwd, '/config/policies/mozilla_modern.yml'),
|
16
|
+
"unit_test" => false,
|
17
|
+
"timeout" => 2,
|
18
|
+
"threads" => 5,
|
19
|
+
"verbosity" => nil,
|
20
|
+
"logger" => Logger.new(STDERR),
|
21
|
+
"fingerprint_database" => "./fingerprints.db"
|
22
22
|
}
|
23
23
|
|
24
|
+
# Reorder arguments before parsing
|
25
|
+
def reorder_args!(order, opt_parser)
|
26
|
+
old_args = opt_parser.default_argv
|
27
|
+
new_args = []
|
28
|
+
len = opt_parser.default_argv.length
|
29
|
+
order.each do |next_keyset|
|
30
|
+
i = 0
|
31
|
+
(0...len).each do
|
32
|
+
if next_keyset.include?(opt_parser.default_argv[i])
|
33
|
+
new_args << old_args.delete_at(i) << old_args.delete_at(i)
|
34
|
+
else
|
35
|
+
i += 1
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
new_args += old_args
|
40
|
+
opt_parser.default_argv = new_args
|
41
|
+
end
|
42
|
+
|
24
43
|
target_parser = SSHScan::TargetParser.new()
|
25
44
|
|
26
45
|
opt_parser = OptionParser.new do |opts|
|
27
|
-
opts.banner =
|
28
|
-
|
46
|
+
opts.banner =
|
47
|
+
"ssh_scan v#{SSHScan::VERSION} (https://github.com/mozilla/ssh_scan)\n\n\
|
48
|
+
Usage: ssh_scan [options]"
|
29
49
|
|
30
50
|
opts.on("-t", "--target [IP/Range/Hostname]", Array,
|
31
51
|
"IP/Ranges/Hostname to scan") do |sockets|
|
32
52
|
sockets.each do |socket|
|
33
53
|
ip, port = socket.chomp.split(':')
|
34
|
-
options[
|
54
|
+
options["sockets"] += target_parser.enumerateIPRange(ip, port)
|
35
55
|
end
|
36
56
|
end
|
37
57
|
|
38
58
|
opts.on("-f", "--file [FilePath]",
|
39
|
-
"File Path of the file containing IP/Range/Hostnames to
|
40
|
-
|
59
|
+
"File Path of the file containing IP/Range/Hostnames to \
|
60
|
+
scan") do |file|
|
61
|
+
unless File.exist?(file)
|
41
62
|
puts "\nReason: input file supplied is not a file"
|
42
63
|
exit
|
43
64
|
end
|
44
65
|
File.open(file).each do |line|
|
45
66
|
line.chomp.split(',').each do |socket|
|
46
67
|
ip, port = socket.chomp.split(':')
|
47
|
-
options[
|
68
|
+
options["sockets"] += target_parser.enumerateIPRange(ip, port)
|
48
69
|
end
|
49
70
|
end
|
50
71
|
end
|
51
72
|
|
52
73
|
opts.on("-T", "--timeout [seconds]",
|
53
|
-
"Timeout per connect after which ssh_scan gives up on the
|
54
|
-
|
74
|
+
"Timeout per connect after which ssh_scan gives up on the\
|
75
|
+
host") do |timeout|
|
76
|
+
options["timeout"] = timeout.to_i
|
55
77
|
end
|
56
78
|
|
57
79
|
opts.on("-L", "--logger [Log File Path]",
|
58
80
|
"Enable logger") do |log_file|
|
59
81
|
if log_file.nil?
|
60
|
-
options[
|
82
|
+
options["logger"] = Logger.new(STDERR)
|
61
83
|
else
|
62
|
-
options[
|
84
|
+
options["logger"] = Logger.new $stdout.reopen(log_file, "w")
|
63
85
|
end
|
64
86
|
end
|
65
87
|
|
66
88
|
opts.on("-O", "--from_json [FilePath]",
|
67
89
|
"File to read JSON output from") do |file|
|
68
|
-
unless File.
|
90
|
+
unless File.exist?(file)
|
69
91
|
puts "\nReason: Invalid file"
|
70
92
|
exit
|
71
93
|
end
|
@@ -73,7 +95,10 @@ opt_parser = OptionParser.new do |opts|
|
|
73
95
|
json = file.read
|
74
96
|
parsed_json = JSON.parse(json)
|
75
97
|
parsed_json.each do |host|
|
76
|
-
options[
|
98
|
+
options["sockets"] += target_parser.enumerateIPRange(
|
99
|
+
host['ip'],
|
100
|
+
host['port']
|
101
|
+
)
|
77
102
|
end
|
78
103
|
end
|
79
104
|
|
@@ -85,54 +110,61 @@ opt_parser = OptionParser.new do |opts|
|
|
85
110
|
opts.on("-p", "--port [PORT]", Array,
|
86
111
|
"Port (Default: 22)") do |ports|
|
87
112
|
temp = []
|
88
|
-
options[
|
113
|
+
options["sockets"].each do |socket|
|
89
114
|
ports.each do |port|
|
90
115
|
ip, old_port = socket.chomp.split(':')
|
91
116
|
if !old_port.nil?
|
92
|
-
puts "Specifying port simultaneously with -t and -p is not
|
117
|
+
puts "Specifying port simultaneously with -t and -p is not\
|
118
|
+
allowed. Please fix this and try again"
|
93
119
|
exit 1
|
94
120
|
end
|
95
121
|
temp += target_parser.enumerateIPRange(ip, port)
|
96
122
|
end
|
97
123
|
end
|
98
|
-
options[
|
124
|
+
options["sockets"] = temp
|
99
125
|
end
|
100
126
|
|
101
127
|
opts.on("-P", "--policy [FILE]",
|
102
128
|
"Custom policy file (Default: Mozilla Modern)") do |policy|
|
103
|
-
options[
|
129
|
+
options["policy"] = policy
|
104
130
|
end
|
105
131
|
|
106
132
|
opts.on("--threads [NUMBER]",
|
107
133
|
"Number of worker threads (Default: 5)") do |threads|
|
108
|
-
options[
|
134
|
+
options["threads"] = threads.to_i
|
109
135
|
end
|
110
136
|
|
111
137
|
opts.on("--fingerprint-db [FILE]",
|
112
|
-
"File location of fingerprint database (Default:
|
113
|
-
|
138
|
+
"File location of fingerprint database (Default: \
|
139
|
+
./fingerprints.db)") do |fingerprint_db|
|
140
|
+
options["fingerprint_database"] = fingerprint_db
|
114
141
|
end
|
115
142
|
|
116
143
|
opts.on("--suppress-update-status", "Do not check for updates") do
|
117
|
-
options[
|
144
|
+
options["suppress_update_status"] = true
|
118
145
|
end
|
119
146
|
|
120
147
|
opts.on("-u", "--unit-test [FILE]",
|
121
148
|
"Throw appropriate exit codes based on compliance status") do
|
122
|
-
options[
|
149
|
+
options["unit_test"] = true
|
123
150
|
end
|
124
151
|
|
125
|
-
opts.on("-V", "--verbosity",
|
126
|
-
"
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
152
|
+
opts.on("-V", "--verbosity [STD_LOGGING_LEVEL]",
|
153
|
+
"File to write JSON output to") do |verb|
|
154
|
+
case verb
|
155
|
+
when "INFO"
|
156
|
+
options["logger"].level == Logger::INFO
|
157
|
+
when "WARN"
|
158
|
+
options["logger"].level == Logger::WARN
|
159
|
+
when "DEBUG"
|
160
|
+
options["logger"].level == Logger::DEBUG
|
161
|
+
when "ERROR"
|
162
|
+
options["logger"].level == Logger::ERROR
|
163
|
+
when "FATAL"
|
164
|
+
options["logger"].level == Logger::FATAL
|
165
|
+
else
|
166
|
+
options["logger"].fatal("Unrecognized logging verbosity level #{verb}")
|
167
|
+
exit 1
|
136
168
|
end
|
137
169
|
end
|
138
170
|
|
@@ -166,16 +198,17 @@ opt_parser = OptionParser.new do |opts|
|
|
166
198
|
end
|
167
199
|
end
|
168
200
|
|
201
|
+
reorder_args!([["-t", "--target"], ["-p", "--port"]], opt_parser)
|
169
202
|
opt_parser.parse!
|
170
203
|
|
171
|
-
if options[
|
204
|
+
if options["sockets"].nil?
|
172
205
|
puts opt_parser.help
|
173
206
|
puts "\nReason: no target specified"
|
174
207
|
exit 1
|
175
208
|
end
|
176
209
|
|
177
|
-
options[
|
178
|
-
ip
|
210
|
+
options["sockets"].each do |socket|
|
211
|
+
ip = socket.chomp.split(':')[0]
|
179
212
|
unless ip.ip_addr? || ip.fqdn?
|
180
213
|
puts opt_parser.help
|
181
214
|
puts "\nReason: #{socket} is not a valid target"
|
@@ -183,8 +216,8 @@ options[:sockets].each do |socket|
|
|
183
216
|
end
|
184
217
|
end
|
185
218
|
|
186
|
-
options[
|
187
|
-
|
219
|
+
options["sockets"].each do |socket|
|
220
|
+
port = socket.chomp.split(':')[1]
|
188
221
|
unless (0..65535).include?(port.to_i)
|
189
222
|
puts opt_parser.help
|
190
223
|
puts "\nReason: port supplied is not within acceptable range"
|
@@ -192,29 +225,34 @@ options[:sockets].each do |socket|
|
|
192
225
|
end
|
193
226
|
end
|
194
227
|
|
195
|
-
unless File.
|
228
|
+
unless File.exist?(options["policy"])
|
196
229
|
puts opt_parser.help
|
197
230
|
puts "\nReason: policy file supplied is not a file"
|
198
231
|
exit 1
|
199
232
|
end
|
200
233
|
|
201
234
|
# Check to see if we're running the latest released version
|
202
|
-
if !options[
|
235
|
+
if !options["suppress_update_status"]
|
203
236
|
update = SSHScan::Update.new
|
204
237
|
if update.newer_gem_available?
|
205
|
-
options[
|
238
|
+
options["logger"].warn(
|
239
|
+
"You're NOT using the latest version of ssh_scan, try 'gem update \
|
240
|
+
ssh_scan' to get the latest"
|
241
|
+
)
|
206
242
|
else
|
207
|
-
if update.errors.
|
243
|
+
if update.errors.any?
|
208
244
|
update.errors.each do |error|
|
209
|
-
options[
|
245
|
+
options["logger"].error(error)
|
210
246
|
end
|
211
247
|
else
|
212
|
-
options[
|
248
|
+
options["logger"].info(
|
249
|
+
"You're using the latest version of ssh_scan #{SSHScan::VERSION}"
|
250
|
+
)
|
213
251
|
end
|
214
252
|
end
|
215
253
|
end
|
216
254
|
|
217
|
-
options[
|
255
|
+
options["policy_file"] = SSHScan::Policy.from_file(options["policy"])
|
218
256
|
|
219
257
|
# Perform scan and get results
|
220
258
|
scan_engine = SSHScan::ScanEngine.new()
|
@@ -222,7 +260,7 @@ results = scan_engine.scan(options)
|
|
222
260
|
|
223
261
|
puts JSON.pretty_generate(results)
|
224
262
|
|
225
|
-
if options[
|
263
|
+
if options["unit_test"] == true
|
226
264
|
results.each do |result|
|
227
265
|
if result["compliance"] &&
|
228
266
|
result["compliance"][:compliant] == false
|