Generated from Manticore v1.1.6 • 388 packages. View on pkg.go.dev

pac

import "github.com/TheManticoreProject/Manticore/network/kerberos/v5/pac"

Package pac parses, builds, and verifies the Microsoft Privilege Attribute Certificate (PAC, [MS-PAC]) carried in a Kerberos ticket’s authorization data.

A PAC is a PACTYPE container (little-endian, NOT NDR at the container level): a cBuffers/Version header followed by a table of PAC_INFO_BUFFER entries, each pointing at an 8-byte-aligned buffer. Individual buffers such as the logon info (KERB_VALIDATION_INFO) are themselves NDR-encoded; this package exposes those buffers as raw bytes and additionally NDR-decodes the logon info into a typed KERB_VALIDATION_INFO via PAC.LogonInfo (see logoninfo.go).

The security-relevant operations — the Server and KDC signatures ([MS-PAC] 2.8, “Generation of PAC Signatures”) — are implemented: both are keyed checksums with key usage KERB_NON_KERB_CKSUM_SALT (17); the server signature covers the entire PAC with all signature buffers’ Signature fields zeroed, and the KDC signature counter-signs the server signature.

Index

Constants

PAC_INFO_BUFFER ulType values ([MS-PAC] 2.4).

const (
    BufferLogonInfo           = 0x00000001 // KERB_VALIDATION_INFO (NDR)
    BufferCredentials         = 0x00000002 // PAC_CREDENTIAL_INFO
    BufferServerChecksum      = 0x00000006 // server signature
    BufferKDCChecksum         = 0x00000007 // KDC (krbtgt) signature
    BufferClientInfo          = 0x0000000A // PAC_CLIENT_INFO
    BufferConstrainedDeleg    = 0x0000000B // S4U_DELEGATION_INFO
    BufferUPNDNSInfo          = 0x0000000C // UPN_DNS_INFO
    BufferClientClaims        = 0x0000000D // client claims
    BufferDeviceInfo          = 0x0000000E // PAC_DEVICE_INFO
    BufferDeviceClaims        = 0x0000000F // device claims
    BufferTicketChecksum      = 0x00000010 // ticket signature
    BufferAttributesInfo      = 0x00000011 // PAC_ATTRIBUTES_INFO
    BufferRequestorSID        = 0x00000012 // PAC_REQUESTOR
    BufferExtendedKDCChecksum = 0x00000013 // extended KDC (full-PAC) signature
)

DefaultGroupAttributes marks a group as mandatory, enabled by default, and enabled (SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED), the attribute set Windows assigns to a user’s group memberships in the PAC.

const DefaultGroupAttributes uint32 = 0x00000007

func MarshalClientInfo

func MarshalClientInfo(clientID time.Time, name string) []byte

MarshalClientInfo lays out a PAC_CLIENT_INFO buffer ([MS-PAC] 2.7): a little-endian FILETIME ClientId (the TGT authentication time), a 16-bit NameLength in bytes, and the client account name as UTF-16LE. This buffer is not NDR-encoded.

func MarshalKerbValidationInfo

func MarshalKerbValidationInfo(info *KERB_VALIDATION_INFO) ([]byte, error)

MarshalKerbValidationInfo NDR-encodes the logon info under type serialization version 1 ([MS-RPCE] 2.2.6): the CommonTypeHeader and PrivateHeaderForConstruct edType frame the NDR body, which is padded to an 8-octet boundary.

func SignatureTypeForEType

func SignatureTypeForEType(etype int) (sigType uint32, size int, ok bool)

SignatureTypeForEType returns the PAC signature type ([MS-PAC] 2.8) and its byte length for a signing key of the given Kerberos encryption type: HMAC-MD5 for RC4, HMAC-SHA1-96 for the AES enctypes. It reports false for unsupported enctypes.

type Buffer

Buffer is one PAC_INFO_BUFFER and its contents.

type Buffer struct {
    Type   uint32
    Offset uint64 // offset from the start of the PAC (informational after Parse)
    Data   []byte
}

type CredentialInfo

CredentialInfo is a parsed PAC_CREDENTIAL_INFO buffer ([MS-PAC] §2.6.1).

type CredentialInfo struct {
    // Version is the structure version (0).
    Version uint32
    // EncryptionType is the etype of SerializedData (the AS reply key's etype).
    EncryptionType uint32
    // SerializedData is the encrypted PAC_CREDENTIAL_DATA.
    SerializedData []byte
}

func ParseCredentialInfo

func ParseCredentialInfo(data []byte) (*CredentialInfo, error)

