Skip to content

Commit

Permalink
generalize binary decoding
Browse files Browse the repository at this point in the history
  • Loading branch information
5amu committed Mar 5, 2024
1 parent 459b699 commit 676143b
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 55 deletions.
4 changes: 2 additions & 2 deletions internal/goad/optldap/crud.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ func (o *Options) read(target string) {
case ObjectSid:
data = append(data, DecodeSID(UnpackToString(m[a])))
case ManagedPassword:
d := UnpackToString(m[ManagedPassword])
blob := mstypes.NewMSDSManagedPasswordBlob([]byte(d))
var blob mstypes.MSDSManagedPasswordBlob
_ = mstypes.UnmarshalBinary(&blob, []byte(UnpackToString(m[ManagedPassword])))
data = append(data, mstypes.HashDataNTLM(blob.CurrentPassword))
default:
data = append(data, UnpackToString(m[a]))
Expand Down
92 changes: 92 additions & 0 deletions pkg/mstypes/common.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package mstypes

import (
"encoding/binary"
"fmt"
"reflect"
)

func next(b []byte, pattern []byte) int {
for i := len(pattern); i < len(b); i++ {
var ok bool = false
for j := 0; j < len(pattern); j++ {
if b[i-len(pattern)+j] == pattern[j] {
if j == 0 {
ok = true
}
ok = ok && true
} else {
ok = false
}
}
if ok {
return i - len(pattern)
}
}
return 0
}

func UnmarshalBinary(s any, d []byte) error {
t := reflect.TypeOf(s)
v := reflect.ValueOf(s)

defer func() {
if r := recover(); r != nil {
fmt.Println("==> panic recovered: ", r)
}
}()

if t.Kind() == reflect.Ptr {
t = t.Elem()
v = v.Elem()
}

var offset int = 0
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
ft := t.Field(i)

switch ft.Type.Kind() {
case reflect.Uint16:
f.Set(reflect.ValueOf(binary.LittleEndian.Uint16(d[offset : offset+2])))
offset += 2
case reflect.Uint32:
f.Set(reflect.ValueOf(binary.LittleEndian.Uint32(d[offset : offset+4])))
offset += 4
case reflect.Uint64:
f.Set(reflect.ValueOf(binary.LittleEndian.Uint64(d[offset : offset+8])))
offset += 8
case reflect.Slice:
delim, ok := ft.Tag.Lookup("delimiter")
if ok {
switch delim {
case "16bitnull":
end := next(d[offset:], []byte{0, 0})
f.Set(reflect.ValueOf(d[offset : offset+end]))
offset = offset + end
default:
}
}
padding, ok := ft.Tag.Lookup("padding")
if ok {
switch padding {
case "null":
var stop bool = false
var end int
for !stop {
tmp := next(d[offset+end:], []byte{0})
if tmp != 0 && tmp == end+1 {
end = tmp
} else {
stop = true
}
}
f.Set(reflect.ValueOf(d[offset : offset+end]))
offset = offset + end
default:
}
}
}
}
return nil
}
57 changes: 4 additions & 53 deletions pkg/mstypes/msds.go
Original file line number Diff line number Diff line change
@@ -1,65 +1,16 @@
package mstypes

import (
"encoding/binary"
)

type MSDSManagedPasswordBlob struct {
Version uint16
Reserved uint16
Lenght uint32
CurrentPasswordOffset uint16
PreviousPasswordOffset uint16
QueryPasswordIntervalOffset uint16
UnchangedPasswordIntervalOffset uint16
CurrentPassword []byte
PreviousPassword []byte
CurrentPassword []byte `delimiter:"16bitnull"`
PreviousPassword []byte `delimiter:"16bitnull"`
AlignmentPadding []byte `padding:"null"`
QueryPasswordInterval uint64
UnchangedPasswordInterval uint64
}

func nextNul(b []byte) uint16 {
var stop bool = false
for i, n := range b {
if n == 0 {
if stop {
return uint16(i - 1)
} else {
stop = true
}
} else {
stop = false
}
}
return 0
}

func NewMSDSManagedPasswordBlob(data []byte) *MSDSManagedPasswordBlob {
var blob MSDSManagedPasswordBlob

blob.Version = binary.LittleEndian.Uint16(data[0:2])
blob.Lenght = binary.LittleEndian.Uint32(data[4:8])
blob.CurrentPasswordOffset = binary.LittleEndian.Uint16(data[8:10])
blob.PreviousPasswordOffset = binary.LittleEndian.Uint16(data[10:12])
blob.QueryPasswordIntervalOffset = binary.LittleEndian.Uint16(data[12:14])
blob.UnchangedPasswordIntervalOffset = binary.LittleEndian.Uint16(data[14:16])

endOfCurrentPassword := 16 + nextNul(data[16:])
blob.CurrentPassword = data[16:endOfCurrentPassword]
endOfPreviousPassword := endOfCurrentPassword + nextNul(data[endOfCurrentPassword:])
blob.PreviousPassword = data[endOfCurrentPassword:endOfPreviousPassword]

endOfPadding := endOfPreviousPassword
stop := false
for !stop {
tmp := endOfPadding
endOfPadding = nextNul(data[endOfPadding:])
if endOfPadding == 0 {
endOfPadding = tmp
stop = true
}
}

blob.QueryPasswordInterval = binary.LittleEndian.Uint64(data[endOfPadding : endOfPadding+8])
blob.UnchangedPasswordInterval = binary.LittleEndian.Uint64(data[endOfPadding+8 : endOfPadding+16])
return &blob
}

0 comments on commit 676143b

Please sign in to comment.