Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions lib/msf/core/exploit/remote/kerberos/client.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# -*- coding: binary -*-

require 'msf/core/opt_timedelta'
require 'rex/proto/gss/kerberos_token'
require 'rex/proto/kerberos/kerberos_logger_subscriber'

module Msf
Expand All @@ -20,9 +21,9 @@ module Client
include Msf::Exploit::Remote::CertificateTrace

# https://datatracker.ietf.org/doc/html/rfc4121#section-4.1
TOK_ID_KRB_AP_REQ = "\x01\x00"
TOK_ID_KRB_AP_REP = "\x02\x00"
TOK_ID_KRB_ERROR = "\x03\x00"
TOK_ID_KRB_AP_REQ = Rex::Proto::Gss::KerberosToken::TOK_ID_KRB_AP_REQ
TOK_ID_KRB_AP_REP = Rex::Proto::Gss::KerberosToken::TOK_ID_KRB_AP_REP
TOK_ID_KRB_ERROR = Rex::Proto::Gss::KerberosToken::TOK_ID_KRB_ERROR

# https://datatracker.ietf.org/doc/html/rfc4178#section-4.2.2
NEG_TOKEN_ACCEPT_COMPLETED = 0
Expand Down
41 changes: 17 additions & 24 deletions lib/msf/core/exploit/remote/kerberos/client/ap_request.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
# -*- coding: binary -*-

require 'rex/proto/gss/kerberos_token'

module Msf
class Exploit
class Remote
module Kerberos
module Client
# Helpers for constructing and wrapping Kerberos AP-REQ messages.
module ApRequest
# https://datatracker.ietf.org/doc/html/rfc4120#section-5.5.1
AP_USE_SESSION_KEY = 0x40000000
Expand All @@ -28,33 +31,23 @@ def build_service_ap_request(opts = {})
ap_req
end

def encode_gss_kerberos_ap_request(ap_request_asn1)
ap_request_mech = wrap_pseudo_asn1(
::Rex::Proto::Gss::OID_KERBEROS_5,
TOK_ID_KRB_AP_REQ + ap_request_asn1.to_der
# @param ap_request_asn1 [OpenSSL::ASN1::ASN1Data] the ASN.1 AP-REQ
# @param ap_request_der [String, nil] a pre-encoded AP-REQ
# @return [String] a GSS-Kerberos token
# @see https://datatracker.ietf.org/doc/html/rfc1964#section-1.1.1
def encode_gss_kerberos_ap_request(ap_request_asn1, ap_request_der: nil)
Rex::Proto::Gss::KerberosToken.build_gss_ap_req(
ap_request_der || ap_request_asn1.to_der
)
end

# @param ap_request_asn1 [Object] The ASN1 KRB_AP_REQ as defined in https://datatracker.ietf.org/doc/html/rfc1964#section-1.1.1
# @return [String] SPNEGO GSS Blob
def encode_gss_spnego_ap_request(ap_request_asn1)
ap_request_mech = encode_gss_kerberos_ap_request(ap_request_asn1)

OpenSSL::ASN1::ASN1Data.new([
::Rex::Proto::Gss::OID_SPNEGO,
OpenSSL::ASN1::ASN1Data.new([
OpenSSL::ASN1::Sequence.new([
OpenSSL::ASN1::ASN1Data.new([
OpenSSL::ASN1::Sequence.new([
::Rex::Proto::Gss::OID_MICROSOFT_KERBEROS_5
])
], 0, :CONTEXT_SPECIFIC),
OpenSSL::ASN1::ASN1Data.new([
OpenSSL::ASN1::OctetString.new(ap_request_mech)
], 2, :CONTEXT_SPECIFIC)
])
], 0, :CONTEXT_SPECIFIC)
], 0, :APPLICATION).to_der
# @param ap_request_asn1 [OpenSSL::ASN1::ASN1Data] the ASN.1 KRB_AP_REQ defined in RFC 1964 section 1.1.1
# @param ap_request_mech [String, nil] a pre-encoded GSS-Kerberos AP-REQ token
# @return [String] a SPNEGO GSS blob
# @see https://datatracker.ietf.org/doc/html/rfc4178#section-4.2.1
def encode_gss_spnego_ap_request(ap_request_asn1, ap_request_mech: nil)
ap_request_mech ||= encode_gss_kerberos_ap_request(ap_request_asn1)
Rex::Proto::Gss::KerberosToken.build_spnego_init(ap_request_mech)
end
end
end
Expand Down
4 changes: 4 additions & 0 deletions lib/rex/proto/gss.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# -*- coding: binary -*-
# frozen_string_literal: true

require 'openssl'
require 'rex/proto'

module Rex::Proto::Gss
OID_SPNEGO = OpenSSL::ASN1::ObjectId.new('1.3.6.1.5.5.2')
Expand Down
20 changes: 15 additions & 5 deletions lib/rex/proto/gss/asn1.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
# frozen_string_literal: true

require 'openssl'
require 'rex/proto'

# Helpers for the pseudo-ASN.1 framing used by GSS mechanism tokens.
module Rex::Proto::Gss::Asn1
#
# GSS has some "pseudo-asn1" to wrap up tokens. This function parses that wrapping, extracts
# the mechanism specified, and returns it and the token following it
def unwrap_pseudo_asn1(token)
start_of_token = nil
mech_id = nil
# This bit is pseudo-ASN1 - we parse up until the OID, then take note of where we got up
# This bit is pseudo-ASN1 - we parse up until the OID, then take note of where we got up
# to, and continue parsing from there.
OpenSSL::ASN1.traverse(token) do | depth, offset, header_len, length, constructed, tag_class, tag|
component = token[offset, header_len+length]
OpenSSL::ASN1.traverse(token) do |depth, offset, header_len, length, _constructed, tag_class, tag|
component = token[offset, header_len + length]
if depth == 1 && tag_class == :UNIVERSAL && tag == 6
mech_id = OpenSSL::ASN1.decode(component)
start_of_token = offset+header_len+length
start_of_token = offset + header_len + length
break
end
end

[mech_id, token[start_of_token, token.length - start_of_token]]
unless mech_id && start_of_token
raise OpenSSL::ASN1::ASN1Error, 'GSS token does not contain a top-level mechanism OID'
end

[mech_id, token.byteslice(start_of_token, token.bytesize - start_of_token)]
end

def wrap_pseudo_asn1(mech_id, token)
Expand Down
Loading
Loading