ParseCredentialInfo parses a PAC_CREDENTIAL_INFO buffer.

func (*CredentialInfo) DecryptCredentialData

func (ci *CredentialInfo) DecryptCredentialData(replyKey []byte) ([]byte, error)

DecryptCredentialData decrypts a PAC_CREDENTIAL_INFO’s SerializedData with the AS reply key (the PKINIT-derived key), yielding the NDR-serialized PAC_CREDENTIAL_DATA. The key usage is KERB_NON_KERB_SALT (16) per [MS-PAC].

type FILETIME

FILETIME is the [MS-DTYP] 2.3.3 64-bit timestamp as two 32-bit halves, NDR marshaled as a structure of two ULONGs (little-endian).

type FILETIME struct {
    LowDateTime  uint32
    HighDateTime uint32
}

func FileTimeFromTime

func FileTimeFromTime(t time.Time) FILETIME

FileTimeFromTime converts a Go time to a Windows FILETIME. A zero time maps to a zero FILETIME.

func NeverExpireFileTime

func NeverExpireFileTime() FILETIME

NeverExpireFileTime is the FILETIME value (0x7FFFFFFFFFFFFFFF) used for “never” times such as LogoffTime, KickOffTime, and PasswordMustChange.

func (FILETIME) IsNever

func (f FILETIME) IsNever() bool

IsNever reports whether the FILETIME is the “never” sentinel (0x7FFFFFFFFFFFFFFF), used for LogoffTime/KickOffTime/PasswordMustChange when the corresponding limit does not apply.

func (FILETIME) Time

func (f FILETIME) Time() time.Time

Time converts the FILETIME to a Go time in UTC. A zero FILETIME (password never set) and the “never” sentinel both map to the zero time.Time, so callers can test the result with time.Time.IsZero. It is the inverse of FileTimeFromTime.

func (FILETIME) Uint64

func (f FILETIME) Uint64() uint64

Uint64 returns the FILETIME as a single 64-bit count of 100-nanosecond intervals since 1601-01-01 (the low half is the least significant).

type GROUP\_MEMBERSHIP

GROUP_MEMBERSHIP is the [MS-PAC] 2.2.2 (RID, attributes) pair naming a group the account belongs to in a domain.

type GROUP_MEMBERSHIP struct {
    RelativeId uint32
    Attributes uint32
}

type KERB\_SID\_AND\_ATTRIBUTES

KERB_SID_AND_ATTRIBUTES is the [MS-PAC] 2.2.1 (SID, attributes) pair used for ExtraSids (groups from domains other than the account domain).

type KERB_SID_AND_ATTRIBUTES struct {
    Sid        *msdtyp.RPC_SID `ndr:"unique"`
    Attributes uint32
}

type KERB\_VALIDATION\_INFO

KERB_VALIDATION_INFO is the [MS-PAC] 2.5 logon-info structure (ulType 0x00000001). It is a subset of NETLOGON_VALIDATION_SAM_INFO4; the NTLM-specific members (UserSessionKey, the User* flag bits) are zero under Kerberos. The pointer members are unique; the size_is arrays are pointers to conformant arrays whose counts follow from the paired *Count field / slice length.

type KERB_VALIDATION_INFO struct {
    LogonTime              FILETIME
    LogoffTime             FILETIME
    KickOffTime            FILETIME
    PasswordLastSet        FILETIME
    PasswordCanChange      FILETIME
    PasswordMustChange     FILETIME
    EffectiveName          RPC_UNICODE_STRING
    FullName               RPC_UNICODE_STRING
    LogonScript            RPC_UNICODE_STRING
    ProfilePath            RPC_UNICODE_STRING
    HomeDirectory          RPC_UNICODE_STRING
    HomeDirectoryDrive     RPC_UNICODE_STRING
    LogonCount             uint16
    BadPasswordCount       uint16
    UserId                 uint32
    PrimaryGroupId         uint32
    GroupCount             uint32
    GroupIds               []GROUP_MEMBERSHIP `ndr:"unique,size_is=GroupCount"`
    UserFlags              uint32
    UserSessionKey         USER_SESSION_KEY
    LogonServer            RPC_UNICODE_STRING
    LogonDomainName        RPC_UNICODE_STRING
    LogonDomainId          *msdtyp.RPC_SID `ndr:"unique"`
    Reserved1              [2]uint32
    UserAccountControl     uint32
    SubAuthStatus          uint32
    LastSuccessfulILogon   FILETIME
    LastFailedILogon       FILETIME
    FailedILogonCount      uint32
    Reserved3              uint32
    SidCount               uint32
    ExtraSids              []KERB_SID_AND_ATTRIBUTES `ndr:"unique,size_is=SidCount"`
    ResourceGroupDomainSid *msdtyp.RPC_SID           `ndr:"unique"`
    ResourceGroupCount     uint32
    ResourceGroupIds       []GROUP_MEMBERSHIP `ndr:"unique,size_is=ResourceGroupCount"`
}

