Module: Msf::Exploit::Remote::CertificateTrace
- Included in:
- HttpClient, Kerberos::Client, LDAP, MsIcpr, Postgres, RDP
- Defined in:
- lib/msf/core/exploit/remote/certificate_trace.rb
Overview
Shared helpers for tracing X.509 certificates encountered during a module run (for example the client certificate presented for PKINIT, or a certificate issued via AD CS / MS-ICPR). Registers the CertificateTrace and CertificateTraceColors advanced options and dispatches formatted, optionally colorized output through Msf::Trace::CertificateTracePresenter.
Include this mixin in any module or mixin that wants certificate tracing, then call #certificate_trace with the certificate of interest.
Instance Method Summary collapse
-
#certificate_csr_trace(csr, attributes = {}) ⇒ void
Dispatches a certificate signing request (CSR) trace at the configured verbosity level, mirroring #certificate_trace for the request side of an enrollment (e.g. AD CS / MS-ICPR).
-
#certificate_peer_cert_trace(cert, host, port, chain: nil) ⇒ void
Surfaces the server TLS peer certificate after a TLS handshake.
-
#certificate_trace(cert) ⇒ void
Dispatches a certificate trace at the configured verbosity level.
-
#certificate_trace_enabled? ⇒ Boolean
Returns true if CertificateTracePresenter is loaded and tracing is enabled.
- #initialize(info = {}) ⇒ Object
Instance Method Details
#certificate_csr_trace(csr, attributes = {}) ⇒ void
This method returns an undefined value.
Dispatches a certificate signing request (CSR) trace at the configured verbosity level, mirroring #certificate_trace for the request side of an enrollment (e.g. AD CS / MS-ICPR). Intended to be called with the CSR and enrollment attributes just before the request is submitted to the CA.
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
# File 'lib/msf/core/exploit/remote/certificate_trace.rb', line 154 def certificate_csr_trace(csr, attributes = {}) return unless certificate_trace_enabled? mode = datastore['CertificateTrace'] presenter = Msf::Trace::CertificateTracePresenter.new output = case mode when 'metadata' presenter.(csr) when 'full' presenter.to_s_csr_full(csr, attributes) else vprint_warning("Unknown CertificateTrace mode: #{mode}") nil end return unless output print_line(certificate_trace_colorize(output)) end |
#certificate_peer_cert_trace(cert, host, port, chain: nil) ⇒ void
This method returns an undefined value.
Surfaces the server TLS peer certificate after a TLS handshake. Uses CertificateTrace and CertificateTraceColors so peer cert output is consistent with issued-certificate and CSR output. Deduplicates per host:port using the database when active, falling back to in-memory dedup within a single module run when the database is not connected.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/msf/core/exploit/remote/certificate_trace.rb', line 77 def certificate_peer_cert_trace(cert, host, port, chain: nil) return unless certificate_trace_enabled? return if cert.nil? @_peer_cert_seen ||= {} key = "#{host}:#{port}" return if @_peer_cert_seen[key] db_active = respond_to?(:framework) && framework&.db&.active if db_active # Dedup across runs using a note keyed by "host:port" in its own data. # Match on the note's serialized data column (already loaded with the # row) rather than walking the host/service associations, which would # issue a separate query per note (N+1). already_noted = framework.db.notes(ntype: 'ssl.peer_cert_seen').any? do |n| n.data.is_a?(Hash) && n.data['endpoint'] == key end if already_noted @_peer_cert_seen[key] = true return end end mode = datastore['CertificateTrace'] presenter = Msf::Trace::CertificateTracePresenter.new(cert) # Label peer certs distinctly from issued (x.509) and CSR output so a # server's TLS cert is not confused with a client/issued certificate. output = case mode when 'metadata' presenter.(label: 'Peer Cert') when 'full' presenter.to_s_full(label: 'Peer Cert') else vprint_warning("Unknown CertificateTrace mode: #{mode}") nil end return unless output # Only record the endpoint as seen once we have actually produced output, # so an unknown mode or a render failure does not permanently suppress # future tracing for this host:port. @_peer_cert_seen[key] = true if db_active framework.db.report_note( host: host, port: port, proto: 'tcp', ntype: 'ssl.peer_cert_seen', data: { 'endpoint' => key }, update: :unique ) end print_line(certificate_trace_colorize(output)) return unless mode == 'full' # When chain is provided, print each intermediate / root CA cert that the # server included in the handshake. chain[0] is the leaf (already printed), # so we start from chain[1]. chain_certs = Array(chain).drop(1) chain_certs.each_with_index do |chain_cert, idx| chain_presenter = Msf::Trace::CertificateTracePresenter.new(chain_cert) chain_output = chain_presenter.to_s_full(label: "Chain #{idx + 1}/#{chain_certs.length}") next unless chain_output print_line(certificate_trace_colorize(chain_output)) end end |
#certificate_trace(cert) ⇒ void
This method returns an undefined value.
Dispatches a certificate trace at the configured verbosity level. Builds a presenter, routes to the appropriate to_s_* method, applies the configured color, then prints via the module instance.
Color convention mirrors HttpTraceColors: the second color in the “req/resp” pair is used for certificate output since a cert is always a received (response-side) artifact.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/msf/core/exploit/remote/certificate_trace.rb', line 45 def certificate_trace(cert) return unless certificate_trace_enabled? mode = datastore['CertificateTrace'] presenter = Msf::Trace::CertificateTracePresenter.new(cert) output = case mode when 'metadata' presenter. when 'full' presenter.to_s_full else vprint_warning("Unknown CertificateTrace mode: #{mode}") nil end return unless output print_line(certificate_trace_colorize(output)) end |
#certificate_trace_enabled? ⇒ Boolean
Returns true if CertificateTracePresenter is loaded and tracing is enabled.
27 28 29 30 31 32 33 |
# File 'lib/msf/core/exploit/remote/certificate_trace.rb', line 27 def certificate_trace_enabled? return false unless defined?(Msf::Trace::CertificateTracePresenter) return false unless respond_to?(:datastore) && datastore mode = datastore['CertificateTrace'] mode && mode != 'off' end |
#initialize(info = {}) ⇒ Object
13 14 15 16 17 18 19 20 21 22 |
# File 'lib/msf/core/exploit/remote/certificate_trace.rb', line 13 def initialize(info = {}) super ( [ OptEnum.new('CertificateTrace', [false, 'Certificate trace verbosity level', 'off', ['off', 'metadata', 'full']]), OptString.new('CertificateTraceColors', [false, 'Certificate trace color (e.g. red/blu, unset to disable)', 'red/blu']) ], Msf::Exploit::Remote::CertificateTrace ) end |