Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/http/cert.rb
19664 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Exploit::Remote::Tcp
8
include Msf::Auxiliary::WmapScanSSL
9
include Msf::Auxiliary::Scanner
10
include Msf::Auxiliary::Report
11
12
def initialize
13
super(
14
'Name' => 'HTTP SSL Certificate Checker',
15
'Author' => 'nebulus',
16
'License' => MSF_LICENSE,
17
'Description' => %q{
18
This module will check the certificate of the specified web servers
19
to ensure the subject and issuer match the supplied pattern and that the certificate
20
is not expired.
21
}
22
)
23
24
register_options(
25
[
26
Opt::RPORT(443),
27
OptRegexp.new('ISSUER', [ true, "Show a warning if the Issuer doesn't match this regex", '.*']),
28
OptBool.new('SHOWALL', [ false, "Show all certificates (issuer,time) regardless of match", false]),
29
]
30
)
31
end
32
33
# Fingerprint a single host
34
def run_host(ip)
35
connect(true, { "SSL" => true }) # Force SSL
36
cert = OpenSSL::X509::Certificate.new(sock.peer_cert)
37
disconnect
38
39
if (not cert)
40
print_status("#{ip} No certificate subject or CN found")
41
return
42
end
43
sub = cert.subject.to_a
44
45
before = Time.parse("#{cert.not_before}")
46
after = Time.parse("#{cert.not_after}")
47
48
now = Time.now
49
a = now <=> before
50
b = now <=> after
51
52
vhostn = 'EMPTY'
53
sub.each do |n|
54
if n[0] == 'CN'
55
vhostn = n[1]
56
end
57
end
58
59
if cert.issuer.to_s !~ /#{datastore['ISSUER'].source}/n
60
print_good("#{ip} - '#{vhostn}' : #{cert.issuer} (BAD ISSUER)")
61
elsif datastore['SHOWALL']
62
# show verbose as status
63
print_status("#{ip} - '#{vhostn}' : #{cert.issuer}")
64
end
65
66
if (a < 1 or b > 0)
67
print_good("#{ip} - '#{vhostn}' : '" + before.to_s + "' - '" + after.to_s + "' (EXPIRED)'")
68
else
69
# show verbose as status
70
print_status("#{ip} - '#{vhostn}' : '" + before.to_s + "' - '" + after.to_s + "'")
71
end
72
73
report_note(
74
:host => ip,
75
:port => rport,
76
:proto => 'tcp',
77
:type => 'http.vhost',
78
:data => { :name => vhostn }
79
) if vhostn
80
81
# Store the SSL certificate itself
82
report_note(
83
:host => ip,
84
:proto => 'tcp',
85
:port => rport,
86
:type => 'ssl.certificate',
87
:data => {
88
:cn => vhostn,
89
:subject => cert.subject.to_a,
90
:algorithm => cert.signature_algorithm
91
92
}
93
) if vhostn
94
95
# Update the server hostname if necessary
96
if vhostn !~ /localhost|snakeoil/i
97
report_host(
98
:host => ip,
99
:name => vhostn
100
)
101
end
102
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
103
rescue ::Timeout::Error, ::Errno::EPIPE
104
rescue ::OpenSSL::SSL::SSLError => e
105
return if (e.to_s.match(/^SSL_connect /)) # strange errors / exception if SSL connection aborted
106
rescue ::Exception => e
107
return if (e.to_s =~ /execution expired/)
108
109
print_error("Error: '#{ip}' '#{e.class}' '#{e}' '#{e.backtrace}'")
110
end
111
end
112
113