lib/apullo/fingerprints/ssh.rb in apullo-0.1.5 vs lib/apullo/fingerprints/ssh.rb in apullo-0.2.0

- old
+ new

@@ -1,36 +1,42 @@ # frozen_string_literal: true +require "mem" require "ssh_scan" +require "uri" module Apullo module Fingerprint class SSH < Base + include Mem + DEFAULT_OPTIONS = { "timeout" => 3 }.freeze DEFAULT_PORTS = [22, 2222].freeze private def build_results - pluck_fingerprints + results = fingerprints + results = results.merge(meta: { links: links }) unless results.empty? + results end - def pluck_fingerprints + def fingerprints result = scan keys = result.dig("keys") || {} keys.map do |cipher, data| - raw = data.dig("raw") fingerprints = data.dig("fingerprints") || [] normalized_fingerprints = fingerprints.map do |hash, value| [hash, value.delete(":")] end.to_h [ cipher, - { raw: raw, fingerprints: normalized_fingerprints } + normalized_fingerprints ] end.to_h end + memoize :fingerprints def _scan(target, port: 22) return nil unless target.host engine = SSHScan::ScanEngine.new @@ -44,9 +50,35 @@ result = _scan(target, port: port) keys = result.dig("keys") || {} return result unless keys.empty? end {} + end + + def shodan_link + uri = URI("https://www.shodan.io/search") + fingerprint = fingerprints.dig("rsa", "md5") || fingerprints.dig("ecdsa-sha2-nistp256", "md5") + return nil unless fingerprint + + fingerprint = fingerprint.to_s.chars.each_slice(2).map(&:join).join(":") + uri.query = URI.encode_www_form(query: "port:22 #{fingerprint}") + uri.to_s + end + + def censys_link + uri = URI("https://censys.io/ipv4") + fingerprint = fingerprints.dig("ecdsa-sha2-nistp256", "sha256") || fingerprints.dig("rsa", "sha256") + return nil unless fingerprint + + uri.query = URI.encode_www_form(q: fingerprint.to_s) + uri.to_s + end + + def links + { + shodan: shodan_link, + censys: censys_link + } end end end end