Module: Msf::Exploit::Remote::SMB::Client::KerberosAuthentication

Defined in:
lib/msf/core/exploit/remote/smb/client/kerberos_authentication.rb

Overview

This class implements an override for RubySMB's default authentication method to instead use a kerberos authenticator

Instance Method Summary collapse

Instance Method Details

#authenticateObject

Raises:

  • (::RubySMB::Error::AuthenticationFailure)


13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/msf/core/exploit/remote/smb/client/kerberos_authentication.rb', line 13

def authenticate
  raise ::RubySMB::Error::AuthenticationFailure, "Missing negotiation security buffer" if negotiation_security_buffer.nil?

  begin
    gss_api = OpenSSL::ASN1.decode(negotiation_security_buffer)
    mech_types = RubySMB::Gss.asn1dig(gss_api, 1, 0, 0, 0)&.value || []
    has_kerberos_gss_mech_type = mech_types&.any? { |mech_type| mech_type.value == ::Rex::Proto::Gss::OID_MICROSOFT_KERBEROS_5.value }
  rescue OpenSSL::ASN1::ASN1Error
    raise ::Rex::Proto::Kerberos::Model::Error::KerberosDecodingError.new('Invalid GSS Response')
  end

  error = "Unable to negotiate kerberos with the remote host. Expected oid #{::Rex::Proto::Gss::OID_MICROSOFT_KERBEROS_5.value} in #{mech_types.map(&:value).inspect}"
  raise ::RubySMB::Error::AuthenticationFailure, error unless has_kerberos_gss_mech_type

  if smb1
    smb1_authenticate
  else
    smb2_authenticate
  end
end

#kerberos_authenticator=(kerberos_authenticator) ⇒ Object

Parameters:



9
10
11
# File 'lib/msf/core/exploit/remote/smb/client/kerberos_authentication.rb', line 9

def kerberos_authenticator=(kerberos_authenticator)
  @kerberos_authenticator = kerberos_authenticator
end

#smb1_authenticateObject

Handles SMB1 Kerberos Authentication by delegating to a kerberos_authenticator implementation to generate a GSS security blob with an embedded AP_REQ. On success information is stored about the peer/server.

Raises:

  • (::RubySMB::Error::AuthenticationFailure)


41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/msf/core/exploit/remote/smb/client/kerberos_authentication.rb', line 41

def smb1_authenticate
  raise ::RubySMB::Error::AuthenticationFailure, 'Missing kerberos authenticator' unless @kerberos_authenticator

  kerberos_result = @kerberos_authenticator.authenticate

  @application_key = @session_key = kerberos_result[:session_key].value[0...16]

  raw_kerberos_response = smb1_kerberos_authenticate(kerberos_result[:security_blob])
  response = smb1_session_setup_response(raw_kerberos_response)
  @kerberos_authenticator.validate_response!(response.data_block.security_blob)

  response_code = response.status_code

  # Store the available OS information before going forward.
  @peer_native_os = response.data_block.native_os.to_s
  @peer_native_lm = response.data_block.native_lan_man.to_s

  @user_id = response.smb_header.uid if response_code == WindowsError::NTStatus::STATUS_SUCCESS

  response_code
end

#smb1_kerberos_authenticate(security_buffer) ⇒ String

Returns the raw binary response from the server.

Parameters:

  • type3_message (String)

    the NTLM Type 3 message

  • user_id (Integer)

    the temporary user ID from the Type 2 response

Returns:

  • (String)

    the raw binary response from the server



67
68
69
70
# File 'lib/msf/core/exploit/remote/smb/client/kerberos_authentication.rb', line 67

def smb1_kerberos_authenticate(security_buffer)
  packet = smb1_kerberos_authenticate_packet(security_buffer)
  send_recv(packet)
end

#smb1_kerberos_authenticate_packet(security_blob) ⇒ RubySMB::SMB1::Packet::SessionSetupRequest

Generates the RubySMB::SMB1::Packet::SessionSetupRequest packet with the NTLM Type 3 (Auth) message in the security_blob field.

Parameters:

  • type3_message (String)

    the NTLM Type 3 message

  • user_id (Integer)

    the temporary user ID from the Type 2 response

