From 2b19052c0cfc0d700a870027cb3d5586fb34a395 Mon Sep 17 00:00:00 2001 From: Aeris Date: Tue, 1 Sep 2015 00:57:48 +0200 Subject: [PATCH] =?UTF-8?q?Don=E2=80=99t=20use=20net-ssh=20to=20(not)=20en?= =?UTF-8?q?sure=20server=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cryptcheck.gemspec | 1 - lib/cryptcheck.rb | 6 ++ lib/cryptcheck/ssh/grade.rb | 12 +--- lib/cryptcheck/ssh/packet.rb | 45 ++++++++++++ lib/cryptcheck/ssh/server.rb | 129 ++++++++++++++++++----------------- 5 files changed, 119 insertions(+), 74 deletions(-) create mode 100644 lib/cryptcheck/ssh/packet.rb diff --git a/cryptcheck.gemspec b/cryptcheck.gemspec index f75d9e5..9eb3808 100644 --- a/cryptcheck.gemspec +++ b/cryptcheck.gemspec @@ -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 diff --git a/lib/cryptcheck.rb b/lib/cryptcheck.rb index d354122..edd77d3 100644 --- a/lib/cryptcheck.rb +++ b/lib/cryptcheck.rb @@ -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 diff --git a/lib/cryptcheck/ssh/grade.rb b/lib/cryptcheck/ssh/grade.rb index d0085c5..a9ea317 100644 --- a/lib/cryptcheck/ssh/grade.rb +++ b/lib/cryptcheck/ssh/grade.rb @@ -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 diff --git a/lib/cryptcheck/ssh/packet.rb b/lib/cryptcheck/ssh/packet.rb new file mode 100644 index 0000000..92993a8 --- /dev/null +++ b/lib/cryptcheck/ssh/packet.rb @@ -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 diff --git a/lib/cryptcheck/ssh/server.rb b/lib/cryptcheck/ssh/server.rb index 3c9ca8a..1292ed1 100644 --- a/lib/cryptcheck/ssh/server.rb +++ b/lib/cryptcheck/ssh/server.rb @@ -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