/
credentials_info.go
132 lines (116 loc) · 4.8 KB
/
credentials_info.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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
129
130
131
132
package pac
import (
"encoding/binary"
"fmt"
"gopkg.in/jcmturner/gokrb5.v5/crypto"
"gopkg.in/jcmturner/gokrb5.v5/iana/keyusage"
"gopkg.in/jcmturner/gokrb5.v5/mstypes"
"gopkg.in/jcmturner/gokrb5.v5/ndr"
"gopkg.in/jcmturner/gokrb5.v5/types"
)
// https://msdn.microsoft.com/en-us/library/cc237931.aspx
// CredentialsInfo implements https://msdn.microsoft.com/en-us/library/cc237953.aspx
type CredentialsInfo struct {
Version uint32 // A 32-bit unsigned integer in little-endian format that defines the version. MUST be 0x00000000.
EType uint32
PACCredentialDataEncrypted []byte // Key usage number for encryption: KERB_NON_KERB_SALT (16)
PACCredentialData CredentialData
}
// Unmarshal bytes into the CredentialsInfo struct
func (c *CredentialsInfo) Unmarshal(b []byte, k types.EncryptionKey) error {
ch, _, p, err := ndr.ReadHeaders(&b)
if err != nil {
return fmt.Errorf("error parsing byte stream headers: %v", err)
}
e := &ch.Endianness
//The next 4 bytes are an RPC unique pointer referent. We just skip these
p += 4
c.Version = ndr.ReadUint32(&b, &p, e)
c.EType = ndr.ReadUint32(&b, &p, e)
c.PACCredentialDataEncrypted = ndr.ReadBytes(&b, &p, len(b)-p, e)
err = c.DecryptEncPart(k, e)
if err != nil {
return fmt.Errorf("error decrypting PAC Credentials Data: %v", err)
}
return nil
}
// DecryptEncPart decrypts the encrypted part of the CredentialsInfo.
func (c *CredentialsInfo) DecryptEncPart(k types.EncryptionKey, e *binary.ByteOrder) error {
if k.KeyType != int32(c.EType) {
return fmt.Errorf("key provided is not the correct type. Type needed: %d, type provided: %d", c.EType, k.KeyType)
}
pt, err := crypto.DecryptMessage(c.PACCredentialDataEncrypted, k, keyusage.KERB_NON_KERB_SALT)
if err != nil {
return err
}
var p int
c.PACCredentialData = ReadPACCredentialData(&pt, &p, e)
return nil
}
// CredentialData implements https://msdn.microsoft.com/en-us/library/cc237952.aspx
// This structure is encrypted prior to being encoded in any other structures.
// Encryption is performed by first serializing the data structure via Network Data Representation (NDR) encoding, as specified in [MS-RPCE].
// Once serialized, the data is encrypted using the key and cryptographic system selected through the AS protocol and the KRB_AS_REP message
// Fields (for capturing this information) and cryptographic parameters are specified in PAC_CREDENTIAL_INFO (section 2.6.1).
type CredentialData struct {
CredentialCount uint32
Credentials []SECPKGSupplementalCred // Size is the value of CredentialCount
}
// ReadPACCredentialData reads a CredentialData from the byte slice.
func ReadPACCredentialData(b *[]byte, p *int, e *binary.ByteOrder) CredentialData {
c := ndr.ReadUint32(b, p, e)
cr := make([]SECPKGSupplementalCred, c, c)
for i := range cr {
cr[i] = ReadSECPKGSupplementalCred(b, p, e)
}
return CredentialData{
CredentialCount: c,
Credentials: cr,
}
}
// SECPKGSupplementalCred implements https://msdn.microsoft.com/en-us/library/cc237956.aspx
type SECPKGSupplementalCred struct {
PackageName mstypes.RPCUnicodeString
CredentialSize uint32
Credentials []uint8 // Is a ptr. Size is the value of CredentialSize
}
// ReadSECPKGSupplementalCred reads a SECPKGSupplementalCred from the byte slice.
func ReadSECPKGSupplementalCred(b *[]byte, p *int, e *binary.ByteOrder) SECPKGSupplementalCred {
n, _ := mstypes.ReadRPCUnicodeString(b, p, e)
cs := ndr.ReadUint32(b, p, e)
c := make([]uint8, cs, cs)
for i := range c {
c[i] = ndr.ReadUint8(b, p)
}
return SECPKGSupplementalCred{
PackageName: n,
CredentialSize: cs,
Credentials: c,
}
}
// NTLMSupplementalCred implements https://msdn.microsoft.com/en-us/library/cc237949.aspx
type NTLMSupplementalCred struct {
Version uint32 // A 32-bit unsigned integer that defines the credential version.This field MUST be 0x00000000.
Flags uint32
LMPassword []byte // A 16-element array of unsigned 8-bit integers that define the LM OWF. The LmPassword member MUST be ignored if the L flag is not set in the Flags member.
NTPassword []byte // A 16-element array of unsigned 8-bit integers that define the NT OWF. The LtPassword member MUST be ignored if the N flag is not set in the Flags member.
}
// ReadNTLMSupplementalCred reads a NTLMSupplementalCred from the byte slice.
func ReadNTLMSupplementalCred(b *[]byte, p *int, e *binary.ByteOrder) NTLMSupplementalCred {
v := ndr.ReadUint32(b, p, e)
f := ndr.ReadUint32(b, p, e)
l := ndr.ReadBytes(b, p, 16, e)
n := ndr.ReadBytes(b, p, 16, e)
return NTLMSupplementalCred{
Version: v,
Flags: f,
LMPassword: l,
NTPassword: n,
}
}
const (
// NTLMSupCredLMOWF indicates that the LM OWF member is present and valid.
NTLMSupCredLMOWF = 31
// NTLMSupCredNTOWF indicates that the NT OWF member is present and valid.
NTLMSupCredNTOWF = 30
)