GithubHelp home page GithubHelp logo

Comments (14)

dodgyturtle avatar dodgyturtle commented on September 28, 2024 1

You're unbelievable! Thank you for your work!

from go-msrpc.

oiweiwei avatar oiweiwei commented on September 28, 2024 1

@dodgyturtle fixed with 2cbdf82

from go-msrpc.

oiweiwei avatar oiweiwei commented on September 28, 2024

hello, @dodgyturtle. please let me know if these changes (6ebf284) worked for you.

from go-msrpc.

dodgyturtle avatar dodgyturtle commented on September 28, 2024

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.

oiweiwei avatar oiweiwei commented on September 28, 2024

@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.

oiweiwei avatar oiweiwei commented on September 28, 2024

@dodgyturtle could you please kindly point me to the proper dataset and root structure you're using in krb5 repo?

from go-msrpc.

dodgyturtle avatar dodgyturtle commented on September 28, 2024

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},
	}

image

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.

oiweiwei avatar oiweiwei commented on September 28, 2024

@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.

oiweiwei avatar oiweiwei commented on September 28, 2024

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.

oiweiwei avatar oiweiwei commented on September 28, 2024

@dodgyturtle could you please clarify, what is actually expected for PAC data to contain, and how can it be used?

from go-msrpc.

dodgyturtle avatar dodgyturtle commented on September 28, 2024

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.

oiweiwei avatar oiweiwei commented on September 28, 2024

@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.

dodgyturtle avatar dodgyturtle commented on September 28, 2024

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.

dodgyturtle avatar dodgyturtle commented on September 28, 2024

Thank you so much!!!

from go-msrpc.

Related Issues (10)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.