metasploit-framework/lib/rex/proto/kerberos/keytab/krb5_keytab.rb

152 lines
4.0 KiB
Ruby

# -*- coding: binary -*-
require 'bindata'
# Models for or Krb5 keytab
module Rex::Proto::Kerberos::Keytab
class Krb5KeytabCountedOctetString < BinData::Primitive
endian :big
search_prefix :krb5_keytab
# @!attribute [rw] len
# @return [Integer]
uint16 :len, value: -> { data.length }
# @!attribute [rw] data
# @return [String]
string :data, read_length: :len
def get
data.snapshot
end
def set(v)
self.data = v
end
end
class Krb5KeytabKeyblock < BinData::Record
endian :big
search_prefix :krb5_keytab
# @!attribute [rw] enctype
# @return [Integer] The encryption type
# @see Rex::Proto::Kerberos::Crypto::Encryption
uint16 :enctype
# @return [KeytabCountedOctetString]
counted_octet_string :data
end
class Krb5KeytabEpoch < BinData::Primitive
endian :big
search_prefix :krb5_keytab
# @!attribute [rw] epoch
# @return [Integer]
uint32 :epoch
def get
Time.at(epoch)
end
def set(v)
self.epoch = v.to_i
end
end
class Krb5KeytabEntry < BinData::Record
endian :big
search_prefix :krb5_keytab
# @return [Integer] The number of bytes for the len field
LEN_FIELD_BYTE_SIZE = 4
# @!attribute [rw] len
# @return [Integer] The number of remaining bytes for this record. The length does not include the 4 bytes for this field
int32 :len,
value: -> {
size = [
count_of_components,
realm,
components,
name_type,
timestamp,
vno8,
keyblock,
vno,
flags
].sum { |field| field.to_binary_s.bytes.count }
size
}
# @!attribute [rw] count_of_components
# @return [Integer]
uint16 :count_of_components, value: -> { components.length }
# @!attribute [rw] realm#
# @return [CountedOctetString]
counted_octet_string :realm
# @!attribute [rw] components
# @return [Array<CountedOctetString>] The components in the principal name, which can be joined by slashes
# to represent the SPN
array :components, initial_length: :count_of_components, type: :counted_octet_string
# @!attribute [rw] name_type
# @return [Integer]
# @see Rex::Proto::Kerberos::Model::NameType
uint32 :name_type
# @!attribute [rw] timestamp
# @return [Integer] The time the key entry was created; Can be 0 for keytabs generated by ktpass
epoch :timestamp
# @!attribute [rw] vno8
# @return [Integer] The lower 8 bits of the version number of the key
uint8 :vno8
# @!attribute [rw] keyblock
# @return [KeytabKeyBlock]
keyblock :keyblock
# @!attribute [rw] vno
# @return [Integer]
uint32 :vno,
initial_value: -> { vno8.to_i },
# only present if >= 4 bytes left in entry
onlyif: -> { ((len + LEN_FIELD_BYTE_SIZE) - vno.rel_offset) >= 4 }
# @!attribute [rw] flags
# @return [Integer]
uint32 :flags,
# only present if >= 4 bytes left in entry
onlyif: -> { ((len + LEN_FIELD_BYTE_SIZE) - flags.rel_offset) >= 4 }
# @return [String] The principal associated with this key tab entry
def principal
"#{components.to_a.join('/')}@#{realm}"
end
end
# Definition from:
# https://web.mit.edu/kerberos/krb5-devel/doc/basic/keytab_def.html
# http://www.ioplex.com/utilities/keytab.txt
# http://web.mit.edu/freebsd/head/crypto/heimdal/doc/doxyout/krb5/html/krb5_fileformats.html
#
class Krb5Keytab < BinData::Record
endian :big
search_prefix :krb5_keytab
# Older keytab version 0x501 not currently supported
# @!attribute [r] file_format_version
# @return [Integer]
uint16 :file_format_version, asserted_value: 0x502
# @!attribute [rw] key_entries
# @return [Array<KeytabEntry>] the keytab entries
array :key_entries, type: :entry, read_until: :eof
end
end