func UnmarshalKerbValidationInfo

func UnmarshalKerbValidationInfo(data []byte) (*KERB_VALIDATION_INFO, error)

UnmarshalKerbValidationInfo decodes a type-serialized logon-info buffer (the output of MarshalKerbValidationInfo, or a Windows PAC’s ulType 0x01 buffer) back into a KERB_VALIDATION_INFO. It strips the 16-byte serialization headers and NDR-decodes the body.

func (*KERB_VALIDATION_INFO) AccountControl

func (k *KERB_VALIDATION_INFO) AccountControl() uint32

AccountControl returns the userAccountControl flags carried in the PAC.

func (*KERB_VALIDATION_INFO) DomainSID

func (k *KERB_VALIDATION_INFO) DomainSID() *msdtyp.RPC_SID

DomainSID returns the account domain’s SID (LogonDomainId), or nil if absent.

func (*KERB_VALIDATION_INFO) ExtraSIDs

func (k *KERB_VALIDATION_INFO) ExtraSIDs() []string

ExtraSIDs returns the ExtraSids member (SIDs from domains other than the account domain, e.g. universal groups and injected SIDs) as textual SID strings.

func (*KERB_VALIDATION_INFO) FullNameString

func (k *KERB_VALIDATION_INFO) FullNameString() string

FullNameString returns the account’s display name (FullName).

func (*KERB_VALIDATION_INFO) GroupRIDs

func (k *KERB_VALIDATION_INFO) GroupRIDs() []uint32

GroupRIDs returns the RIDs of the account’s groups in its own domain (GroupIds).

func (*KERB_VALIDATION_INFO) GroupSIDs

func (k *KERB_VALIDATION_INFO) GroupSIDs() []string

GroupSIDs returns the account’s account-domain group memberships (GroupIds) as full SID strings (domain SID + each group RID). It returns nil if the PAC has no LogonDomainId.

func (*KERB_VALIDATION_INFO) LogonDomainNameString

func (k *KERB_VALIDATION_INFO) LogonDomainNameString() string

LogonDomainNameString returns the NetBIOS name of the account’s domain.

func (*KERB_VALIDATION_INFO) LogonServerName

func (k *KERB_VALIDATION_INFO) LogonServerName() string

LogonServerName returns the NetBIOS name of the KDC that issued the ticket.

func (*KERB_VALIDATION_INFO) PrimaryGroupRID

func (k *KERB_VALIDATION_INFO) PrimaryGroupRID() uint32

PrimaryGroupRID returns the RID of the account’s primary group.

func (*KERB_VALIDATION_INFO) PrimaryGroupSID

func (k *KERB_VALIDATION_INFO) PrimaryGroupSID() string

PrimaryGroupSID returns the primary group’s SID (domain SID + PrimaryGroupId), or "" if the PAC has no LogonDomainId.

func (*KERB_VALIDATION_INFO) UserName

func (k *KERB_VALIDATION_INFO) UserName() string

UserName returns the account’s samAccountName (EffectiveName) as a Go string.

func (*KERB_VALIDATION_INFO) UserRID

func (k *KERB_VALIDATION_INFO) UserRID() uint32

UserRID returns the account’s relative identifier (UserId).

func (*KERB_VALIDATION_INFO) UserSID

func (k *KERB_VALIDATION_INFO) UserSID() string

UserSID returns the account’s SID as the domain SID with the UserId RID appended, or "" if the PAC has no LogonDomainId.

type NTLMCredential

NTLMCredential holds the LM and NT hashes recovered from a NTLM_SUPPLEMENTAL_CREDENTIAL ([MS-PAC] §2.6.4).

type NTLMCredential struct {
    // Version is the structure version (0).
    Version uint32
    // Flags indicates which hashes are present (bit 0 = LM, bit 1 = NT).
    Flags uint32
    // LMHash is the 16-byte LM hash (valid when Flags&1 != 0).
    LMHash []byte
    // NTHash is the 16-byte NT hash (valid when Flags&2 != 0).
    NTHash []byte
}

func ParseNTLMSupplementalCredential

func ParseNTLMSupplementalCredential(data []byte) (*NTLMCredential, error)

ParseNTLMSupplementalCredential extracts the NTLM_SUPPLEMENTAL_CREDENTIAL from a decrypted PAC_CREDENTIAL_DATA blob.

