Comments (14)
You're unbelievable! Thank you for your work!
from go-msrpc.
@dodgyturtle fixed with 2cbdf82
from go-msrpc.
hello, @dodgyturtle. please let me know if these changes (6ebf284) worked for you.
from go-msrpc.
Thank you very much! Now the marshaling works fine. But Samba can't parse the data. I compare the marshaling result of go-msrpc with the library https://github.com/jcmturner/gokrb5/tree/master/v8/pac and they don't match. Test data from gokrb5 samba unmarshals well :(
from go-msrpc.
@dodgyturtle I guess the issue here can be with different marshaling rules for structures in PAC. some of them should be marshaled as-is (with ndr.Opaque option) some of them with NDR-applied rules (NDR headers and so on). Let me check this.
from go-msrpc.
@dodgyturtle could you please kindly point me to the proper dataset and root structure you're using in krb5 repo?
from go-msrpc.
I tried sending to Samba MarshaledPAC_AD_WIN2K_PAC and Samba unmarshals well.
After I unmarshaled MarshaledPAC_AD_WIN2K_PAC
to PACType
struct and get:
a := &ms_pac.PACInfoBuffer{
Type: 1,
BufferLength: 552,
Offset: 88,
}
b := &ms_pac.PACInfoBuffer{
Type: 10,
BufferLength: 28,
Offset: 640,
}
c := &ms_pac.PACInfoBuffer{
Type: 12,
BufferLength: 88,
Offset: 672,
}
d := &ms_pac.PACInfoBuffer{
Type: 6,
BufferLength: 16,
Offset: 760,
}
e := &ms_pac.PACInfoBuffer{
Type: 7,
BufferLength: 20,
Offset: 776,
}
pacL := &ms_pac.PACType{
BuffersCount: 5,
Version: 0x00000000,
Buffers: []*ms_pac.PACInfoBuffer{a, b, c, d, e},
}
Also I tried to check MarshaledPAC_Client_Info. I create ClientInfo
struct with:
- name:
testuser1
- ClientID:
go time.Date(2017, 5, 6, 15, 53, 11, 000000000, time.UTC)
do go ms_ndr.Marshal(clientInfo, ms_ndr.Opaque)
and get 808dd1dc80c6d2011200740065007300740075007300650072003100000000000000000000000000000000000000
instead of 808dd1dc80c6d2011200740065007300740075007300650072003100
from go-msrpc.
@dodgyturtle right, clientInfo has bug, as len(Name) * 2 is a NameLength. I was looking at the structure and found some not implemented features like Type Serialization, so you can refer to this sample: eb4a67e#diff-8808873b797eb464d7dbb45c60964f6100acb5ec85c42fcb476001c1cad52f84
Overall, as the data type is not NDR but bunch of custom formats, PACType encoder/decoder must be added manually.
I think MarshalWithTypeSerializationV1 should work, there is a slight difference on data size because PAC data in sample sends UnicodeString as non-nil pointer with Length fields set to zero, while in my implementation all such zero-strings are set to null.
from go-msrpc.
I'm currently looking into implementing something like that, but again, various data is encoded in multiple ways, so this may take some time to actually get into the working solution:
package pac
import (
"bytes"
dtyp "github.com/oiweiwei/go-msrpc/msrpc/dtyp"
ndr "github.com/oiweiwei/go-msrpc/ndr"
)
type PAC struct {
LogonInformation *KerberosValidationInfo `json:"logon_information,omitempty"`
ServerChecksum *PACSignatureData `json:"server_checksum,omitempty"`
KDCChecksum *PACSignatureData `json:"kdc_checksum,omitempty"`
ClientNameAndTicketInformation *PACClientInfo `json:"client_name_and_ticket_information,omitempty"`
ConstrainedDelegationInformation *S4UDelegationInfo `json:"constrained_delegation_information,omitempty"`
UPNAndDNSInformation *UPNDNSInfo `json:"upn_and_dns_information,omitempty"`
TicketChecksum *PACSignatureData `json:"ticket_checksum,omitempty"`
Attributes *PACAttributesInfo `json:"attributes,omitempty"`
RequestorSID *dtyp.SID `json:"requestor_sid,omitempty"`
ExtendedKDCChecksum *PACSignatureData `json:"extended_kdc_checksum,omitempty"`
RequestorGUID *dtyp.GUID `json:"requestor_guid,omitempty"`
}
func (p *PAC) Marshal() ([]byte, error) {
var pac PACType
pac.Version = 5
buf := bytes.NewBuffer(nil)
if p.LogonInformation != nil {
b, err := ndr.MarshalWithTypeSerializationV1(p.LogonInformation)
if err != nil {
return nil, err
}
buf.Write(b)
pac.Buffers = append(pac.Buffers, PACBuffer{Offset: 0, BufferLength: uint64(len(b)), Type: 0x00000001})
}
if p.ServerChecksum != nil {
b, err := ndr.Marshal(p.ServerChecksum)
if err != nil {
return nil, err
}
buf.Write(b)
pac.Buffers = append(pac.Buffers, PACBuffer{Offset: uint64(buf.Len()), BufferLength: uint64(len(b)), Type: 0x00000006})
}
if p.KDCChecksum != nil {
b, err := ndr.Marshal(p.KDCChecksum)
if err != nil {
return nil, err
}
buf.Write(b)
pac.Buffers = append(pac.Buffers, PACBuffer{Offset: uint64(buf.Len()), BufferLength: uint64(len(b)), Type: 0x00000007})
}
if p.ClientNameAndTicketInformation != nil {
b, err := ndr.Marshal(p.ClientNameAndTicketInformation)
if err != nil {
return nil, err
}
buf.Write(b)
pac.Buffers = append(pac.Buffers, PACBuffer{Offset: uint64(buf.Len()), BufferLength: uint64(len(b)), Type: 0x0000000A})
}
if p.ConstrainedDelegationInformation != nil {
b, err := ndr.Marshal(p.ConstrainedDelegationInformation)
if err != nil {
return nil, err
}
buf.Write(b)
pac.Buffers = append(pac.Buffers, PACBuffer{Offset: uint64(buf.Len()), BufferLength: uint64(len(b)), Type: 0x0000000B})
}
if p.UPNAndDNSInformation != nil {
b, err := ndr.Marshal(p.UPNAndDNSInformation)
if err != nil {
return nil, err
}
buf.Write(b)
pac.Buffers = append(pac.Buffers, PACBuffer{Offset: uint64(buf.Len()), BufferLength: uint64(len(b)), Type: 0x0000000C})
}
if p.TicketChecksum != nil {
b, err := ndr.Marshal(p.TicketChecksum)
if err != nil {
return nil, err
}
buf.Write(b)
pac.Buffers = append(pac.Buffers, PACBuffer{Offset: uint64(buf.Len()), BufferLength: uint64(len(b)), Type: 0x00000010})
}
if p.Attributes != nil {
b, err := ndr.Marshal(p.Attributes)
if err != nil {
return nil, err
}
buf.Write(b)
pac.Buffers = append(pac.Buffers, PACBuffer{Offset: uint64(buf.Len()), BufferLength: uint64(len(b)), Type: 0x00000011})
}
if p.RequestorSID != nil {
b, err := ndr.Marshal(p.RequestorSID)
if err != nil {
return nil, err
}
buf.Write(b)
pac.Buffers = append(pac.Buffers, PACBuffer{Offset: uint64(buf.Len()), BufferLength: uint64(len(b)), Type: 0x00000012})
}
if p.ExtendedKDCChecksum != nil {
b, err := ndr.Marshal(p.ExtendedKDCChecksum)
if err != nil {
return nil, err
}
buf.Write(b)
pac.Buffers = append(pac.Buffers, PACBuffer{Offset: uint64(buf.Len()), BufferLength: uint64(len(b)), Type: 0x00000013})
}
if p.RequestorGUID != nil {
b, err := ndr.Marshal(p.RequestorGUID)
if err != nil {
return nil, err
}
buf.Write(b)
pac.Buffers = append(pac.Buffers, PACBuffer{Offset: uint64(buf.Len()), BufferLength: uint64(len(b)), Type: 0x00000014})
}
for i, buffer := range pac.Buffers {
pac.Buffers[i].Offset += len(pac.Buffers) * 8
}
b, err := ndr.Marshal(pac)
if err != nil {
return nil, err
}
return append(b, buf.Bytes()...), nil
}
func (p *PAC) Unmarshal(b []byte) error {
var pac PACType
if err := ndr.Unmarshal(b, &pac, ndr.Opaque); err != nil {
return err
}
for _, buffer := range pac.Buffers {
b := b[buffer.Offset : buffer.Offset+uint64(buffer.BufferLength)]
switch buffer.Type {
case 0x00000001:
var v KerberosValidationInfo
if err := ndr.UnmarshalWithTypeSerializationV1(b, ndr.UnmarshalerPointer(&v)); err != nil {
return err
}
p.LogonInformation = &v
case 0x00000002:
// TODO: Credentials information
case 0x00000006:
var v PACSignatureData
if err := ndr.Unmarshal(b, &v, ndr.Opaque); err != nil {
return err
}
p.ServerChecksum = &v
case 0x00000007:
var v PACSignatureData
if err := ndr.Unmarshal(b, &v, ndr.Opaque); err != nil {
return err
}
p.KDCChecksum = &v
case 0x0000000A:
var v PACClientInfo
if err := ndr.Unmarshal(b, &v, ndr.Opaque); err != nil {
return err
}
p.ClientNameAndTicketInformation = &v
case 0x0000000B:
var v S4UDelegationInfo
if err := ndr.Unmarshal(b, &v, ndr.Opaque); err != nil {
return err
}
p.ConstrainedDelegationInformation = &v
case 0x0000000C:
var v UPNDNSInfo
if err := ndr.Unmarshal(b, &v, ndr.Opaque); err != nil {
return err
}
p.UPNAndDNSInformation = &v
case 0x0000000D:
var v PACClientClaimsInfo
if err := ndr.UnmarshalWithTypeSerializationV1(b, ndr.UnmarshalerPointer(&v)); err != nil {
return err
}
p.LogonInformation = &v
case 0x0000000E:
// TODO: Device information
case 0x0000000F:
// TODO: Device claims information
case 0x00000010:
var v PACSignatureData
if err := ndr.Unmarshal(b, &v, ndr.Opaque); err != nil {
return err
}
p.TicketChecksum = &v
case 0x00000011:
var v PACAttributesInfo
if err := ndr.Unmarshal(b, &v, ndr.Opaque); err != nil {
return err
}
p.Attributes = &v
case 0x00000012:
var v dtyp.SID
if err := ndr.Unmarshal(b, &v, ndr.Opaque); err != nil {
return err
}
p.RequestorSID = &v
case 0x00000013:
var v PACSignatureData
if err := ndr.Unmarshal(b, &v, ndr.Opaque); err != nil {
return err
}
p.ExtendedKDCChecksum = &v
case 0x00000014:
var v dtyp.GUID
if err := ndr.Unmarshal(b, &v, ndr.Opaque); err != nil {
return err
}
p.RequestorGUID = &v
}
}
return nil
}
UPD: it needs more testing as offset calculation must consider 8 byte alignment for each entry and so on, so it will take more time and need to get more test vectors.
from go-msrpc.
@dodgyturtle could you please clarify, what is actually expected for PAC data to contain, and how can it be used?
from go-msrpc.
I need Samba to unpack the PAC. To do this I need to pass 4 types of PacBuffers: 1,6,7,10. I have written the code, but so far it doesn't work properly. Samba gives the error "PAC out of alignment". I think it is here somewhere: https://github.com/samba-team/samba/blob/68f0835c8e1c5029cd831c267b75c02185b206c7/third_party/heimdal/lib/krb5/pac.c#L316
I'm still trying to figure it out.
from go-msrpc.
@dodgyturtle, with this commit (c00efae), could you please verify, if it will work for you:
p := &PAC{
// fill-in LogonInformation (1), ServerChecksum (6), KDCChecksum (7), ClientNameAndTicketInformation (10)
}
b, err := p.Marshal()
// b will contain your PAC data.
from go-msrpc.
You set pac.Version = 5
But is in docs: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-pac/6655b92f-ab06-490b-845d-037e6987275f version 0
.
When I fixed it, all work fine.
from go-msrpc.
Thank you so much!!!
from go-msrpc.
Related Issues (10)
- [Question] About pass the hash HOT 21
- [Issues] Auth user with member of `Domain users` issues HOT 27
- any example about WMI class StdRegProv? HOT 3
- any example about MS-DRSR use? HOT 2
- [Feature request] null session test and support HOT 4
- Wrong length of CommonHeaderLength and no multiplicity check 8 HOT 2
- Documentation for gssapi.Mechanism HOT 6
- Add marshalling and unmarshalling PAC_REQUESTOR_SID and PAC_REQUESTOR_GUID HOT 2
- PAC for Windows HOT 20
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from go-msrpc.