Browse Source

Don’t use net-ssh to (not) ensure server compatibility

master
Aeris 4 years ago
parent
commit
2b19052c0c
5 changed files with 119 additions and 74 deletions
  1. 0
    1
      cryptcheck.gemspec
  2. 6
    0
      lib/cryptcheck.rb
  3. 2
    10
      lib/cryptcheck/ssh/grade.rb
  4. 45
    0
      lib/cryptcheck/ssh/packet.rb
  5. 66
    63
      lib/cryptcheck/ssh/server.rb

+ 0
- 1
cryptcheck.gemspec View File

@@ -35,5 +35,4 @@ Gem::Specification.new do |spec|
spec.add_dependency 'parallel', '~> 1.3', '>= 1.3.4'
spec.add_dependency 'ruby-progressbar', '~> 1.7', '>= 1.7.1'
spec.add_dependency 'colorize', '~> 0.7', '>= 0.7.7'
spec.add_dependency 'net-ssh', '~> 2.9', '>= 2.9.2'
end

+ 6
- 0
lib/cryptcheck.rb View File

@@ -31,4 +31,10 @@ module CryptCheck
autoload :Grade, 'cryptcheck/tls/smtp/grade'
end
end

module Ssh
autoload :Packet, 'cryptcheck/ssh/packet'
autoload :Server, 'cryptcheck/ssh/server'
autoload :SshNotSupportedServer, 'cryptcheck/ssh/server'
end
end

+ 2
- 10
lib/cryptcheck/ssh/grade.rb View File

@@ -1,6 +1,6 @@
module CryptCheck
module Tls
class TlsNotSupportedGrade
module Ssh
class SshNotSupportedGrade
attr_reader :server, :score, :grade

def initialize(server)
@@ -13,14 +13,6 @@ module CryptCheck

def initialize(server)
@server = server
calculate_protocol_score
calculate_key_exchange_score
calculate_cipher_strengths_score
@score = @protocol_score*0.3 + @key_exchange_score*0.3 + @cipher_strengths_score*0.4
calculate_error
calculate_warning
calculate_success
calculate_grade
end

def display

+ 45
- 0
lib/cryptcheck/ssh/packet.rb View File

@@ -0,0 +1,45 @@
module CryptCheck
module Ssh
class Packet
SSH_MSG_KEXINIT = 20

def self.uint32(raw)
raw.gets(4).unpack('N').first
end

def self.string(raw)
length = self.uint32 raw
raw.gets length
end

def self.strings(raw)
self.string(raw).split ','
end

def self.read(socket)
packet_length = socket.recv(4).unpack('N').first
padding_length = socket.recv(1).unpack('C').first
payload = socket.recv packet_length - padding_length - 1
socket.recv padding_length
StringIO.new payload
end

def self.read_kex_init(socket)
payload = self.read socket
msg_id = payload.gets(1).unpack('C').first
raise "Not expected message id #{msg_id}" unless msg_id == SSH_MSG_KEXINIT

payload.gets 16 # cookie

key_algorithms = self.strings payload
host_key_algorithms = self.strings payload
encryption_algorithms = (self.strings(payload) + self.strings(payload)).uniq
mac_algorithms = (self.strings(payload) + self.strings(payload)).uniq
compression_algorithms = (self.strings(payload) + self.strings(payload)).uniq

{ kex: key_algorithms, host_key: host_key_algorithms, encryption: encryption_algorithms,
mac: mac_algorithms, compression: compression_algorithms }
end
end
end
end

+ 66
- 63
lib/cryptcheck/ssh/server.rb View File

@@ -1,4 +1,4 @@
require 'net/ssh'
require 'socket'

module CryptCheck
module Ssh
@@ -11,91 +11,95 @@ module CryptCheck
end

class Server
TCP_TIMEOUT = 10
TCP_TIMEOUT = 10
class SshNotAvailableException < Exception
end

attr_reader :hostname, :port, :kex, :encryption, :hmac, :compression, :key

KEX = {
'curve25519-sha256@libssh.org' => :green,
'diffie-hellman-group1-sha1' => :yellow,
'diffie-hellman-group14-sha1' => :yellow,
'diffie-hellman-group-exchange-sha1' => :yellow,
'diffie-hellman-group-exchange-sha256' => :green,
'ecdh-sha2-nistp256' => :yellow,
'ecdh-sha2-nistp384' => :yellow,
'ecdh-sha2-nistp521' => :yellow
'curve25519-sha256@libssh.org' => :green,
'diffie-hellman-group1-sha1' => :yellow,
'diffie-hellman-group14-sha1' => :yellow,
'diffie-hellman-group-exchange-sha1' => :yellow,
'diffie-hellman-group-exchange-sha256' => :green,
'ecdh-sha2-nistp256' => :yellow,
'ecdh-sha2-nistp384' => :yellow,
'ecdh-sha2-nistp521' => :yellow
}

ENCRYPTION = {
'3des-cbc' => :red,
'aes128-cbc' => :yellow,
'aes192-cbc' => :yellow,
'aes256-cbc' => :yellow,
'aes128-ctr' => :yellow,
'aes192-ctr' => :yellow,
'aes256-ctr' => :yellow,
'aes128-gcm@openssh.com' => :green,
'aes256-gcm@openssh.com' => :green,
'arcfour' => :red,
'arcfour128' => :red,
'arcfour256' => :red,
'blowfish-cbc' => :yellow,
'cast128-cbc' => nil,
'chacha20-poly1305@openssh.com' => :green
'3des-cbc' => :red,
'aes128-cbc' => :yellow,
'aes192-cbc' => :yellow,
'aes256-cbc' => :yellow,
'aes128-ctr' => :yellow,
'aes192-ctr' => :yellow,
'aes256-ctr' => :yellow,
'aes128-gcm@openssh.com' => :green,
'aes256-gcm@openssh.com' => :green,
'arcfour' => :red,
'arcfour128' => :red,
'arcfour256' => :red,
'blowfish-cbc' => :yellow,
'cast128-cbc' => nil,
'chacha20-poly1305@openssh.com' => :green
}

