ssh_scan 0.0.40 → 0.0.41

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
  SHA256:
3
- metadata.gz: 876b8b5d07476eea82ba8d4a802254e625f0610258601f96a10c8f7ea2dc88c3
4
- data.tar.gz: db1836ba6ec5cb21cd1a1ef09a3cbcaa41b3986329fc7779bde33ac84086aa7a
3
+ metadata.gz: 30ae6fc2118a4c57d91680ce36dfb5f05f04887b27e1c29c11e87a19440a220c
4
+ data.tar.gz: 8bb716eafcb9ddedd8141466463c12a1d18323b68a7bb01bc7c6edb02fe899ae
5
5
  SHA512:
6
- metadata.gz: b3c255143c2e499923b6101f22f7befd6912274071a9edac8fe2a7d4bda7b4c00d69c0f68b5b53d6f400f57be9320d6c5f254756010d483a690aac04d8ba66ed
7
- data.tar.gz: 80371f6ba9868dbf949c64f6e2d263d1dc0eb57d5317c0d8147427695bfe4c36fd2105c5727e41b384a336ddf6f1f0251525d6dad0ac6a3c3d66e9aa1a216a5e
6
+ metadata.gz: b54db17fe59790ef8bec162fb4bb2949ab087ff7738217263a1454ec220fae500ccb21da7776407d8196dee9fa1a729c1cc472de8a200d64cb99e87e63cb0f93
7
+ data.tar.gz: f8516f26b7066e50d237bec19c56c4ae81f2a007c04d1a06af4e524f900807bb5e8924a7bcc58be5c9d6cea7435430ba7f13a244038ca24c3af6dac1116b8ff5
@@ -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!**](http://rspec.info/) Your patch won't be accepted (or will be delayed) if it doesn't have 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**](http://yardoc.org/) Make sure the README and any other
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**](http://stackoverflow.com/questions/6934752/git-combining-multiple-commits-before-pushing) Make sure each individual commit in your pull
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
 
@@ -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" => "json"
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
- $stdout.reopen(file, "w")
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
 
@@ -39,10 +39,11 @@ module SSHScan
39
39
 
40
40
  def fingerprint_sha1
41
41
  SSHKey.sha1_fingerprint(@key_string)
42
- end
42
+ end
43
43
 
44
44
  def fingerprint_sha256
45
- SSHKey.sha256_fingerprint(@key_string)
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 => ":")
46
47
  end
47
48
 
48
49
  def to_hash
@@ -157,12 +157,20 @@ module SSHScan
157
157
  @auth_methods = auth_methods
158
158
  end
159
159
 
160
+ def keys
161
+ @keys || {}
162
+ end
163
+
160
164
  def keys=(keys)
161
165
  @keys = keys
162
166
  end
163
167
 
164
- def keys
165
- @keys
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)
@@ -250,6 +258,7 @@ module SSHScan
250
258
  "languages_server_to_client" => self.languages_server_to_client,
251
259
  "auth_methods" => self.auth_methods,
252
260
  "keys" => self.keys,
261
+ "dns_keys" => self.dns_keys,
253
262
  "duplicate_host_key_ips" => self.duplicate_host_key_ips.uniq,
254
263
  "compliance" => @compliance,
255
264
  "start_time" => self.start_time,
@@ -3,6 +3,7 @@ require 'ssh_scan/client'
3
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'
@@ -221,6 +222,15 @@ module SSHScan
221
222
  end
222
223
  end
223
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
231
+ end
232
+ end
233
+
224
234
  # Decorate all the results with compliance information
225
235
  results.each do |result|
226
236
  # Do this only when we have all the information we need
@@ -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
@@ -0,0 +1,43 @@
1
+ module SSHScan
2
+ module Tests
3
+ class DnsKeyVerification
4
+ def initialize(result)
5
+ @result = result
6
+ end
7
+
8
+ def pass?
9
+ @result.keys.each do |key,value|
10
+ valid = false
11
+
12
+ @result.dns_keys.each do |dns_key|
13
+ if key == dns_key["algo"] &&
14
+ value["fingerprints"].values.include?(dns_key["hex"])
15
+ valid = true
16
+ end
17
+ end
18
+
19
+ # This means we fail any key that's offered that's not verifiable via information from DNS
20
+ return false unless valid == true
21
+ end
22
+
23
+ return true
24
+ end
25
+
26
+ def fail_description
27
+ if pass?
28
+ ""
29
+ else
30
+ "One or more of the keys offered by the SSH service were not able to be verified using an SSHFS record"
31
+ end
32
+ end
33
+
34
+ def score_deduction
35
+ if pass?
36
+ 0
37
+ else
38
+ -5
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,3 +1,3 @@
1
1
  module SSHScan
2
- VERSION = '0.0.40'
2
+ VERSION = '0.0.41'
3
3
  end
@@ -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
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.40
4
+ version: 0.0.41
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: 2019-01-18 00:00:00.000000000 Z
15
+ date: 2019-05-03 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: bindata
@@ -190,6 +190,7 @@ files:
190
190
  - lib/ssh_scan/public_key.rb
191
191
  - lib/ssh_scan/result.rb
192
192
  - lib/ssh_scan/scan_engine.rb
193
+ - lib/ssh_scan/ssh_fp.rb
193
194
  - lib/ssh_scan/ssh_lib.rb
194
195
  - lib/ssh_scan/ssh_lib/ciscossh.rb
195
196
  - lib/ssh_scan/ssh_lib/cryptlib.rb
@@ -208,6 +209,7 @@ files:
208
209
  - lib/ssh_scan/ssh_lib/unknown.rb
209
210
  - lib/ssh_scan/subprocess.rb
210
211
  - lib/ssh_scan/target_parser.rb
212
+ - lib/ssh_scan/tests/test_dns_key_verification.rb
211
213
  - lib/ssh_scan/update.rb
212
214
  - lib/ssh_scan/version.rb
213
215
  - lib/string_ext.rb