Skip to content
Draft
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
139 changes: 127 additions & 12 deletions lib/msf/core/exploit/remote/kerberos/client/tgs_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,10 @@ def build_tgs_request(opts = {})
))
end

checksum = opts.fetch(:checksum) do

build_tgs_body_checksum(body: body,
session_key: opts[:session_key],
cksum_key_usage: Rex::Proto::Kerberos::Crypto::KeyUsage::TGS_REQ_PA_TGS_REQ_AP_REQ_AUTHENTICATOR_CHKSUM)
end
checksum = opts.fetch(:checksum)
checksum ||= build_tgs_body_checksum(body: body,
session_key: opts[:session_key],
cksum_key_usage: Rex::Proto::Kerberos::Crypto::KeyUsage::TGS_REQ_PA_TGS_REQ_AP_REQ_AUTHENTICATOR_CHKSUM)

authenticator = opts.fetch(:authenticator) do
build_authenticator(opts.merge(
Expand All @@ -70,10 +68,62 @@ def build_tgs_request(opts = {})

pa_data = []
pa_data.push(pa_ap_req)

if opts.fetch(:dmsa)
x509_user = Rex::Proto::Kerberos::Model::PreAuthS4Ux509User.new(opts[:session_key], opts[:impersonate], realm, opts[:nonce], dmsa: true)

pa_data_x509_user = Rex::Proto::Kerberos::Model::PreAuthDataEntry.new(
type: Rex::Proto::Kerberos::Model::PreAuthType::PA_S4U_X509_USER,
value: x509_user.encode
)

pa_data << pa_data_x509_user

pa_pac_options_flags = Rex::Proto::Kerberos::Model::PreAuthPacOptionsFlags.from_flags(
[
Rex::Proto::Kerberos::Model::PreAuthPacOptionsFlags::BRANCH_AWARE
]
)

pa_pac_options = Rex::Proto::Kerberos::Model::PreAuthPacOptions.new(
flags: pa_pac_options_flags
)

pa_pac = Rex::Proto::Kerberos::Model::PreAuthDataEntry.new(
type: Rex::Proto::Kerberos::Model::PreAuthType::PA_PAC_OPTIONS,
value: pa_pac_options.encode
)

pa_data << pa_pac
else
###################### ADDED FOR TESTING FINAL TGS REQUESTING - should likely be behind a dMSA flag \/ \/ \/ \/ \/
pa_pac_options_flags = Rex::Proto::Kerberos::Model::PreAuthPacOptionsFlags.from_flags(
[
Rex::Proto::Kerberos::Model::PreAuthPacOptionsFlags::BRANCH_AWARE
]
)

pa_pac_options = Rex::Proto::Kerberos::Model::PreAuthPacOptions.new(
flags: pa_pac_options_flags
)

pa_pac = Rex::Proto::Kerberos::Model::PreAuthDataEntry.new(
type: Rex::Proto::Kerberos::Model::PreAuthType::PA_PAC_OPTIONS,
value: pa_pac_options.encode
)

pa_data << pa_pac
###################### ADDED FOR TESTING FINAL TGS REQUESTING - should likely be behind a dMSA flag ^^^^^^
end


if opts[:pa_data]
opts[:pa_data].each { |pa| pa_data.push(pa) }
end


print_tgs_req_debug(body: body, pa_data: pa_data)

request = Rex::Proto::Kerberos::Model::KdcRequest.new(
pvno: 5,
msg_type: Rex::Proto::Kerberos::Model::TGS_REQ,
Expand All @@ -84,6 +134,64 @@ def build_tgs_request(opts = {})
request
end

def print_tgs_req_debug(body:, pa_data: [])
puts "=== TGS-REQ Debug Output ==="

puts " PA-DATA:"
Array(pa_data).each_with_index do |pa, idx|
puts " PA-DATA[#{idx}]:"
puts " type: #{pa.type}"
puts " value: #{pa.value.unpack1("H*")}"
end

puts " kdc-options: #{body.options.value.to_s(16)}"

if body.cname
puts " cname:"
puts " name-type: #{body.cname.name_type}"
puts " name-string: #{body.cname.name_string.join('/')}"
else
puts " cname: null"
end

puts " realm: #{body.realm}"

if body.sname
puts " sname:"
puts " name-type: #{body.sname.name_type}"
puts " name-string: #{body.sname.name_string.join('/')}"
else
puts " sname: null"
end

puts " from: #{body.from ? body.from.utc.iso8601 : 'null'}"
puts " till: #{body.till ? body.till.utc.iso8601 : 'null'}"
puts " rtime: #{body.rtime ? body.rtime.utc.iso8601 : 'null'}"

puts " nonce: #{body.nonce || 'null'}"

etypes = body.etype || []
puts " etypes: [#{etypes.join(', ')}]"

if body.respond_to?(:additional_tickets) && body.additional_tickets&.any?
puts " additional-tickets:"
body.additional_tickets.each_with_index do |ticket, i|
encoded = ticket.encode rescue '[error encoding]'
puts " - Ticket[#{i}]: #{Rex::Text.hexify(encoded, '')}"
end
end

if body.respond_to?(:enc_authorization_data) && body.enc_authorization_data
enc = body.enc_authorization_data
puts " enc-authorization-data:"
puts " etype: #{enc.etype}"
puts " cipher: #{Rex::Text.hexify(enc.cipher)}"
end

puts "=== End Debug ==="
end


# Builds the encrypted TGS authorization data
#
# @param opts [Hash{Symbol => <Rex::Proto::Kerberos::Model::AuthorizationData, Rex::Proto::Kerberos::Model::EncryptionKey>}]
Expand Down Expand Up @@ -237,10 +345,11 @@ def build_subkey(opts={})
# @see Rex::Proto::Kerberos::Model::PrincipalName
# @see Rex::Proto::Kerberos::Model::KdcRequestBody
def build_tgs_request_body(opts = {})
options = opts.fetch(:options) { 0x50800000 } # Forwardable, Proxiable, Renewable
from = opts.fetch(:from) { Time.at(0).utc }
#options = opts.fetch(:options) { 0x50800000 } # Forwardable, Proxiable, Renewable
options = opts.fetch(:options) { 0x60810010 } # Forwardable, Proxiable, Renewable
# from = opts.fetch(:from) { Time.at(0).utc }
till = opts.fetch(:till) { Time.at(0).utc }
rtime = opts.fetch(:rtime) { Time.at(0).utc }
# rtime = opts.fetch(:rtime) { Time.at(0).utc }
nonce = opts.fetch(:nonce) { Rex::Text.rand_text_numeric(6).to_i }
etype = opts.fetch(:etype) { [Rex::Proto::Kerberos::Crypto::Encryption::DefaultEncryptionType] }
cname = opts.fetch(:cname) { build_client_name(opts) }
Expand All @@ -254,15 +363,22 @@ def build_tgs_request_body(opts = {})
cname: cname,
realm: realm,
sname: sname,
from: from,
#from: from,
till: till,
rtime: rtime,
#rtime: rtime,
nonce: nonce,
etype: etype,
enc_auth_data: enc_auth_data,
additional_tickets: additional_tickets
)

# Do what rubeus does - for now - just debugging
body.etype.add(18)
body.etype.add(17)
body.etype.add(23)
#body.etype.add(24) - not defined currently - maybe define it?


body
end

Expand Down Expand Up @@ -330,7 +446,6 @@ def build_pa_for_user(opts = {})
value: pa_for_user.encode
)
end

end
end
end
Expand Down
45 changes: 33 additions & 12 deletions lib/msf/core/exploit/remote/kerberos/service_authenticator/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ def request_tgs_only(credential, options = {})
def s4u2self(credential, options = {})
realm = self.realm.upcase
sname = options.fetch(:sname)
dmsa = options.fetch(:dmsa, nil)
client_name = username

now = Time.now.utc
Expand All @@ -430,16 +431,24 @@ def s4u2self(credential, options = {})
etypes = Set.new([credential.keyblock.enctype.value])
etypes << Rex::Proto::Kerberos::Crypto::Encryption::RC4_HMAC

unless dmsa
pa_data = build_pa_for_user( {
username: options[:impersonate],
session_key: session_key,
realm: realm
}
)
end



tgs_options = {
ticket_storage: options.fetch(:ticket_storage, @ticket_storage),
credential_cache_username: options[:impersonate],
pa_data: build_pa_for_user(
{
username: options[:impersonate],
session_key: session_key,
realm: realm
}
)
pa_data: pa_data,
nonce: options[:nonce],
impersonate: options[:impersonate],
dmsa: dmsa
}

request_service_ticket(
Expand Down Expand Up @@ -678,6 +687,10 @@ def request_service_ticket(session_key, tgt_ticket, realm, client_name, etypes,
Rex::Proto::Kerberos::Model::KdcOptionFlags::FORWARDABLE,
Rex::Proto::Kerberos::Model::KdcOptionFlags::RENEWABLE,
Rex::Proto::Kerberos::Model::KdcOptionFlags::CANONICALIZE,
Rex::Proto::Kerberos::Model::KdcOptionFlags::FORWARDED,
# Rex::Proto::Kerberos::Model::KdcOptionFlags::PRE_AUTHENT,
# Rex::Proto::Kerberos::Model::KdcOptionFlags::OK_AS_DELEGATE,
Rex::Proto::Kerberos::Model::KdcOptionFlags::RENEWABLE_OK,
])
if options[:additional_flags].present?
additional_flags = options[:additional_flags]
Expand All @@ -693,13 +706,16 @@ def request_service_ticket(session_key, tgt_ticket, realm, client_name, etypes,
etype: etypes,
options: ticket_options,

impersonate: options[:impersonate] || nil,
nonce: options[:nonce] || nil,

# Specify nil to ensure the KDC uses the current time for the desired starttime of the requested ticket
from: nil,
# from: Time.at(0).utc,
till: expiry_time,
rtime: nil,
# rtime: Time.at(0).utc,

# certificate time
ctime: now
#ctime: now
}
if options[:additional_tickets].present?
additional_tickets = options[:additional_tickets]
Expand All @@ -708,6 +724,9 @@ def request_service_ticket(session_key, tgt_ticket, realm, client_name, etypes,
end

tgs_options = {
dmsa: options[:dmsa] || nil,
nonce: options[:nonce] || nil,
impersonate: options[:impersonate] || nil,
session_key: session_key,
subkey: nil,
checksum: nil,
Expand All @@ -719,7 +738,7 @@ def request_service_ticket(session_key, tgt_ticket, realm, client_name, etypes,
body: build_tgs_request_body(**tgs_body_options)
}
if options[:pa_data].present?
pa_data = [options[:pa_data]] unless options[:pa_data].is_a?(::Enumerable)
pa_data = options[:pa_data].is_a?(::Enumerable) ? options[:pa_data] : [options[:pa_data]]
tgs_options[:pa_data] = pa_data
end

Expand Down Expand Up @@ -829,6 +848,7 @@ def authenticate_via_krb5_ccache_credential_tgs(credential, options = {})
def authenticate_via_krb5_ccache_credential_tgt(credential, options = {})
realm = self.realm.upcase
sname = options.fetch(:sname)
nonce = options.fetch(:nonce)
client_name = username

now = Time.now.utc
Expand All @@ -843,7 +863,8 @@ def authenticate_via_krb5_ccache_credential_tgt(credential, options = {})
etypes = Set.new([credential.keyblock.enctype.value])
tgs_options = {
pa_data: [],
ticket_storage: ticket_storage
ticket_storage: ticket_storage,
nonce: nonce
}

tgs_ticket, tgs_auth = request_service_ticket(
Expand Down
1 change: 1 addition & 0 deletions lib/rex/proto/kerberos/crypto.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ module KeyUsage
GSS_ACCEPTOR_SIGN = 23
GSS_INITIATOR_SEAL = 24
GSS_INITIATOR_SIGN = 25
PA_S4U_X509_USER = 26
end

module Checksum
Expand Down
12 changes: 12 additions & 0 deletions lib/rex/proto/kerberos/model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,15 @@ module NameType
NT_SRV_XHST = 4
# Unique ID
NT_UID = 5

NT_ENTERPRISE = 10
end

module PaS4uX509UserOptions
CHECK_LOGON_RESTRICTIONS = 0x40000000,
SIGN_REPLY = 0x20000000,
NT_AUTH_POLICY_NOT_REQUIRED = 0x10000000,
UNCONDITIONAL_DELEGATION = 0x08000000
end

# See:
Expand All @@ -65,9 +74,12 @@ module PreAuthType
PA_ETYPE_INFO2 = 19
PA_PAC_REQUEST = 128
PA_FOR_USER = 129
PA_S4U_X509_USER = 130
KEY_LIST_REP = 162
PA_SUPPORTED_ETYPES = 165
PA_PAC_OPTIONS = 167
KERB_SUPERSEDED_BY_USER = 170
DMSA_KEY_PACKAGE = 171
end

module AuthorizationDataType
Expand Down
Loading
Loading