-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2a1fdc4
commit 1b6ad72
Showing
23 changed files
with
3,162 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Go-WinACL | ||
|
||
## Usage | ||
|
||
```go | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
winacl "github.com/kgoins/go-winacl/pkg" | ||
) | ||
|
||
func main() { | ||
rawNTSD, _ := os.ReadFile("testdata.bin") | ||
ntsd, _ := winacl.NewNtSecurityDescriptor(rawNTSD) | ||
fmt.Println(ntsd.ToSDDL()) | ||
} | ||
``` | ||
|
||
## Credit | ||
This repo was forked from https://github.com/rvazarkar/go-winacl, who did the hard work of figuring out the models and parsers. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module github.com/kgoins/go-winacl | ||
|
||
go 1.16 | ||
|
||
require ( | ||
github.com/audibleblink/bamflags v1.0.0 | ||
github.com/stretchr/testify v1.7.0 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
github.com/audibleblink/bamflags v0.2.0 h1:xLsR8OO2mmbhpQglTvSKNJMnmQMI9L884eJ15zbu4mI= | ||
github.com/audibleblink/bamflags v0.2.0/go.mod h1:zpuLMpykftgB88SHYGBa1urg0uHn01R2pjeBed+JhB8= | ||
github.com/audibleblink/bamflags v1.0.0 h1:Ul07TOyv5Ht7/u3GsIQDUy++eiKB8q+Nvah6AgEWB8k= | ||
github.com/audibleblink/bamflags v1.0.0/go.mod h1:zpuLMpykftgB88SHYGBa1urg0uHn01R2pjeBed+JhB8= | ||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= | ||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= | ||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,285 @@ | ||
package winacl | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/audibleblink/bamflags" | ||
) | ||
|
||
// AceType is the type of ACE as defined by Microsoft here: | ||
// https://docs.microsoft.com/en-us/windows/win32/secauthz/access-control-entries | ||
type AceType byte | ||
|
||
const ( | ||
AceTypeAccessAllowed AceType = iota | ||
AceTypeAccessDenied | ||
AceTypeSystemAudit | ||
AceTypeSystemAlarm | ||
AceTypeAccessAllowedCompound | ||
AceTypeAccessAllowedObject | ||
AceTypeAccessDeniedObject | ||
AceTypeSystemAuditObject | ||
AceTypeSystemAlarmObject | ||
AceTypeAccessAllowedCallback | ||
AceTypeAccessDeniedCallback | ||
AceTypeAccessAllowedCallbackObject | ||
AceTypeAccessDeniedCallbackObject | ||
AceTypeSystemAuditCallback | ||
AceTypeSystemAlarmCallback | ||
AceTypeSystemAuditCallbackObject | ||
AceTypeSystemAlarmCallbackObject | ||
) | ||
|
||
// ACETypeLookup maps AceTypes to a human-readable labels | ||
var ACETypeLookup = map[AceType]string{ | ||
AceTypeAccessAllowed: "ACCESS_ALLOWED", | ||
AceTypeAccessDenied: "ACCESS_DENIED", | ||
AceTypeSystemAudit: "SYSTEM_AUDIT", | ||
AceTypeSystemAlarm: "SYSTEM_ALARM", | ||
AceTypeAccessAllowedCompound: "ACCESS_ALLOWED_COMPOUND", | ||
AceTypeAccessAllowedObject: "ACCESS_ALLOWED_OBJECT", | ||
AceTypeAccessDeniedObject: "ACCESS_DENIED_OBJECT", | ||
AceTypeSystemAuditObject: "SYSTEM_AUDIT_OBJECT", | ||
AceTypeSystemAlarmObject: "SYSTEM_ALARM_OBJECT", | ||
AceTypeAccessAllowedCallback: "ACCESS_ALLOWED_CALLBACK", | ||
AceTypeAccessDeniedCallback: "ACCESS_DENIED_CALLBACK", | ||
AceTypeAccessAllowedCallbackObject: "ACCESS_ALLOWED_CALLBACK_OBJECT", | ||
AceTypeAccessDeniedCallbackObject: "ACCESS_DENIED_CALLBACK_OBJECT", | ||
AceTypeSystemAuditCallback: "SYSTEM_AUDIT_CALLBACK", | ||
AceTypeSystemAlarmCallback: "SYSTEM_ALARM_CALLBACK", | ||
AceTypeSystemAuditCallbackObject: "SYSTEM_AUDIT_CALLBACK_OBJECT", | ||
AceTypeSystemAlarmCallbackObject: "SYSTEM_ALARM_CALLBACK_OBJECT", | ||
} | ||
|
||
// AceHeadFlags is a type representing an ACEs header | ||
type ACEHeaderFlags byte | ||
|
||
const ( | ||
ACEHeaderFlagsObjectInheritAce ACEHeaderFlags = 0x01 | ||
ACEHeaderFlagsContainerInheritAce = 0x02 | ||
ACEHeaderFlagsNoPropogateInheritAce = 0x04 | ||
ACEHeaderFlagsInheritOnlyAce = 0x08 | ||
ACEHeaderFlagsInheritedAce = 0x10 | ||
ACEHeaderFlagsSuccessfulAccessAceFlag = 0x40 | ||
ACEHeaderFlagsFailedAccessAceFlag = 0x80 | ||
) | ||
|
||
var ACEHeaderFlagLookup = map[ACEHeaderFlags]string{ | ||
ACEHeaderFlagsObjectInheritAce: "OBJECT_INHERIT_ACE", | ||
ACEHeaderFlagsContainerInheritAce: "CONTAINER_INHERIT_ACE", | ||
ACEHeaderFlagsNoPropogateInheritAce: "NO_PROPOGATE_INHERIT_ACE", | ||
ACEHeaderFlagsInheritOnlyAce: "INHERIT_ONLY_ACE", | ||
ACEHeaderFlagsInheritedAce: "INHERITED_ACE", | ||
ACEHeaderFlagsSuccessfulAccessAceFlag: "SUCCESSFUL_ACCESS_ACE_FLAG", | ||
ACEHeaderFlagsFailedAccessAceFlag: "FAILED_ACCESS_ACE_FLAG", | ||
} | ||
|
||
// ACEInheritanceFlags is a type representing an ACEs inheritance flags | ||
type ACEInheritanceFlags uint32 | ||
|
||
const ( | ||
ACEInheritanceFlagsObjectTypePresent ACEInheritanceFlags = 0x01 | ||
ACEInheritanceFlagsInheritedObjectTypePresent = 0x02 | ||
) | ||
|
||
// ACEInheritanceFlagsLookup maps ACEInheritanceFlags to a human-readable labels | ||
var ACEInheritanceFlagsLookup = map[ACEInheritanceFlags]string{ | ||
ACEInheritanceFlagsObjectTypePresent: "ACE_OBJECT_TYPE_PRESENT", | ||
ACEInheritanceFlagsInheritedObjectTypePresent: "ACE_INHERITED_OBJECT_TYPE_PRESENT", | ||
} | ||
|
||
// ACEAccessMask represents an ACE's permissions | ||
type ACEAccessMask struct { | ||
value uint32 | ||
} | ||
|
||
const ( | ||
AccessMaskGenericRead = 0x80000000 | ||
AccessMaskGenericWrite = 0x40000000 | ||
AccessMaskGenericExecute = 0x20000000 | ||
AccessMaskGenericAll = 0x10000000 | ||
AccessMaskMaximumAllowed = 0x02000000 | ||
AccessMaskSystemSecurity = 0x01000000 | ||
AccessMaskSynchronize = 0x00100000 | ||
AccessMaskWriteOwner = 0x00080000 | ||
AccessMaskWriteDACL = 0x00040000 | ||
AccessMaskReadControl = 0x00020000 | ||
AccessMaskDelete = 0x00010000 | ||
|
||
// Advances ACE Masks | ||
ADSRightDSControlAccess = 0x00000100 | ||
ADSRightDSListObject = 0x00000080 | ||
ADSRightDSDeleteTree = 0x00000040 | ||
ADSRightDSWriteProp = 0x00000020 | ||
ADSRightDSReadProp = 0x00000010 | ||
ADSRightDSSelf = 0x00000008 | ||
ADSRightDSListChildrend = 0x00000004 | ||
ADSRightDSDeleteChild = 0x00000002 | ||
ADSRightDSCreateChild = 0x00000001 | ||
) | ||
|
||
// ACEAccessMaskLookup maps ACEAccessMasks to a human-readable labels | ||
var ACEAccessMaskLookup = map[uint32]string{ | ||
AccessMaskGenericRead: "GENERIC_READ", | ||
AccessMaskGenericWrite: "GENERIC_WRITE", | ||
AccessMaskGenericExecute: "GENERIC_EXECUTE", | ||
AccessMaskGenericAll: "GENERIC_ALL", | ||
AccessMaskMaximumAllowed: "MAXIMUM_ALLOWED", | ||
AccessMaskSystemSecurity: "SYSTEM_SECURITY", | ||
AccessMaskSynchronize: "SYNCHRONIZE", | ||
AccessMaskWriteOwner: "WRITE_OWNER", | ||
AccessMaskWriteDACL: "WRITE_DACL", | ||
AccessMaskReadControl: "READ_CONTROL", | ||
AccessMaskDelete: "DELETE", | ||
|
||
// Advanced ACEs | ||
ADSRightDSControlAccess: "CONTROL_ACCESS", | ||
ADSRightDSWriteProp: "WRITE_PROP", | ||
ADSRightDSReadProp: "READ_PROP", | ||
ADSRightDSSelf: "SELF", | ||
ADSRightDSDeleteChild: "DELETE_CHILD", | ||
ADSRightDSCreateChild: "CREATE_CHILD", | ||
} | ||
|
||
// Raw returns an ACEAccessMask's uint32 Access Mask | ||
func (am ACEAccessMask) Raw() uint32 { | ||
return am.value | ||
} | ||
|
||
// String returns an ACEAccessMask's human-readable Access Mask | ||
func (am ACEAccessMask) String() string { | ||
readableRights := am.StringSlice() | ||
return strings.Join(readableRights, " ") | ||
} | ||
|
||
// StringSlice, like String, returns human-readable permissions, | ||
// except as a slice of string | ||
func (am ACEAccessMask) StringSlice() []string { | ||
var readableRights []string | ||
rights, _ := bamflags.ParseInt(int64(am.value)) | ||
|
||
for _, right := range rights { | ||
if perm := ACEAccessMaskLookup[uint32(right)]; perm != "" { | ||
readableRights = append(readableRights, perm) | ||
} | ||
} | ||
return readableRights | ||
} | ||
|
||
// ACE represents an ACE within an ACL | ||
type ACE struct { | ||
//Header + AccessMask is 16 bytes | ||
Header ACEHeader | ||
AccessMask ACEAccessMask | ||
ObjectAce ObjectAce | ||
} | ||
|
||
// Strings returns an human-readable representation of an ACE | ||
func (s ACE) String() string { | ||
sb := strings.Builder{} | ||
|
||
aceType := s.GetTypeString() | ||
perms := s.AccessMask.String() | ||
var sid SID | ||
|
||
sb.WriteString(fmt.Sprintf("AceType: %s\n", aceType)) | ||
|
||
switch s.ObjectAce.(type) { | ||
case BasicAce: | ||
sb.WriteString(fmt.Sprintf("Flags: %s\n", s.Header.FlagsString())) | ||
sid = s.ObjectAce.GetPrincipal() | ||
|
||
case AdvancedAce: | ||
aa := s.ObjectAce.(AdvancedAce) | ||
sid = aa.GetPrincipal() | ||
|
||
switch aa.Flags { | ||
case ACEInheritanceFlagsObjectTypePresent: | ||
sb.WriteString(fmt.Sprintf("ObjectType: %s\n", aa.ObjectType.Resolve())) | ||
case ACEInheritanceFlagsInheritedObjectTypePresent: | ||
sb.WriteString(fmt.Sprintf("InheritedObjectType: %s\n", aa.InheritedObjectType.Resolve())) | ||
} | ||
} | ||
|
||
sb.WriteString(fmt.Sprintf("Permissions: %s\n", perms)) | ||
return fmt.Sprintf("SID: %s\n%s", sid.String(), sb.String()) | ||
} | ||
|
||
// ACEHeader represents an ACE Header | ||
type ACEHeader struct { | ||
Type AceType | ||
Flags ACEHeaderFlags | ||
Size uint16 | ||
} | ||
|
||
// FlagsString returns an human-readable representation of an ACEHeader's Flags | ||
func (ah ACEHeader) FlagsString() string { | ||
var readableFlags []string | ||
flags, _ := bamflags.ParseInt(int64(ah.Flags)) | ||
for _, flag := range flags { | ||
headerFlag := ACEHeaderFlags(flag) | ||
f := ACEHeaderFlagLookup[headerFlag] | ||
readableFlags = append(readableFlags, f) | ||
} | ||
return strings.Join(readableFlags, " ") | ||
} | ||
|
||
// ACEObjectType holds information and an ACE's Object Type. A GUID | ||
type ACEObjectType struct { | ||
PartA uint32 | ||
PartB uint16 | ||
PartC uint16 | ||
PartD [8]byte | ||
} | ||
|
||
// GetType returns the ACE type, fetched from the ACE Header | ||
func (s ACE) GetType() AceType { | ||
return s.Header.Type | ||
} | ||
|
||
// GetTypeString returns the ACE type as a human-readable string | ||
func (s ACE) GetTypeString() string { | ||
return ACETypeLookup[s.Header.Type] | ||
} | ||
|
||
// BasicAce represent a Simple ACEs | ||
type BasicAce struct { | ||
SecurityIdentifier SID | ||
} | ||
|
||
// GetPrincipal returns an ACEs Principal | ||
func (s BasicAce) GetPrincipal() SID { | ||
return s.SecurityIdentifier | ||
} | ||
|
||
//AdvancedAce represents an Object Ace | ||
type AdvancedAce struct { | ||
Flags ACEInheritanceFlags //4 bytes | ||
ObjectType GUID //16 bytes | ||
InheritedObjectType GUID | ||
SecurityIdentifier SID | ||
} | ||
|
||
// GetPrincipal returns an ACEs Principal | ||
func (s AdvancedAce) GetPrincipal() SID { | ||
return s.SecurityIdentifier | ||
} | ||
|
||
// FlagsString returns an human-readable representation of an ACEHeader's Flags | ||
func (s AdvancedAce) FlagsString() string { | ||
sb := strings.Builder{} | ||
flags, _ := bamflags.ParseInt(int64(s.Flags)) | ||
for _, flag := range flags { | ||
aaf := ACEInheritanceFlags(flag) | ||
f := ACEInheritanceFlagsLookup[aaf] | ||
fmt.Fprintf(&sb, "%s ", f) | ||
} | ||
return sb.String() | ||
} | ||
|
||
// ObjectAce is an interface that defines what constitutes an ACE within | ||
// go-winacl | ||
type ObjectAce interface { | ||
GetPrincipal() SID | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package winacl_test | ||
|
||
import ( | ||
"bytes" | ||
"encoding/binary" | ||
"testing" | ||
|
||
winacl "github.com/kgoins/go-winacl/pkg" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestNewACEHeader(t *testing.T) { | ||
|
||
r := require.New(t) | ||
|
||
t.Run("Returns an error when given a malformed byte stream", func(t *testing.T) { | ||
sd := newTestSD() | ||
ace := sd.DACL.Aces[0] | ||
buf := bytes.Buffer{} | ||
err := binary.Write(&buf, binary.LittleEndian, &ace.Header) | ||
r.NoError(err) | ||
|
||
buf.Next(1) | ||
|
||
_, err = winacl.NewACEHeader(&buf) | ||
r.Error(err) | ||
}) | ||
|
||
} |
Oops, something went wrong.