HMAC = {
'hmac-md5' => :red,
'hmac-md5-96' => :red,
'hmac-ripemd160' => :green,
'hmac-sha1' => :yellow,
'hmac-sha1-96' => :red,
'hmac-sha2-256' => :green,
'hmac-sha2-512' => :green,
'umac-64@openssh.com' => :red,
'umac-128@openssh.com' => nil,
'hmac-md5-etm@openssh.com' => :red,
'hmac-md5-96-etm@openssh.com' => :red,
'hmac-ripemd160-etm@openssh.com' => :green,
'hmac-sha1-etm@openssh.com' => :yellow,
'hmac-sha1-96-etm@openssh.com' => :red,
'hmac-sha2-256-etm@openssh.com' => :green,
'hmac-sha2-512-etm@openssh.com' => :green,
'umac-64-etm@openssh.com' => :red,
'umac-128-etm@openssh.com' => nil
'hmac-md5' => :red,
'hmac-md5-96' => :red,
'hmac-ripemd160' => :green,
'hmac-sha1' => :yellow,
'hmac-sha1-96' => :red,
'hmac-sha2-256' => :green,
'hmac-sha2-512' => :green,
'umac-64@openssh.com' => :red,
'umac-128@openssh.com' => nil,
'hmac-md5-etm@openssh.com' => :red,
'hmac-md5-96-etm@openssh.com' => :red,
'hmac-ripemd160-etm@openssh.com' => :green,
'hmac-sha1-etm@openssh.com' => :yellow,
'hmac-sha1-96-etm@openssh.com' => :red,
'hmac-sha2-256-etm@openssh.com' => :green,
'hmac-sha2-512-etm@openssh.com' => :green,
'umac-64-etm@openssh.com' => :red,
'umac-128-etm@openssh.com' => nil
}

COMPRESSION = {
'none' => nil,
'zlib@openssh.com' => nil
'none' => nil,
'zlib@openssh.com' => nil
}

KEY = {
'ecdsa-sha2-nistp256-cert-v01@openssh.com' => :yellow,
'ecdsa-sha2-nistp384-cert-v01@openssh.com' => :yellow,
'ecdsa-sha2-nistp521-cert-v01@openssh.com' => :yellow,
'ssh-ed25519-cert-v01@openssh.com' => :green,
'ssh-rsa-cert-v01@openssh.com' => :yellow,
'ssh-dss-cert-v01@openssh.com' => :red,
'ssh-rsa-cert-v00@openssh.com' => :yellow,
'ssh-dss-cert-v00@openssh.com' => :red,
'ecdsa-sha2-nistp256' => :yellow,
'ecdsa-sha2-nistp384' => :yellow,
'ecdsa-sha2-nistp521' => :yellow,
'ssh-ed25519' => :green,
'ssh-rsa' => :yellow,
'ssh-dss' => :red
'ecdsa-sha2-nistp256-cert-v01@openssh.com' => :yellow,
'ecdsa-sha2-nistp384-cert-v01@openssh.com' => :yellow,
'ecdsa-sha2-nistp521-cert-v01@openssh.com' => :yellow,
'ssh-ed25519-cert-v01@openssh.com' => :green,
'ssh-rsa-cert-v01@openssh.com' => :yellow,
'ssh-dss-cert-v01@openssh.com' => :red,
'ssh-rsa-cert-v00@openssh.com' => :yellow,
'ssh-dss-cert-v00@openssh.com' => :red,
'ecdsa-sha2-nistp256' => :yellow,
'ecdsa-sha2-nistp384' => :yellow,
'ecdsa-sha2-nistp521' => :yellow,
'ssh-ed25519' => :green,
'ssh-rsa' => :yellow,
'ssh-dss' => :red
}

def initialize(hostname, port)
@hostname, @port = hostname, port

Logger.info { "#{hostname}:#{port}".colorize :blue }
session = ::Net::SSH::Transport::Session.new @hostname, port: @port, timeout: TCP_TIMEOUT
data = session.algorithms.instance_variable_get :@server_data
@kex, @encryption, @hmac, @compression, @key = data[:kex], data[:encryption_server], data[:hmac_server], data[:compression_server], data[:host_key]
kex = ::Socket.tcp hostname, port, connect_timeout: TCP_TIMEOUT do |socket|
socket.readline
socket.write "SSH-2.0-CryptCheck\r\n"
Packet.read_kex_init socket
end

@kex, @encryption, @hmac, @compression, @key = kex[:kex], kex[:encryption], kex[:mac], kex[:compression], kex[:host_key]

Logger.info { '' }
@kex.each { |k| Logger.info { "Key exchange : #{k.colorize KEX[k]}" } }
@@ -107,7 +111,6 @@ module CryptCheck
@compression.each { |c| Logger.info { "Compression : #{c}" } }
Logger.info { '' }
@key.each { |k| Logger.info { "Key type : #{k.colorize KEY[k]}" } }
session.close
rescue => e
Logger.debug { "SSH not supported : #{e}" }
raise SshNotAvailableException, e

Loading…
Cancel
Save