PAC_CREDENTIAL_DATA is NDR type-serialized ([MS-PAC] §2.6.2): a 16-byte type serialization header, then CredentialCount and an array of SECPKG_SUPPLEMENTAL_CRED. For the single “NTLM” package Windows emits, the deferred Credentials byte array is the 40-byte NTLM_SUPPLEMENTAL_CREDENTIAL (Version, Flags, LM[16], NT[16]); it is the final conformant array in the buffer, located here via its 4-byte MaximumCount prefix.

type PAC

PAC is a parsed PACTYPE container.

type PAC struct {
    Version uint32
    Buffers []Buffer
    // contains filtered or unexported fields
}

func Forge

func Forge(info *KERB_VALIDATION_INFO, clientName string, clientAuthTime time.Time, signEType int) (*PAC, error)

Forge assembles an unsigned PAC from an NDR-encoded logon info and the client principal, with empty server (0x06) and KDC (0x07) signature buffers sized for signEType. Call Sign(serverKey, kdcKey) on the result to fill the signatures and obtain the final marshaled PAC. For a golden ticket both keys are the krbtgt key; for a silver ticket both are the service account key.

func Parse

func Parse(data []byte) (*PAC, error)

Parse decodes a PACTYPE container. Buffer contents are copied out.

func (*PAC) Buffer

func (p *PAC) Buffer(ulType uint32) (Buffer, bool)

Buffer returns the first buffer of the given ulType.

func (*PAC) LogonInfo

func (p *PAC) LogonInfo() (*KERB_VALIDATION_INFO, error)

LogonInfo locates the logon-info buffer (PAC_INFO_BUFFER ulType 0x00000001) and NDR-decodes it into a KERB_VALIDATION_INFO ([MS-PAC] 2.5). It returns an error if the PAC has no logon-info buffer or the buffer does not decode.

func (*PAC) Marshal

func (p *PAC) Marshal() ([]byte, error)

Marshal lays out the PAC in wire form: header, PAC_INFO_BUFFER table, then each buffer’s data 8-byte aligned. It uses the buffers’ current Data verbatim (so signature buffers should already be sized and, if unsigned, zero-filled).

func (*PAC) Sign

func (p *PAC) Sign(serverKey, kdcKey []byte) ([]byte, error)

Sign fills the server signature (buffer 0x06) and then the KDC signature (buffer 0x07) in place, using the given keys. Both use key usage KERB_NON_KERB_CKSUM_SALT. The buffers must already exist, sized to 4 + checksumSize(their SignatureType). Returns the fully signed marshaled PAC.

func (*PAC) VerifyKDCSignature

func (p *PAC) VerifyKDCSignature(krbtgtKey []byte) error

VerifyKDCSignature recomputes the KDC signature with the krbtgt key (over the stored server-signature bytes) and compares it to the stored value.

func (*PAC) VerifyServerSignature

func (p *PAC) VerifyServerSignature(serverKey []byte) error

VerifyServerSignature recomputes the server signature with serverKey and compares it, in constant time, to the stored value. The PAC must have been produced by Parse (so the exact issued bytes are available).

type RPC\_UNICODE\_STRING

RPC_UNICODE_STRING is the [MS-DTYP] 2.3.10 counted Unicode string. Length and MaximumLength are byte counts; Buffer is a unique pointer to a conformant and varying array of UTF-16LE code units (no NUL terminator). The NDR array counts are derived from Buffer’s length, so callers should keep Length == MaximumLength == 2*len(Buffer) (NewUnicodeString does this).

type RPC_UNICODE_STRING struct {
    Length        uint16
    MaximumLength uint16
    Buffer        []uint16 `ndr:"unique,varying"`
}

func NewUnicodeString

func NewUnicodeString(s string) RPC_UNICODE_STRING

NewUnicodeString builds an RPC_UNICODE_STRING from a Go string, encoding it as UTF-16LE with Length and MaximumLength set to its byte length.

func (RPC_UNICODE_STRING) String

func (u RPC_UNICODE_STRING) String() string

String decodes the RPC_UNICODE_STRING to a Go string. Only the first Length/2 UTF-16 code units are significant ([MS-DTYP] 2.3.10 counts bytes, and the buffer carries no NUL terminator); any extra allocated units are dropped.

type USER\_SESSION\_KEY

USER_SESSION_KEY is the 16-byte session key ([MS-PAC] 2.2.3). It is zero for [MS-KILE] (Kerberos) authentication.

type USER_SESSION_KEY struct {
    Data [16]byte
}