ssh_scan 0.0.38 → 0.0.43
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +3 -3
- data/README.md +2 -2
- data/bin/ssh_scan +19 -4
- data/config/policies/just_etm_macs.yaml +24 -0
- data/lib/ssh_scan/client.rb +3 -0
- data/lib/ssh_scan/public_key.rb +64 -0
- data/lib/ssh_scan/result.rb +16 -7
- data/lib/ssh_scan/scan_engine.rb +36 -35
- data/lib/ssh_scan/ssh_fp.rb +47 -0
- data/lib/ssh_scan/version.rb +1 -1
- data/lib/string_ext.rb +25 -0
- data/ssh_scan.gemspec +1 -1
- metadata +7 -5
- data/lib/ssh_scan/crypto.rb +0 -60
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 035ffcd050babf1ef147195f6981a84a331e41d6929479a13383692b7148261f
|
4
|
+
data.tar.gz: 5354ffacae2dcf14ecc9a8ebe640baf96cf450ed08ad18dd0fb0bafe818131af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a859e1d12f2c6479f15d8e34a2b71c6d040f6d7913ef7d661209ad902f73b901c2fb79f439656d68e43275b57db41e10a7f9d0aa939404e5978dc2067cde124
|
7
|
+
data.tar.gz: 596a3102e97a68d74ebe0d698eeaef1687229e896a44fd7152241b658d0f7a6b28c5a9dd1b94e31215b52ebf1ad3179b4a0a614f97cfde9b8f4f7b460c9cf714
|
data/CONTRIBUTING.md
CHANGED
@@ -27,9 +27,9 @@ inclusion, but sending a pull request is much more awesome.
|
|
27
27
|
|
28
28
|
If you want your pull requests to be accepted, please follow the following guidelines:
|
29
29
|
|
30
|
-
- [**Add tests!**](
|
30
|
+
- [**Add tests!**](https://rspec.info/) Your patch won't be accepted (or will be delayed) if it doesn't have tests.
|
31
31
|
|
32
|
-
- [**Document any change in behaviour**](
|
32
|
+
- [**Document any change in behaviour**](https://yardoc.org/) Make sure the README and any other
|
33
33
|
relevant documentation are kept up-to-date.
|
34
34
|
|
35
35
|
- [**Create topic branches**](https://github.com/dchelimsky/rspec/wiki/Topic-Branches) Don't ask us to pull from your master branch.
|
@@ -37,7 +37,7 @@ If you want your pull requests to be accepted, please follow the following guide
|
|
37
37
|
- [**One pull request per feature**](https://help.github.com/articles/using-pull-requests) If you want to do more than one thing, send
|
38
38
|
multiple pull requests.
|
39
39
|
|
40
|
-
- [**Send coherent history**](
|
40
|
+
- [**Send coherent history**](https://stackoverflow.com/questions/6934752/git-combining-multiple-commits-before-pushing) Make sure each individual commit in your pull
|
41
41
|
request is meaningful. If you had to make multiple intermediate commits while
|
42
42
|
developing, please squash them before sending them to us.
|
43
43
|
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@ A SSH configuration and policy scanner
|
|
9
9
|
|
10
10
|
## Key Benefits
|
11
11
|
|
12
|
-
- **Minimal
|
12
|
+
- **Minimal Dependencies** - Uses native Ruby and BinData to do its work, no heavy dependencies.
|
13
13
|
- **Not Just a Script** - Implementation is portable for use in another project or for automation of tasks.
|
14
14
|
- **Simple** - Just point `ssh_scan` at an SSH service and get a JSON report of what it supports and its policy status.
|
15
15
|
- **Configurable** - Make your own custom policies that fit your unique policy requirements.
|
@@ -89,7 +89,7 @@ Examples:
|
|
89
89
|
|
90
90
|
## ssh_scan as a service/api?
|
91
91
|
|
92
|
-
This project is
|
92
|
+
This project is solely for ssh_scan engine/command-line usage.
|
93
93
|
|
94
94
|
If you would like to run ssh_scan as a service, please refer to [the ssh_scan_api project](https://github.com/mozilla/ssh_scan_api)
|
95
95
|
|
data/bin/ssh_scan
CHANGED
@@ -20,7 +20,7 @@ options = {
|
|
20
20
|
"verbosity" => nil,
|
21
21
|
"logger" => Logger.new(STDERR),
|
22
22
|
"fingerprint_database" => ENV['HOME']+'/.ssh_scan_fingerprints.yml',
|
23
|
-
"output_type" =>
|
23
|
+
"output_type" => nil
|
24
24
|
}
|
25
25
|
|
26
26
|
# Reorder arguments before parsing
|
@@ -106,7 +106,8 @@ scan") do |file|
|
|
106
106
|
|
107
107
|
opts.on("-o", "--output [FilePath]",
|
108
108
|
"File to write JSON output to") do |file|
|
109
|
-
|
109
|
+
options["output"] = file
|
110
|
+
# $stdout.reopen(file, "w")
|
110
111
|
end
|
111
112
|
|
112
113
|
opts.on("--output-type [json, yaml]",
|
@@ -238,9 +239,23 @@ options["policy_file"] = SSHScan::Policy.from_file(options["policy"])
|
|
238
239
|
scan_engine = SSHScan::ScanEngine.new()
|
239
240
|
results = scan_engine.scan(options)
|
240
241
|
|
241
|
-
if options["output_type"] == "yaml"
|
242
|
+
if options["output_type"] == "yaml" && (options["output"].nil? || options["output"].empty?)
|
242
243
|
puts YAML.dump(results)
|
243
|
-
elsif options["output_type"] == "json"
|
244
|
+
elsif options["output_type"] == "json" && (options["output"].nil? || options["output"].empty?)
|
245
|
+
puts JSON.pretty_generate(results)
|
246
|
+
elsif (options["output_type"].nil? || options["output_type"].empty?) && (!options["output"].nil? && options["output"].split(".").last.downcase == "yml")
|
247
|
+
open(options["output"], 'w') do |f|
|
248
|
+
f.puts YAML.dump(results)
|
249
|
+
end
|
250
|
+
elsif (options["output_type"].nil? || options["output_type"].empty?) && (!options["output"].nil? && options["output"].split(".").last.downcase == "json")
|
251
|
+
open(options["output"], 'w') do |f|
|
252
|
+
f.puts JSON.pretty_generate(results)
|
253
|
+
end
|
254
|
+
elsif (options["output_type"].nil? || options["output_type"].empty?) && options["output"]
|
255
|
+
open(options["output"], 'w') do |f|
|
256
|
+
f.puts JSON.pretty_generate(results)
|
257
|
+
end
|
258
|
+
else
|
244
259
|
puts JSON.pretty_generate(results)
|
245
260
|
end
|
246
261
|
|
@@ -0,0 +1,24 @@
|
|
1
|
+
---
|
2
|
+
name: Mozilla Modern - with just ETM macs
|
3
|
+
ssh_version: 2.0
|
4
|
+
auth_methods:
|
5
|
+
- publickey
|
6
|
+
kex:
|
7
|
+
- curve25519-sha256@libssh.org
|
8
|
+
- ecdh-sha2-nistp521
|
9
|
+
- ecdh-sha2-nistp384
|
10
|
+
- ecdh-sha2-nistp256
|
11
|
+
- diffie-hellman-group-exchange-sha256
|
12
|
+
encryption:
|
13
|
+
- chacha20-poly1305@openssh.com
|
14
|
+
- aes256-gcm@openssh.com
|
15
|
+
- aes128-gcm@openssh.com
|
16
|
+
- aes256-ctr
|
17
|
+
- aes192-ctr
|
18
|
+
- aes128-ctr
|
19
|
+
macs:
|
20
|
+
- hmac-sha2-512-etm@openssh.com
|
21
|
+
- hmac-sha2-256-etm@openssh.com
|
22
|
+
- umac-128-etm@openssh.com
|
23
|
+
references:
|
24
|
+
- https://example.com/custom_policy
|
data/lib/ssh_scan/client.rb
CHANGED
@@ -70,6 +70,9 @@ module SSHScan
|
|
70
70
|
rescue Errno::EHOSTUNREACH => e
|
71
71
|
@error = SSHScan::Error::ConnectionRefused.new(e.message)
|
72
72
|
@sock = nil
|
73
|
+
rescue Errno::ENOPROTOOPT => e
|
74
|
+
@error = SSHScan::Error::ConnectionRefused.new(e.message)
|
75
|
+
@sock = nil
|
73
76
|
else
|
74
77
|
if @raw_server_banner.nil?
|
75
78
|
@error = SSHScan::Error::NoBanner.new(
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'sshkey'
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
module SSHScan
|
6
|
+
# All cryptography related methods.
|
7
|
+
module Crypto
|
8
|
+
# House methods helpful in analysing SSH public keys.
|
9
|
+
class PublicKey
|
10
|
+
def initialize(key_string)
|
11
|
+
@key_string = key_string
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid?
|
15
|
+
SSHKey.valid_ssh_public_key?(@key_string)
|
16
|
+
end
|
17
|
+
|
18
|
+
def type
|
19
|
+
if @key_string.start_with?("ssh-rsa")
|
20
|
+
return "rsa"
|
21
|
+
elsif @key_string.start_with?("ssh-dss")
|
22
|
+
return "dsa"
|
23
|
+
elsif @key_string.start_with?("ecdsa-sha2-nistp256")
|
24
|
+
return "ecdsa-sha2-nistp256"
|
25
|
+
elsif @key_string.start_with?("ssh-ed25519")
|
26
|
+
return "ed25519"
|
27
|
+
else
|
28
|
+
return "unknown"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def length
|
33
|
+
SSHKey.ssh_public_key_bits(@key_string)
|
34
|
+
end
|
35
|
+
|
36
|
+
def fingerprint_md5
|
37
|
+
SSHKey.fingerprint(@key_string)
|
38
|
+
end
|
39
|
+
|
40
|
+
def fingerprint_sha1
|
41
|
+
SSHKey.sha1_fingerprint(@key_string)
|
42
|
+
end
|
43
|
+
|
44
|
+
def fingerprint_sha256
|
45
|
+
# We're translating this to hex because the SSHKEY default isn't as useful for comparing with SSHFP records
|
46
|
+
Base64.decode64(SSHKey.sha256_fingerprint(@key_string)).hexify(:delim => ":")
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_hash
|
50
|
+
{
|
51
|
+
self.type => {
|
52
|
+
"raw" => @key_string,
|
53
|
+
"length" => self.length,
|
54
|
+
"fingerprints" => {
|
55
|
+
"md5" => self.fingerprint_md5,
|
56
|
+
"sha1" => self.fingerprint_sha1,
|
57
|
+
"sha256" => self.fingerprint_sha256
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/ssh_scan/result.rb
CHANGED
@@ -8,7 +8,7 @@ module SSHScan
|
|
8
8
|
class Result
|
9
9
|
def initialize()
|
10
10
|
@version = SSHScan::VERSION
|
11
|
-
@
|
11
|
+
@keys = nil
|
12
12
|
@duplicate_host_key_ips = Set.new()
|
13
13
|
@compliance = {}
|
14
14
|
end
|
@@ -157,12 +157,20 @@ module SSHScan
|
|
157
157
|
@auth_methods = auth_methods
|
158
158
|
end
|
159
159
|
|
160
|
-
def
|
161
|
-
@
|
160
|
+
def keys
|
161
|
+
@keys || {}
|
162
162
|
end
|
163
163
|
|
164
|
-
def
|
165
|
-
@
|
164
|
+
def keys=(keys)
|
165
|
+
@keys = keys
|
166
|
+
end
|
167
|
+
|
168
|
+
def dns_keys
|
169
|
+
@dns_keys
|
170
|
+
end
|
171
|
+
|
172
|
+
def dns_keys=(dns_keys)
|
173
|
+
@dns_keys = dns_keys
|
166
174
|
end
|
167
175
|
|
168
176
|
def duplicate_host_key_ips=(duplicate_host_key_ips)
|
@@ -249,8 +257,9 @@ module SSHScan
|
|
249
257
|
"languages_client_to_server" => self.languages_client_to_server,
|
250
258
|
"languages_server_to_client" => self.languages_server_to_client,
|
251
259
|
"auth_methods" => self.auth_methods,
|
252
|
-
"
|
253
|
-
"
|
260
|
+
"keys" => self.keys,
|
261
|
+
"dns_keys" => self.dns_keys,
|
262
|
+
"duplicate_host_key_ips" => self.duplicate_host_key_ips.uniq,
|
254
263
|
"compliance" => @compliance,
|
255
264
|
"start_time" => self.start_time,
|
256
265
|
"end_time" => self.end_time,
|
data/lib/ssh_scan/scan_engine.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'socket'
|
2
2
|
require 'ssh_scan/client'
|
3
|
-
require 'ssh_scan/
|
3
|
+
require 'ssh_scan/public_key'
|
4
4
|
require 'ssh_scan/fingerprint_database'
|
5
5
|
require 'ssh_scan/subprocess'
|
6
|
+
require 'ssh_scan/ssh_fp'
|
6
7
|
require 'net/ssh'
|
7
8
|
require 'logger'
|
8
9
|
require 'open3'
|
@@ -119,11 +120,11 @@ module SSHScan
|
|
119
120
|
end
|
120
121
|
|
121
122
|
# Figure out what rsa or dsa fingerprints exist
|
122
|
-
|
123
|
+
keys = {}
|
123
124
|
|
124
125
|
output = ""
|
125
126
|
|
126
|
-
cmd = ['ssh-keyscan', '-t', 'rsa,dsa', '-p', port.to_s, target].join(" ")
|
127
|
+
cmd = ['ssh-keyscan', '-t', 'rsa,dsa,ecdsa,ed25519', '-p', port.to_s, target].join(" ")
|
127
128
|
|
128
129
|
Utils::Subprocess.new(cmd) do |stdout, stderr, thread|
|
129
130
|
if stdout
|
@@ -136,31 +137,27 @@ module SSHScan
|
|
136
137
|
|
137
138
|
for i in 0..host_keys_len
|
138
139
|
if host_keys[i].eql? "ssh-dss"
|
139
|
-
|
140
|
-
|
141
|
-
"dsa" => {
|
142
|
-
"known_bad" => pkey.bad_key?.to_s,
|
143
|
-
"md5" => pkey.fingerprint_md5,
|
144
|
-
"sha1" => pkey.fingerprint_sha1,
|
145
|
-
"sha256" => pkey.fingerprint_sha256,
|
146
|
-
}
|
147
|
-
})
|
140
|
+
key = SSHScan::Crypto::PublicKey.new([host_keys[i], host_keys[i + 1]].join(" "))
|
141
|
+
keys.merge!(key.to_hash)
|
148
142
|
end
|
149
143
|
|
150
144
|
if host_keys[i].eql? "ssh-rsa"
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
145
|
+
key = SSHScan::Crypto::PublicKey.new([host_keys[i], host_keys[i + 1]].join(" "))
|
146
|
+
keys.merge!(key.to_hash)
|
147
|
+
end
|
148
|
+
|
149
|
+
if host_keys[i].eql? "ecdsa-sha2-nistp256"
|
150
|
+
key = SSHScan::Crypto::PublicKey.new([host_keys[i], host_keys[i + 1]].join(" "))
|
151
|
+
keys.merge!(key.to_hash)
|
152
|
+
end
|
153
|
+
|
154
|
+
if host_keys[i].eql? "ssh-ed25519"
|
155
|
+
key = SSHScan::Crypto::PublicKey.new([host_keys[i], host_keys[i + 1]].join(" "))
|
156
|
+
keys.merge!(key.to_hash)
|
160
157
|
end
|
161
158
|
end
|
162
159
|
|
163
|
-
result.
|
160
|
+
result.keys = keys
|
164
161
|
result.set_end_time
|
165
162
|
|
166
163
|
return result
|
@@ -200,12 +197,10 @@ module SSHScan
|
|
200
197
|
results.each do |result|
|
201
198
|
fingerprint_db.clear_fingerprints(result.ip)
|
202
199
|
|
203
|
-
if result.
|
204
|
-
result.
|
205
|
-
host_key_algo.each do |fingerprint|
|
206
|
-
|
207
|
-
next if key == "known_bad"
|
208
|
-
fingerprint_db.add_fingerprint(value, result.ip)
|
200
|
+
if result.keys
|
201
|
+
result.keys.values.each do |host_key_algo|
|
202
|
+
host_key_algo['fingerprints'].values.each do |fingerprint|
|
203
|
+
fingerprint_db.add_fingerprint(fingerprint, result.ip)
|
209
204
|
end
|
210
205
|
end
|
211
206
|
end
|
@@ -213,20 +208,26 @@ module SSHScan
|
|
213
208
|
|
214
209
|
# Decorate all the results with duplicate keys
|
215
210
|
results.each do |result|
|
216
|
-
if result.
|
211
|
+
if result.keys
|
217
212
|
ip = result.ip
|
218
213
|
result.duplicate_host_key_ips = []
|
219
|
-
result.
|
220
|
-
host_key_algo.each do |fingerprint|
|
221
|
-
|
222
|
-
next if key == "known_bad"
|
223
|
-
fingerprint_db.find_fingerprints(value).each do |other_ip|
|
214
|
+
result.keys.values.each do |host_key_algo|
|
215
|
+
host_key_algo["fingerprints"].values.each do |fingerprint|
|
216
|
+
fingerprint_db.find_fingerprints(fingerprint).each do |other_ip|
|
224
217
|
next if ip == other_ip
|
225
218
|
result.duplicate_host_key_ips << other_ip
|
226
219
|
end
|
227
220
|
end
|
228
221
|
end
|
229
|
-
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# Decorate all the results with SSHFP records
|
226
|
+
sshfp = SSHScan::SshFp.new()
|
227
|
+
results.each do |result|
|
228
|
+
if !result.hostname.empty?
|
229
|
+
dns_keys = sshfp.query(result.hostname)
|
230
|
+
result.dns_keys = dns_keys
|
230
231
|
end
|
231
232
|
end
|
232
233
|
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'resolv'
|
2
|
+
|
3
|
+
module SSHScan
|
4
|
+
class SshFp
|
5
|
+
|
6
|
+
ALGO_MAP = {
|
7
|
+
0 => "reserved", # Reference: https://tools.ietf.org/html/rfc4255#section-2.4
|
8
|
+
1 => "rsa", # Reference: https://tools.ietf.org/html/rfc4255#section-2.4
|
9
|
+
2 => "dss", # Reference: https://tools.ietf.org/html/rfc4255#section-2.4
|
10
|
+
3 => "ecdsa", # Reference: https://tools.ietf.org/html/rfc6594#section-5.3.1
|
11
|
+
4 => "ed25519" # Reference: https://tools.ietf.org/html/rfc7479
|
12
|
+
}
|
13
|
+
|
14
|
+
|
15
|
+
FPTYPE_MAP = {
|
16
|
+
0 => "reserved", # Reference: https://tools.ietf.org/html/rfc4255#section-2.4
|
17
|
+
1 => "sha1", # Reference: https://tools.ietf.org/html/rfc4255#section-2.4
|
18
|
+
2 => "sha256" # Reference: https://tools.ietf.org/html/rfc6594#section-5.1.2
|
19
|
+
}
|
20
|
+
|
21
|
+
|
22
|
+
def query(fqdn)
|
23
|
+
sshfp_records = []
|
24
|
+
|
25
|
+
# Reference: https://stackoverflow.com/questions/28867626/how-to-use-resolvdnsresourcegeneric
|
26
|
+
# Note: this includes some fixes too, I'll post a direct link back to the SO article.
|
27
|
+
Resolv::DNS.open do |dns|
|
28
|
+
all_records = dns.getresources(fqdn, Resolv::DNS::Resource::IN::ANY ) rescue nil
|
29
|
+
all_records.each do |rr|
|
30
|
+
if rr.is_a? Resolv::DNS::Resource::Generic then
|
31
|
+
classname = rr.class.name.split('::').last
|
32
|
+
if classname == "Type44_Class1"
|
33
|
+
data = rr.data.bytes
|
34
|
+
algo = data[0].to_s
|
35
|
+
fptype = data[1].to_s
|
36
|
+
fp = data[2..-1]
|
37
|
+
hex = fp.map{|b| b.to_s(16).rjust(2,'0') }.join(':')
|
38
|
+
sshfp_records << {"fptype" => FPTYPE_MAP[fptype.to_i], "algo" => ALGO_MAP[algo.to_i], "hex" => hex}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
return sshfp_records.sort_by { |k| k["hex"] }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/ssh_scan/version.rb
CHANGED
data/lib/string_ext.rb
CHANGED
@@ -69,6 +69,31 @@ class String
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
72
|
+
# Stolen from: https://github.com/emonti/rbkb/blob/master/lib/rbkb/extends/string.rb
|
73
|
+
def hexify(opts={})
|
74
|
+
delim = opts[:delim]
|
75
|
+
pre = (opts[:prefix] || "")
|
76
|
+
suf = (opts[:suffix] || "")
|
77
|
+
|
78
|
+
if (rx=opts[:rx]) and not rx.kind_of? Regexp
|
79
|
+
raise "rx must be a regular expression for a character class"
|
80
|
+
end
|
81
|
+
|
82
|
+
hx = [("0".."9").to_a, ("a".."f").to_a].flatten
|
83
|
+
|
84
|
+
out=Array.new
|
85
|
+
|
86
|
+
self.each_byte do |c|
|
87
|
+
hc = if (rx and not rx.match c.chr)
|
88
|
+
c.chr
|
89
|
+
else
|
90
|
+
pre + (hx[(c >> 4)] + hx[(c & 0xf )]) + suf
|
91
|
+
end
|
92
|
+
out << (hc)
|
93
|
+
end
|
94
|
+
out.join(delim)
|
95
|
+
end
|
96
|
+
|
72
97
|
def fqdn?
|
73
98
|
begin
|
74
99
|
resolve_fqdn
|
data/ssh_scan.gemspec
CHANGED
@@ -32,7 +32,7 @@ Gem::Specification.new do |s|
|
|
32
32
|
|
33
33
|
s.add_dependency('bindata', '2.4.3')
|
34
34
|
s.add_dependency('netaddr', '1.5.1')
|
35
|
-
s.add_dependency('net-ssh', '5.0
|
35
|
+
s.add_dependency('net-ssh', '5.2.0')
|
36
36
|
s.add_dependency('sshkey')
|
37
37
|
s.add_development_dependency('pry', '0.11.3')
|
38
38
|
s.add_development_dependency('rspec', '3.7.0')
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ssh_scan
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.43
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonathan Claudius
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date:
|
15
|
+
date: 2020-05-27 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: bindata
|
@@ -48,14 +48,14 @@ dependencies:
|
|
48
48
|
requirements:
|
49
49
|
- - '='
|
50
50
|
- !ruby/object:Gem::Version
|
51
|
-
version: 5.0
|
51
|
+
version: 5.2.0
|
52
52
|
type: :runtime
|
53
53
|
prerelease: false
|
54
54
|
version_requirements: !ruby/object:Gem::Requirement
|
55
55
|
requirements:
|
56
56
|
- - '='
|
57
57
|
- !ruby/object:Gem::Version
|
58
|
-
version: 5.0
|
58
|
+
version: 5.2.0
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: sshkey
|
61
61
|
requirement: !ruby/object:Gem::Requirement
|
@@ -155,6 +155,7 @@ files:
|
|
155
155
|
- README.md
|
156
156
|
- Rakefile
|
157
157
|
- bin/ssh_scan
|
158
|
+
- config/policies/just_etm_macs.yaml
|
158
159
|
- config/policies/mozilla_intermediate.yml
|
159
160
|
- config/policies/mozilla_modern.yml
|
160
161
|
- data/README
|
@@ -163,7 +164,6 @@ files:
|
|
163
164
|
- lib/ssh_scan/banner.rb
|
164
165
|
- lib/ssh_scan/client.rb
|
165
166
|
- lib/ssh_scan/constants.rb
|
166
|
-
- lib/ssh_scan/crypto.rb
|
167
167
|
- lib/ssh_scan/error.rb
|
168
168
|
- lib/ssh_scan/error/closed_connection.rb
|
169
169
|
- lib/ssh_scan/error/connect_timeout.rb
|
@@ -188,8 +188,10 @@ files:
|
|
188
188
|
- lib/ssh_scan/policy.rb
|
189
189
|
- lib/ssh_scan/policy_manager.rb
|
190
190
|
- lib/ssh_scan/protocol.rb
|
191
|
+
- lib/ssh_scan/public_key.rb
|
191
192
|
- lib/ssh_scan/result.rb
|
192
193
|
- lib/ssh_scan/scan_engine.rb
|
194
|
+
- lib/ssh_scan/ssh_fp.rb
|
193
195
|
- lib/ssh_scan/ssh_lib.rb
|
194
196
|
- lib/ssh_scan/ssh_lib/ciscossh.rb
|
195
197
|
- lib/ssh_scan/ssh_lib/cryptlib.rb
|
data/lib/ssh_scan/crypto.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
require 'openssl'
|
2
|
-
require 'sshkey'
|
3
|
-
require 'base64'
|
4
|
-
|
5
|
-
module SSHScan
|
6
|
-
# All cryptography related methods.
|
7
|
-
module Crypto
|
8
|
-
# House methods helpful in analysing SSH public keys.
|
9
|
-
class PublicKey
|
10
|
-
def initialize(key)
|
11
|
-
@key = key
|
12
|
-
end
|
13
|
-
|
14
|
-
# Is the current key known to be in our known bad key list
|
15
|
-
# @return [Boolean] true if this {SSHScan::Crypto::PublicKey}
|
16
|
-
# instance's key is also in {SSHScan::Crypto}'s
|
17
|
-
# bad_public_keys, otherwise false
|
18
|
-
def bad_key?
|
19
|
-
SSHScan::Crypto.bad_public_keys.each do |other_key|
|
20
|
-
if self.fingerprint_sha256 == other_key.fingerprint_sha256
|
21
|
-
return true
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
return false
|
26
|
-
end
|
27
|
-
|
28
|
-
# Generate MD5 fingerprint for this {SSHScan::Crypto::PublicKey} instance.
|
29
|
-
# @return [String] formatted MD5 fingerprint
|
30
|
-
def fingerprint_md5
|
31
|
-
OpenSSL::Digest::MD5.hexdigest(::Base64.decode64(@key)).scan(/../).join(':')
|
32
|
-
end
|
33
|
-
|
34
|
-
# Generate SHA1 fingerprint for this {SSHScan::Crypto::PublicKey} instance.
|
35
|
-
# @return [String] formatted SHA1 fingerprint
|
36
|
-
def fingerprint_sha1
|
37
|
-
OpenSSL::Digest::SHA1.hexdigest(::Base64.decode64(@key)).scan(/../).join(':')
|
38
|
-
end
|
39
|
-
|
40
|
-
# Generate SHA256 fingerprint for this {SSHScan::Crypto::PublicKey} instance.
|
41
|
-
# @return [String] formatted SHA256 fingerprint
|
42
|
-
def fingerprint_sha256
|
43
|
-
OpenSSL::Digest::SHA256.hexdigest(::Base64.decode64(@key)).scan(/../).join(':')
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def self.bad_public_keys
|
48
|
-
bad_keys = []
|
49
|
-
|
50
|
-
Dir.glob("data/ssh-badkeys/host/*.key").each do |file_path|
|
51
|
-
file = File.read(File.expand_path(file_path))
|
52
|
-
key = SSHKey.new(file)
|
53
|
-
bad_keys << SSHScan::Crypto::PublicKey.new(key.ssh_public_key.split[1])
|
54
|
-
end
|
55
|
-
|
56
|
-
return bad_keys
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
60
|
-
end
|