Files
metasploit-gs/modules/auxiliary/scanner/http/ssl.rb
T
Brent Cook af7eef231c Fix a few issues with the SSL scanner
First, we need to handle public keys with strength not measured on the same bit
scale as RSA keys. This fixes handshakes for ECDSA and others.

Second, depending on the host we are talking to, we may not have a peer cert.
Handle this properly by checking first on the socket before using it.
2016-04-04 22:08:01 -05:00

144 lines
4.2 KiB
Ruby

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class MetasploitModule < Msf::Auxiliary
include Msf::Exploit::Remote::Tcp
include Msf::Auxiliary::WmapScanSSL
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
include Rex::Socket::Comm
def initialize
super(
'Name' => 'HTTP SSL Certificate Information',
'Description' => 'Parse the server SSL certificate to obtain the common name and signature algorithm',
'Author' =>
[
'et', #original module
'Chris John Riley', #additions
'Veit Hailperin <hailperv[at]gmail.com>', # checks for public key size, valid time
],
'License' => MSF_LICENSE
)
register_options([
Opt::RPORT(443)
], self.class)
end
# Fingerprint a single host
def run_host(ip)
begin
connect(true, {"SSL" => true}) #Force SSL
if sock.respond_to? :peer_cert
cert = OpenSSL::X509::Certificate.new(sock.peer_cert)
end
disconnect
if cert
print_status("Subject: #{cert.subject}")
print_status("Issuer: #{cert.issuer}")
print_status("Signature Alg: #{cert.signature_algorithm}")
# If we use ECDSA rather than RSA, our metrics for key size are different
public_key_size = 0
if cert.public_key.respond_to? :n
public_key_size = cert.public_key.n.num_bytes * 8
print_status("Public Key Size: #{public_key_size} bits")
end
print_status("Not Valid Before: #{cert.not_before}")
print_status("Not Valid After: #{cert.not_after}")
# Checks for common properties of self signed certificates
caissuer = (/CA Issuers - URI:(.*?),/i).match(cert.extensions.to_s)
if caissuer.to_s.empty?
print_good("Certificate contains no CA Issuers extension... possible self signed certificate")
else
print_status(caissuer.to_s[0..-2])
end
if cert.issuer.to_s == cert.subject.to_s
print_good("Certificate Subject and Issuer match... possible self signed certificate")
end
alg = cert.signature_algorithm
if alg.downcase.include? "md5"
print_status("WARNING: Signature algorithm using MD5 (#{alg})")
end
vhostn = nil
cert.subject.to_a.each do |n|
vhostn = n[1] if n[0] == 'CN'
end
if public_key_size > 0
if public_key_size == 1024
print_status("WARNING: Public Key only 1024 bits")
elsif public_key_size < 1024
print_status("WARNING: Weak Public Key: #{public_key_size} bits")
end
end
if cert.not_after < Time.now
print_status("WARNING: Certificate not valid anymore")
end
if cert.not_before > Time.now
print_status("WARNING: Certificate not valid yet")
end
if vhostn
print_status("Has common name #{vhostn}")
# Store the virtual hostname for HTTP
report_note(
:host => ip,
:port => rport,
:proto => 'tcp',
:type => 'http.vhost',
:data => {:name => vhostn}
)
# Store the SSL certificate itself
report_note(
:host => ip,
:proto => 'tcp',
:port => rport,
:type => 'ssl.certificate',
:data => {
:cn => vhostn,
:subject => cert.subject.to_a,
:algorithm => alg,
:valid_from => cert.not_before,
:valid_after => cert.not_after,
:key_size => public_key_size
}
)
# Update the server hostname if necessary
if vhostn !~ /localhost|snakeoil/i
report_host(
:host => ip,
:name => vhostn
)
end
end
else
print_status("No certificate subject or common name found")
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
end
end
end