Module: Msf::Exploit::Remote::DCERPC::KerberosAuthentication
- Defined in:
- lib/msf/core/exploit/remote/dcerpc/kerberos_authentication.rb
Overview
This class implements an override for RubySMB’s default authentication method to instead use a kerberos authenticator
Instance Attribute Summary collapse
-
#krb_encryptor ⇒ Object
Returns the value of attribute krb_encryptor.
Instance Method Summary collapse
- #auth_provider_complete_handshake(response, options) ⇒ Object
-
#auth_provider_decrypt_and_verify(dcerpc_response) ⇒ Boolean
Decrypt the value in dcerpc_response, and validate its signature.
-
#auth_provider_encrypt_and_sign(dcerpc_req) ⇒ Object
Encrypt the value in dcerpc_req, and add a valid signature to the request.
-
#auth_provider_init ⇒ Object
Initialize the auth provider using Kerberos.
- #build_ap_rep(session_key, sequence_number) ⇒ Object
- #get_auth_padding_length(plaintext_len) ⇒ Object
- #kerberos_authenticator=(kerberos_authenticator) ⇒ Object
Instance Attribute Details
#krb_encryptor ⇒ Object
Returns the value of attribute krb_encryptor.
134 135 136 |
# File 'lib/msf/core/exploit/remote/dcerpc/kerberos_authentication.rb', line 134 def krb_encryptor @krb_encryptor end |
Instance Method Details
#auth_provider_complete_handshake(response, options) ⇒ Object
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 |
# File 'lib/msf/core/exploit/remote/dcerpc/kerberos_authentication.rb', line 84 def auth_provider_complete_handshake(response, ) begin @kerberos_authenticator.validate_response!(response.auth_value, accept_incomplete: true) gss_api = OpenSSL::ASN1.decode(response.auth_value) security_blob = ::RubySMB::Gss.asn1dig(gss_api, 0, 2, 0)&.value ap_rep = Rex::Proto::Kerberos::Model::ApRep.decode(security_blob) ap_rep_enc_part = ap_rep.decrypt_enc_part(@session_key.value) rescue ::Rex::Proto::Kerberos::Model::Error::KerberosDecodingError, ::Rex::Proto::Kerberos::Model::Error::KerberosError, OpenSSL::ASN1::ASN1Error => e raise RubySMB::Dcerpc::Error::BindError, e. # raise the more context-specific BindError end server_sequence_number = ap_rep_enc_part.sequence_number # Now complete the handshake - see [MS-KILE] 3.4.5.1 - https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-kile/190ab8de-dc42-49cf-bf1b-ea5705b7a087 response_ap_rep = build_ap_rep(@session_key, server_sequence_number) wrapped_ap_rep = OpenSSL::ASN1::ASN1Data.new([ OpenSSL::ASN1::Sequence.new([ OpenSSL::ASN1::ASN1Data.new([ OpenSSL::ASN1::OctetString(response_ap_rep.encode) ], 2, :CONTEXT_SPECIFIC) ]) ], 1, :CONTEXT_SPECIFIC).to_der alter_ctx = RubySMB::Dcerpc::AlterContext.new() alter_ctx.pdu_header.call_id = @call_id add_auth_verifier(alter_ctx, wrapped_ap_rep) send_packet(alter_ctx) begin dcerpc_response = recv_struct(RubySMB::Dcerpc::AlterContextResp) rescue RubySMB::Dcerpc::Error::InvalidPacket raise RubySMB::Dcerpc::Error::BindError, e. # raise the more context-specific BindError end self.krb_encryptor = @kerberos_authenticator.(ap_rep_enc_part.subkey, @client_sequence_number, server_sequence_number, rc4_pad_style: :eight_byte_aligned) # Set the session key value on the parent class - needed for decrypting attribute values in e.g. DRSR @session_key = ap_rep_enc_part.subkey.value end |
#auth_provider_decrypt_and_verify(dcerpc_response) ⇒ Boolean
Decrypt the value in dcerpc_response, and validate its signature. This function modifies the request object in-place, and returns whether the signature was valid.
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/msf/core/exploit/remote/dcerpc/kerberos_authentication.rb', line 41 def auth_provider_decrypt_and_verify(dcerpc_response) auth_type = dcerpc_response.sec_trailer.auth_type unless [RubySMB::Dcerpc::RPC_C_AUTHN_GSS_NEGOTIATE].include?(auth_type) raise ArgumentError, "Unsupported Auth Type: #{dcerpc_response.sec_trailer.auth_type}" end encrypted_stub = get_response_full_stub(dcerpc_response) signature = dcerpc_response.auth_value data = signature + encrypted_stub begin result = self.krb_encryptor.decrypt_and_verify(data) rescue Rex::Proto::Kerberos::Model::Error::KerberosError return false end set_decrypted_packet(dcerpc_response, result) true end |
#auth_provider_encrypt_and_sign(dcerpc_req) ⇒ Object
Encrypt the value in dcerpc_req, and add a valid signature to the request. This function modifies the request object in-place, and does not return anything.
25 26 27 28 29 30 31 32 33 34 |
# File 'lib/msf/core/exploit/remote/dcerpc/kerberos_authentication.rb', line 25 def auth_provider_encrypt_and_sign(dcerpc_req) auth_pad_length = get_auth_padding_length(dcerpc_req.stub.to_binary_s.length) plain_stub = dcerpc_req.stub.to_binary_s + "\x00" * auth_pad_length , header_length, krb_pad_length = self.krb_encryptor.encrypt_and_increment(plain_stub) encrypted_stub = [header_length..-1] signature = [0,header_length] set_encrypted_packet(dcerpc_req, encrypted_stub, auth_pad_length) set_signature_on_packet(dcerpc_req, signature) end |
#auth_provider_init ⇒ Object
Initialize the auth provider using Kerberos
15 16 17 18 19 20 |
# File 'lib/msf/core/exploit/remote/dcerpc/kerberos_authentication.rb', line 15 def auth_provider_init kerberos_result = @kerberos_authenticator.authenticate @application_key = @session_key = kerberos_result[:session_key] @client_sequence_number = kerberos_result[:client_sequence_number] kerberos_result[:security_blob] end |
#build_ap_rep(session_key, sequence_number) ⇒ Object
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/msf/core/exploit/remote/dcerpc/kerberos_authentication.rb', line 60 def build_ap_rep(session_key, sequence_number) pvno = Rex::Proto::Kerberos::Model::VERSION msg_type = Rex::Proto::Kerberos::Model::AP_REP ctime = Time.now.utc cusec = ctime&.usec encrypted_part = Rex::Proto::Kerberos::Model::EncApRepPart.new( ctime: ctime, cusec: cusec, sequence_number: sequence_number, enc_key_usage: Rex::Proto::Kerberos::Crypto::KeyUsage::AP_REP_ENCPART ) enc_aprep = Rex::Proto::Kerberos::Model::EncryptedData.new( etype: session_key.type, cipher: encrypted_part.encrypt(session_key.type, session_key.value) ) Rex::Proto::Kerberos::Model::ApRep.new( pvno: pvno, msg_type: msg_type, enc_part: enc_aprep ) end |
#get_auth_padding_length(plaintext_len) ⇒ Object
130 131 132 |
# File 'lib/msf/core/exploit/remote/dcerpc/kerberos_authentication.rb', line 130 def get_auth_padding_length(plaintext_len) (16 - (self.krb_encryptor.calculate_encrypted_length(plaintext_len) % 16)) % 16 end |
#kerberos_authenticator=(kerberos_authenticator) ⇒ Object
9 10 11 |
# File 'lib/msf/core/exploit/remote/dcerpc/kerberos_authentication.rb', line 9 def kerberos_authenticator=(kerberos_authenticator) @kerberos_authenticator = kerberos_authenticator end |