Lucene search

K
metasploitDaniel van Eeden <[email protected]>, h00dieMSF:AUXILIARY-SCANNER-SSH-SSH_VERSION-
HistoryJan 15, 2010 - 3:25 a.m.

SSH Version Scanner

2010-01-1503:25:34
Daniel van Eeden <[email protected]>, h00die
www.rapid7.com
27

6.9 Medium

AI Score

Confidence

Low

2.6 Low

CVSS2

Access Vector

NETWORK

Access Complexity

HIGH

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

NONE

Availability Impact

NONE

AV:N/AC:H/Au:N/C:P/I:N/A:N

0.123 Low

EPSS

Percentile

95.3%

Detect SSH Version, and the server encryption

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'recog'
require 'net/ssh/transport/session'

class MetasploitModule < Msf::Auxiliary
  include Msf::Auxiliary::Scanner
  include Msf::Auxiliary::Report

  def initialize
    super(
      'Name' => 'SSH Version Scanner',
      'Description' => 'Detect SSH Version, and the server encryption',
      'References' => [
        ['URL', 'https://en.wikipedia.org/wiki/SecureShell'], # general info
        ['URL', 'https://datatracker.ietf.org/doc/html/rfc8732#name-deprecated-algorithms'], # deprecation of kex gss-sha1 stuff
        ['URL', 'https://datatracker.ietf.org/doc/html/draft-ietf-curdle-ssh-kex-sha2-20#page-16'], # diffie-hellman-group-exchange-sha1, diffie-hellman-group1-sha1, rsa1024-sha1
        ['URL', 'https://datatracker.ietf.org/doc/html/rfc8758#name-iana-considerations'], # arc4 deprecation
        ['URL', 'https://github.com/net-ssh/net-ssh?tab=readme-ov-file#supported-algorithms'], # a bunch of diff removed things from the ruby lib
        ['CVE', '2008-5161'] # CBC modes
      ],
      'Author' => [
        'Daniel van Eeden <metasploit[at]myname.nl>', # original author
        'h00die' # algorithms enhancements
      ],
      'License' => MSF_LICENSE
    )

    register_options(
      [
        Opt::RPORT(22),
        OptInt.new('TIMEOUT', [true, 'Timeout for the SSH probe', 30]),
        OptBool.new('EXTENDED_CHECKS', [true, 'Check for cryptographic issues', true])
      ],
      self.class
    )
  end

  def timeout
    datastore['TIMEOUT']
  end

  def rport
    datastore['RPORT']
  end

  def perform_recog(ident)
    table = []
    recog_info = []
    if /^SSH-\d+\.\d+-(.*)$/ =~ ident
      recog_match = Recog::Nizer.match('ssh.banner', ::Regexp.last_match(1))
      if recog_match
        recog_match.each_pair do |k, v|
          next if k == 'matched'

          recog_info << "#{k}: #{v}"
        end
      end
    end

    return table if recog_info.empty?

    recog_info.each do |info|
      info = info.split(': ')
      table << [info[0], info[1..].join(': ')]
    end
    table
  end

  def check_host_key(server_data)
    table = []

    host_key_checks = {
      %w[
        ecdsa-sha2-nistp521 ecdsa-sha2-nistp384
        ecdsa-sha2-nistp256
      ] => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#host-keys']
    }
    server_data[:host_key].each do |host_key|
      note = ''
      host_key_checks.each do |host_key_check, refs|
        host_key_check.each do |bad_key|
          next unless host_key.downcase == bad_key

          vprint_good("#{target_host} - Host Key Encryption #{host_key} uses a weak elliptic curve and should not be used.")
          report_vuln(
            host: target_host,
            port: rport,
            proto: 'tcp',
            name: name,
            info: "Module #{fullname} confirmed SSH Host Key Encryption #{host_key} is available, but should be deprecated",
            refs: refs
          )
          note = 'Weak elliptic curve'
        end
      end
      table << ['encryption.host_key', host_key, note]
    end
    table
  end

  def check_encryption(server_data)
    table = []

    encryption_checks = {
      'arcfour' => ['https://datatracker.ietf.org/doc/html/rfc8758#name-iana-considerations'],
      'arcfour128' => ['https://datatracker.ietf.org/doc/html/rfc8758#name-iana-considerations'],
      'arcfour256' => ['https://datatracker.ietf.org/doc/html/rfc8758#name-iana-considerations'],
      'aes256-cbc' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#encryption-algorithms-ciphers', 'CVE-2008-5161'],
      'aes192-cbc' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#encryption-algorithms-ciphers', 'CVE-2008-5161'],
      'aes128-cbc' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#encryption-algorithms-ciphers', 'CVE-2008-5161'],
      '[email protected]' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#encryption-algorithms-ciphers', 'CVE-2008-5161'],
      'blowfish-cbc' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#encryption-algorithms-ciphers', 'CVE-2008-5161'],
      'cast128-cbc' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#encryption-algorithms-ciphers', 'CVE-2008-5161'],
      '3des-cbc' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#encryption-algorithms-ciphers', 'CVE-2008-5161'],
      'idea-cbc' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#encryption-algorithms-ciphers', 'CVE-2008-5161'],
      'twofish-cbc' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#encryption-algorithms-ciphers', 'CVE-2008-5161'],
      'twofish128-cbc' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#encryption-algorithms-ciphers', 'CVE-2008-5161'],
      'twofish256-cbc' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#encryption-algorithms-ciphers', 'CVE-2008-5161'],
      'blowfish-ctr' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#encryption-algorithms-ciphers'],
      'cast128-ctr' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#encryption-algorithms-ciphers'],
      '3des-ctr' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#encryption-algorithms-ciphers'],
      'none' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#encryption-algorithms-ciphers']
    }

    server_data[:encryption_server].each do |encryption|
      note = ''
      encryption_checks.each do |bad_enc, refs|
        next unless encryption.downcase == bad_enc

        vprint_good("#{target_host} - Encryption #{encryption} is deprecated and should not be used.")
        report_vuln(
          host: target_host,
          port: rport,
          proto: 'tcp',
          name: name,
          info: "Module #{fullname} confirmed SSH Encryption #{encryption} is available, but should be deprecated",
          refs: refs
        )
        note = 'Deprecated'
      end
      table << ['encryption.encryption', encryption, note]
    end
    table
  end

  def check_kex(server_data)
    table = []
    kex_checks = {
      'gss-group1-sha1-*' => ['https://datatracker.ietf.org/doc/html/rfc8732#name-deprecated-algorithms'],
      'gss-group14-sha1-gss-gex-sha1-*' => ['https://datatracker.ietf.org/doc/html/rfc8732#name-deprecated-algorithms'],
      'gss-gex-sha1-*' => ['https://datatracker.ietf.org/doc/html/rfc8732#name-deprecated-algorithms'],
      'ecdsa-sha2-nistp521' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#key-exchange'],
      'ecdsa-sha2-nistp384' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#key-exchange'],
      'ecdsa-sha2-nistp256' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#key-exchange'],
      'diffie-hellman-group-exchange-sha1' => ['https://datatracker.ietf.org/doc/html/draft-ietf-curdle-ssh-kex-sha2-20#page-16'],
      'diffie-hellman-group1-sha1' => ['https://datatracker.ietf.org/doc/html/draft-ietf-curdle-ssh-kex-sha2-20#page-16'],
      'rsa1024-sha1' => ['https://datatracker.ietf.org/doc/html/draft-ietf-curdle-ssh-kex-sha2-20#page-16']
    }
    server_data[:kex].each do |kex|
      note = ''
      kex_checks.each do |bad_kex, refs|
        if bad_kex.ends_with? '*'
          next unless kex.downcase.start_with? bad_kex[0..-2]
        else
          next unless kex.downcase == bad_kex
        end

        vprint_good("#{target_host} - Key Exchange (kex) #{kex} is deprecated and should not be used.")
        report_vuln(
          host: target_host,
          port: rport,
          proto: 'tcp',
          name: name,
          info: "Module #{fullname} confirmed SSH Encryption #{kex} is available, but should be deprecated",
          refs: refs
        )
        note = 'Deprecated'
      end
      table << ['encryption.key_exchange', kex, note]
    end
    table
  end

  def check_hmac(server_data)
    table = []

    hmac_checks = {
      'hmac-sha2-512-96' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#message-authentication-code-algorithms'],
      'hmac-sha2-256-96' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#message-authentication-code-algorithms'],
      'hmac-sha1-96' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#message-authentication-code-algorithms'],
      'hmac-ripemd160' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#message-authentication-code-algorithms'],
      'hmac-md5' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#message-authentication-code-algorithms'],
      'hmac-md5-96' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#message-authentication-code-algorithms'],
      'none' => ['https://github.com/net-ssh/net-ssh?tab=readme-ov-file#message-authentication-code-algorithms']
    }

    server_data[:hmac_server].each do |hmac|
      note = ''
      hmac_checks.each do |bad_hmac, refs|
        next unless hmac.downcase == bad_hmac

        vprint_good("#{target_host} - HMAC #{hmac} is deprecated and should not be used.")
        report_vuln(
          host: target_host,
          port: rport,
          proto: 'tcp',
          name: name,
          info: "Module #{fullname} confirmed SSH HMAC #{hmac} is available, but should be deprecated",
          refs: refs
        )
        note = 'Deprecated'
      end
      table << ['encryption.hmac', hmac, note]
    end
    table
  end

  def run_host(target_host)
    ::Timeout.timeout(timeout) do
      transport = Net::SSH::Transport::Session.new(target_host, { port: rport })

      server_data = transport.algorithms.instance_variable_get(:@server_data)
      host_keys = transport.algorithms.session.instance_variable_get(:@host_keys).instance_variable_get(:@host_keys)
      host_keys.each do |host_key|
        print_status("#{target_host} - Key Fingerprint: #{host_key.ssh_type} #{Base64.strict_encode64(host_key.to_blob)}")
      end

      ident = transport.server_version.version

      print_status("#{target_host} - SSH server version: #{ident}")

      report_service(host: target_host, port: rport, name: 'ssh', proto: 'tcp', info: ident)

      return unless datastore['EXTENDED_CHECKS']

      table = Rex::Text::Table.new(
        'Header' => 'Server Information and Encryption',
        'Indent' => 2,
        'SortIndex' => 0,
        'Columns' => %w[Type Value Note]
      )

      # if these ever get expanded to have checks, they should be moved to their own function
      server_data[:language_server].each do |language|
        table << ['encryption.language', language, '']
      end

      # if these ever get expanded to have checks, they should be moved to their own function
      server_data[:compression_server].each do |compression|
        table << ['encryption.compression', compression, '']
      end

      table.rows.concat check_kex(server_data)

      table.rows.concat check_host_key(server_data)

      table.rows.concat check_hmac(server_data)

      table.rows.concat check_encryption(server_data)

      table.rows.concat perform_recog(ident)

      # XXX check for host key size?
      # h00die - not sure how to get that info from the library.
      # https://www.tenable.com/plugins/nessus/153954

      print_status("#{target_host} - #{table}")
    end
  rescue EOFError, Rex::ConnectionError => e
    vprint_error("#{target_host} - #{e.message}") # This may be a little noisy, but it is consistent
  rescue Timeout::Error
    vprint_warning("#{target_host} - Timed out after #{timeout} seconds. Skipping.")
  end
end

6.9 Medium

AI Score

Confidence

Low

2.6 Low

CVSS2

Access Vector

NETWORK

Access Complexity

HIGH

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

NONE

Availability Impact

NONE

AV:N/AC:H/Au:N/C:P/I:N/A:N

0.123 Low

EPSS

Percentile

95.3%