Returns:

  • (RubySMB::SMB1::Packet::SessionSetupRequest)

    the second authentication packet to send



78
79
80
81
82
83
84
85
86
# File 'lib/msf/core/exploit/remote/smb/client/kerberos_authentication.rb', line 78

def smb1_kerberos_authenticate_packet(security_blob)
  packet = RubySMB::SMB1::Packet::SessionSetupRequest.new
  # packet.smb_header.uid = user_id
  packet.set_security_buffer(security_blob)
  packet.parameter_block.max_buffer_size = self.max_buffer_size
  packet.parameter_block.max_mpx_count = 50
  packet.smb_header.flags2.extended_security = 1
  packet
end

#smb2_authenticateObject

Handles SMB2 Kerberos Authentication by delegating to a kerberos_authenticator implementation to generate a GSS security blob with an embedded AP_REQ. On success information is stored about the peer/server.

Raises:

  • (::RubySMB::Error::AuthenticationFailure)


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
144
145
146
147
# File 'lib/msf/core/exploit/remote/smb/client/kerberos_authentication.rb', line 95

def smb2_authenticate
  raise ::RubySMB::Error::AuthenticationFailure, 'Missing kerberos authenticator' unless @kerberos_authenticator

  kerberos_result = @kerberos_authenticator.authenticate

  raw_kerberos_response = smb2_kerberos_authenticate(kerberos_result[:security_blob])
  response = smb2_session_setup_response(raw_kerberos_response)
  @kerberos_authenticator.validate_response!(response.buffer)

  @session_id = response.smb2_header.session_id
  if @encryption_algorithm.present?
    key_len = OpenSSL::Cipher.new(@encryption_algorithm).key_len
  else
    key_len = 16
  end
  @application_key = @session_key = kerberos_result[:session_key].value[0...key_len]

  @session_is_guest = response.session_flags.guest == 1

  if @smb3
    if response.session_flags.encrypt_data == 1
      # if the server indicates that encryption is required, enable it
      @session_encrypt_data = true
    elsif (@session_is_guest && password != '') || (username == '' && password == '')
      # disable encryption when necessary
      @session_encrypt_data = false
    end

    # see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/7fd079ca-17e6-4f02-8449-46b606ea289c
    if @dialect == '0x0300' || @dialect == '0x0302'
      @application_key = RubySMB::Crypto::KDF.counter_mode(
        @session_key,
        "SMB2APP\x00",
        "SmbRpc\x00"
      )
    else
      @application_key = RubySMB::Crypto::KDF.counter_mode(
        @session_key,
        "SMBAppKey\x00",
        @preauth_integrity_hash_value
      )
    end
    # otherwise, leave encryption to the default value that it was initialized to
  end
  ######
  # DEBUG
  #puts "Session ID = #{@session_id.to_binary_s.each_byte.map {|e| '%02x' % e}.join}"
  #puts "Session key = #{@session_key.each_byte.map {|e| '%02x' % e}.join}"
  #puts "PreAuthHash = #{@preauth_integrity_hash_value.each_byte.map {|e| '%02x' % e}.join}" if @preauth_integrity_hash_value
  ######

  response.status_code
end

#smb2_kerberos_authenticate(security_blob) ⇒ Object



156
157
158
159
160
161
162
163
# File 'lib/msf/core/exploit/remote/smb/client/kerberos_authentication.rb', line 156

def smb2_kerberos_authenticate(security_blob)
  packet = smb2_kerberos_authenticate_packet(security_blob)
  response = send_recv(packet)
  if @dialect == '0x0311'
    update_preauth_hash(packet)
  end
  response
end

#smb2_kerberos_authenticate_packet(security_blob) ⇒ Object



149
150
151
152
153
154
# File 'lib/msf/core/exploit/remote/smb/client/kerberos_authentication.rb', line 149

def smb2_kerberos_authenticate_packet(security_blob)
  packet = RubySMB::SMB2::Packet::SessionSetupRequest.new
  packet.set_security_buffer(security_blob)
  packet.security_mode.signing_enabled = 1
  packet
end