From bc73c8d13a61045347a07d50e2389a3ac4cdf832 Mon Sep 17 00:00:00 2001 From: Chris Dent Date: Fri, 3 Apr 2020 11:50:02 +0100 Subject: [PATCH 1/7] Adds ntSecurityDescriptor parser framework --- .../00 - Enums/{Enums.ps1 => 00 - Enums.ps1} | 0 .../NTSecurityDescriptor/00 - AccessRight.ps1 | 19 ++++++ .../NTSecurityDescriptor/00 - AceFlags.ps1 | 10 +++ .../NTSecurityDescriptor/00 - AceType.ps1 | 20 ++++++ .../00 - ObjectAceFlags.ps1 | 6 ++ .../00 - SecurityDescriptorControl.ps1 | 19 ++++++ .../01 - Base Classes/01 - Base Classes.ps1 | 1 - .../Classes/01 - Base Classes/01 - SID.ps1 | 37 +++++++---- ActiveDirectoryCore/Classes/02 - Classes.ps1 | 1 - .../02 - Intermediate Classes/02 - Ace.ps1 | 37 +++++++++++ .../02 - Intermediate Classes/02 - Acl.ps1 | 61 +++++++++++++++++++ .../02 - ObjectAce.ps1 | 4 ++ .../02 - SecurityDescriptor.ps1 | 58 ++++++++++++++++++ Tests/Classes/01 - Base Classes/SID.Tests.ps1 | 15 ++++- 14 files changed, 271 insertions(+), 17 deletions(-) rename ActiveDirectoryCore/Classes/00 - Enums/{Enums.ps1 => 00 - Enums.ps1} (100%) create mode 100644 ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AccessRight.ps1 create mode 100644 ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceFlags.ps1 create mode 100644 ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceType.ps1 create mode 100644 ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - ObjectAceFlags.ps1 create mode 100644 ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - SecurityDescriptorControl.ps1 delete mode 100644 ActiveDirectoryCore/Classes/01 - Base Classes/01 - Base Classes.ps1 delete mode 100644 ActiveDirectoryCore/Classes/02 - Classes.ps1 create mode 100644 ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Ace.ps1 create mode 100644 ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Acl.ps1 create mode 100644 ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - ObjectAce.ps1 create mode 100644 ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - SecurityDescriptor.ps1 diff --git a/ActiveDirectoryCore/Classes/00 - Enums/Enums.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/00 - Enums.ps1 similarity index 100% rename from ActiveDirectoryCore/Classes/00 - Enums/Enums.ps1 rename to ActiveDirectoryCore/Classes/00 - Enums/00 - Enums.ps1 diff --git a/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AccessRight.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AccessRight.ps1 new file mode 100644 index 0000000..8522ed9 --- /dev/null +++ b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AccessRight.ps1 @@ -0,0 +1,19 @@ +[Flags()] +enum AccessRight : uint { + GenericRead = 0x80000000u + GenericWrite = 0x40000000 + GenericExecute = 0x20000000 + GenericAll = 0x10000000 + AccessSystemSecurity = 0x01000000 + Synchronize = 0x00100000 + WriteOwner = 0x00080000 + WriteDacl = 0x00040000 + ReadControl = 0x00020000 + Delete = 0x00010000 + ControlAccess = 0x00000100 + CreateChild = 0x00000001 + DeleteChild = 0x00000002 + ReadProperty = 0x00000010 + WriteProperty = 0x00000020 + ValidatedWrite = 0x00000008 +} diff --git a/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceFlags.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceFlags.ps1 new file mode 100644 index 0000000..5c89041 --- /dev/null +++ b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceFlags.ps1 @@ -0,0 +1,10 @@ +[Flags()] +enum AceFlags : byte { + ObjectInherit = 0x01 + ContainerInherit = 0x02 + NoPropagateInherit = 0x04 + InheritOnly = 0x08 + Inherited = 0x10 + SuccessfulAccess = 0x40 + FailedAccess = 0x80 +} diff --git a/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceType.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceType.ps1 new file mode 100644 index 0000000..02f78f2 --- /dev/null +++ b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceType.ps1 @@ -0,0 +1,20 @@ +enum AceType : byte { + Allow + Deny + Audit + Alarm + AllowCompound + AllowObject + DenyObject + AuditObject + AlarmObject + AllowCallback + AllowCallbackObject + AuditCallback + AlarmCallback + AuditCallbackObject + AlarmCallbackObject + MandatoryLabel + ResourceAttribute + ScopedPolicyID +} diff --git a/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - ObjectAceFlags.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - ObjectAceFlags.ps1 new file mode 100644 index 0000000..31a66a5 --- /dev/null +++ b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - ObjectAceFlags.ps1 @@ -0,0 +1,6 @@ +[Flags()] +enum ObjectAceFlags : uint { + None + ObjectTypePresent + InheritedObjectTypePresent +} diff --git a/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - SecurityDescriptorControl.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - SecurityDescriptorControl.ps1 new file mode 100644 index 0000000..f3d4b4f --- /dev/null +++ b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - SecurityDescriptorControl.ps1 @@ -0,0 +1,19 @@ +[Flags()] +enum SecurityDescriptorControl : ushort { + SelfRelative = 0x0000 + RMControlValid = 0x0001 + SaclProtected = 0x0002 + DaclProtected = 0x0004 + SaclAutoInherited = 0x0008 + DaclAutoInherited = 0x0010 + SaclComputedInheritanceRequired = 0x0020 + DaclComputedInheritanceRequired = 0x0040 + ServerSecurity = 0x0080 + DaclTrusted = 0x0100 + SaclDefaulted = 0x0200 + SaclPresent = 0x0400 + DaclDefaulted = 0x0800 + DaclPresent = 0x1000 + GroupDefaulted = 0x2000 + OwnerDefaulted = 0x4000 +} diff --git a/ActiveDirectoryCore/Classes/01 - Base Classes/01 - Base Classes.ps1 b/ActiveDirectoryCore/Classes/01 - Base Classes/01 - Base Classes.ps1 deleted file mode 100644 index 43cf724..0000000 --- a/ActiveDirectoryCore/Classes/01 - Base Classes/01 - Base Classes.ps1 +++ /dev/null @@ -1 +0,0 @@ -# Base classes, interfaces, abstracts, etc (no dependencies from within the module outside of Enums) diff --git a/ActiveDirectoryCore/Classes/01 - Base Classes/01 - SID.ps1 b/ActiveDirectoryCore/Classes/01 - Base Classes/01 - SID.ps1 index f0f9ad2..99165a5 100644 --- a/ActiveDirectoryCore/Classes/01 - Base Classes/01 - SID.ps1 +++ b/ActiveDirectoryCore/Classes/01 - Base Classes/01 - SID.ps1 @@ -3,21 +3,18 @@ class SID : IEquatable[Object] { [string] $AccountDomainSid [string] $Value - [byte] $revisionLevel - [IdentifierAuthority] $identifierAuthority - [uint[]] $subAuthorities + hidden [byte] $revisionLevel + hidden [IdentifierAuthority] $identifierAuthority + hidden [uint[]] $subAuthorities + # Create an instance of SID from a string SID([string] $sidString) { - $null, $this.RevisionLevel, $this.identifierAuthority, $this.subAuthorities = $sidString -split '-' - $this.BinaryLength = 8 + ($this.subAuthorities.Count * 4) - $this.Value = $this.ToString() + $this.ConvertFromString($sidString) + } - if ($this.subAuthorities.Count -eq 4) { - $this.AccountDomainSid = $sidString - } - elseif ($this.subAuthorities.Count -gt 4) { - $this.AccountDomainSid = $sidString -replace '-\d+$' - } + # Create an instance of SID from the SecurityIdentifier class + SID([System.Security.Principal.SecurityIdentifier]$securityIdentifier) { + $this.ConvertFromString($securityIdentifier.ToString()) } SID([byte[]] $sidBytes) { @@ -63,7 +60,21 @@ class SID : IEquatable[Object] { } } - [byte[]] GetBinaryForm() { + hidden ConvertFromString([string] $sidString) { + $null, $this.RevisionLevel, $this.identifierAuthority, $this.subAuthorities = $sidString -split '-' + $this.BinaryLength = 8 + ($this.subAuthorities.Count * 4) + $this.Value = $this.ToString() + + if ($this.subAuthorities.Count -eq 4) { + $this.AccountDomainSid = $sidString + } + elseif ($this.subAuthorities.Count -gt 4) { + $this.AccountDomainSid = $sidString -replace '-\d+$' + } + } + + # Return the security identifier as a byte array. + [byte[]] GetBytes() { $sidBytes = [byte[]]::new($this.BinaryLength) $sidBytes[0] = $this.revisionLevel $sidBytes[1] = $this.subAuthorities.Count diff --git a/ActiveDirectoryCore/Classes/02 - Classes.ps1 b/ActiveDirectoryCore/Classes/02 - Classes.ps1 deleted file mode 100644 index 4593bc5..0000000 --- a/ActiveDirectoryCore/Classes/02 - Classes.ps1 +++ /dev/null @@ -1 +0,0 @@ -# All other classes diff --git a/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Ace.ps1 b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Ace.ps1 new file mode 100644 index 0000000..8c3201d --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Ace.ps1 @@ -0,0 +1,37 @@ +class Ace { + [AceType] $Type + [AceFlags] $Flags + [AccessRight] $AccessRights + [Sid[]] $IdentityReference + + hidden [ushort] $Size + + Ace() { } + + Ace([System.IO.BinaryReader] $binaryReader) { + $this.Type = $binaryReader.ReadByte() + $this.Flags = $binaryReader.ReadByte() + $this.Size = $binaryReader.ReadUInt16() + $this.AccessRights = $binaryReader.ReadUInt32() + + $bytesRemaining = $this.Size + $this.IdentityReference = while ($bytesRemaining -gt $this.Size) { + $sid = [Sid]::new($binaryReader) + $bytesRemaining -= $sid.BinaryLength + $sid + } + } + + [byte[]] GetBytes() { + $bytes = [System.Collections.Generic.List[byte]]::new() + $bytes.Add($this.Type) + $bytes.Add($this.Flags) + $bytes.AddRange([BitConverter]::GetBytes($this.AccessRights)) + + foreach ($sid in $this.Sid) { + $bytes.AddRange($sid.GetBytes()) + } + + return $bytes.ToArray() + } +} diff --git a/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Acl.ps1 b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Acl.ps1 new file mode 100644 index 0000000..47390a2 --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Acl.ps1 @@ -0,0 +1,61 @@ +class AclEnumerator : System.Collections.IEnumerator { + hidden [int] $position = -1 + hidden [object] $Current + hidden [object] ${IEnumerator.Current} + hidden [Ace[]] $_ace + + AclEnumerator([Ace[]] $ace) { + $this._ace = $ace + } + + [bool] MoveNext() { + $this.position++ + $this.Current = $this.'IEnumerator.Current' = $this._ace[$this.position] + return $this.position -lt $this._ace.Length + } + + [void] Reset() { + $this.Current = $this.{IEnumerator.Current} = $null + $this.Position = -1 + } +} + +class Acl : System.Collections.IEnumerable { + hidden [byte] $revision + hidden [byte] $sbz1 + hidden [ushort] $aclSize + hidden [ushort] $aceCount + hidden [ushort] $sbz2 + hidden [Ace[]] $_ace + + Acl([System.IO.BinaryReader] $binaryReader) { + $this.revision = $binaryReader.ReadByte() + $this.sbz1 = $binaryReader.ReadByte() + $this.aclSize = $binaryReader.ReadUInt16() + $this.aceCount = $binaryReader.ReadUInt16() + $this.sbz2 = $binaryReader.ReadUInt16() + + $this._ace = for ($i = 0; $i -lt $this.aceCount; $i++) { + [Ace]::new($binaryReader) + } + } + + [System.Collections.IEnumerator] GetEnumerator() { + return [AclEnumerator]::new($this._ace) + } + + [Byte[]] GetBytes([Ace[]] $ace) { + $bytes = [System.Collections.Generic.List[byte]]::new() + $bytes.Add($this.revision) + $bytes.Add($this.sbz1) + $bytes.AddRange([BitConverter]::GetBytes($this.aclSize)) + $bytes.AddRange([BitConverter]::GetBytes($this.aceCount)) + $bytes.AddRange([BitConverter]::GetBytes($this.sbz2)) + + foreach ($ace in $this._ace) { + $bytes.AddRange($ace.GetBytes()) + } + + return $bytes.ToArray() + } +} diff --git a/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - ObjectAce.ps1 b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - ObjectAce.ps1 new file mode 100644 index 0000000..f1a3b02 --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - ObjectAce.ps1 @@ -0,0 +1,4 @@ +class ObjectAce : Ace { + [Guid] $ObjectType + [Guid] $InheritedObjectType +} diff --git a/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - SecurityDescriptor.ps1 b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - SecurityDescriptor.ps1 new file mode 100644 index 0000000..9587158 --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - SecurityDescriptor.ps1 @@ -0,0 +1,58 @@ +class SecurityDescriptor { + [ushort] $Control + [SID] $OwnerSid + [SID] $GroupSid + [Acl] $Audit + [Acl] $Access + + hidden [byte] $revision + hidden [byte] $sbz1 + hidden [uint] $offsetOwner + hidden [uint] $offsetGroup + hidden [uint] $offsetSacl + hidden [uint] $offsetDacl + + SecurityDescriptor([byte[]] $securityDescriptorBytes) { + $binaryReader = [System.IO.BinaryReader][System.IO.MemoryStream]$securityDescriptorBytes + + $this.revision = $binaryReader.ReadByte() + $this.sbz1 = $binaryReader.ReadByte() + $this.Control = $binaryReader.ReadUInt16() + $this.offsetOwner = $binaryReader.ReadUInt16() + $this.offsetGroup = $binaryReader.ReadUInt16() + $this.offsetSacl = $binaryReader.ReadUInt16() + $this.offsetDacl = $binaryReader.ReadUInt16() + + $this.Owner = [Sid]::new($binaryReader) + $this.Group = [Sid]::new($binaryReader) + $this.Audit = [Acl]::new($binaryReader) + $this.Dacl = [Acl]::new($binaryReader) + } + + [byte[]] GetBytes() { + $bytes = [System.Collections.Generic.List[byte]]::new() + $bytes.Add($this.revision) + $bytes.Add($this.sbz1) + $bytes.AddRange([BitConverter]::GetBytes($this.Control)) + $bytes.AddRange([BitConverter]::GetBytes($this.offsetOwner)) + $bytes.AddRange([BitConverter]::GetBytes($this.offsetGroup)) + $bytes.AddRange([BitConverter]::GetBytes($this.offsetSacl)) + $bytes.AddRange([BitConverter]::GetBytes($this.offsetDacl)) + $bytes.AddRange($this.Owner.GetBytes()) + $bytes.AddRange($this.Group.GetBytes()) + $bytes.AddRange($this.Audit.GetBytes()) + $bytes.AddRange($this.Access.GetBytes()) + + return $bytes.ToArray() + } + + hidden static [System.DirectoryServices.ActiveDirectorySecurity] op_Implicit([SecurityDescriptor] $securityDescriptor) { + try { + $securityDescriptor = [System.DirectoryServices.ActiveDirectorySecurity]::new() + # Fill this in. + return $securityDescriptor + } catch { + throw + } + } +} diff --git a/Tests/Classes/01 - Base Classes/SID.Tests.ps1 b/Tests/Classes/01 - Base Classes/SID.Tests.ps1 index 46e8dd4..88c1481 100644 --- a/Tests/Classes/01 - Base Classes/SID.Tests.ps1 +++ b/Tests/Classes/01 - Base Classes/SID.Tests.ps1 @@ -1,5 +1,5 @@ #region:TestFileHeader -$projectRoot = $PSScriptRoot.Substring(0, $PSScriptRoot.IndexOf('\Tests')) +$projectRoot = $PSScriptRoot.Substring(0, $PSScriptRoot.IndexOf(([IO.Path]::DirectorySeparatorChar + "Tests"))) $moduleName = Split-Path $projectRoot -Leaf $module = Join-Path -Path $projectRoot -ChildPath "BuildOutput\$moduleName\*\$moduleName.psd1" | Resolve-Path @@ -25,7 +25,7 @@ InModuleScope ActiveDirectoryCore { It 'can convert the SID string to binary' -TestCases $testCases { param ( [string]$SID, [string]$SIDBytes ) - [SID]::new($SID).GetBinaryForm() | Should -Be ([Convert]::FromBase64String($SIDBytes)) + [SID]::new($SID).GetBytes() | Should -Be ([Convert]::FromBase64String($SIDBytes)) } It 'can convert the SID bytes to the SID string ' -TestCase $testCases { @@ -45,6 +45,17 @@ InModuleScope ActiveDirectoryCore { } } + It 'can cast a SecurityIdentifier to SID on the Windows platform' -TestCases $testCases { + param ( [string]$SID ) + + if ($PSVersionTable.Platform -ne 'Win32NT') { + Set-ItResult -Inconclusive -Because 'This test is only supported on the Windows platform' + } + else { + { [SID][System.Security.Principal.SecurityIdentifier]$SID } | Should -Not -Throw + } + } + It 'can compare to an instance of SecurityIdentifier on the Windows platform' -TestCases $testCases { param ( [string]$SID ) From f73c88a0f4a9923bed905459a7a87faa0b9afd75 Mon Sep 17 00:00:00 2001 From: Chris Dent Date: Fri, 3 Apr 2020 11:50:02 +0100 Subject: [PATCH 2/7] Adds ntSecurityDescriptor parser framework --- .../Classes/00 - Enums/00 - Enums.ps1 | 9 +++ .../NTSecurityDescriptor/00 - AccessRight.ps1 | 19 ++++++ .../NTSecurityDescriptor/00 - AceFlags.ps1 | 10 +++ .../NTSecurityDescriptor/00 - AceType.ps1 | 20 ++++++ .../00 - ObjectAceFlags.ps1 | 6 ++ .../00 - SecurityDescriptorControl.ps1 | 19 ++++++ .../Classes/01 - Base Classes/00 - SID.ps1 | 2 +- .../02 - Intermediate Classes/02 - Ace.ps1 | 37 +++++++++++ .../02 - Intermediate Classes/02 - Acl.ps1 | 61 +++++++++++++++++++ .../02 - ObjectAce.ps1 | 4 ++ .../02 - SecurityDescriptor.ps1 | 58 ++++++++++++++++++ Tests/Classes/01 - Base Classes/SID.Tests.ps1 | 2 +- 12 files changed, 245 insertions(+), 2 deletions(-) create mode 100644 ActiveDirectoryCore/Classes/00 - Enums/00 - Enums.ps1 create mode 100644 ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AccessRight.ps1 create mode 100644 ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceFlags.ps1 create mode 100644 ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceType.ps1 create mode 100644 ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - ObjectAceFlags.ps1 create mode 100644 ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - SecurityDescriptorControl.ps1 create mode 100644 ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Ace.ps1 create mode 100644 ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Acl.ps1 create mode 100644 ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - ObjectAce.ps1 create mode 100644 ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - SecurityDescriptor.ps1 diff --git a/ActiveDirectoryCore/Classes/00 - Enums/00 - Enums.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/00 - Enums.ps1 new file mode 100644 index 0000000..0b3bc7c --- /dev/null +++ b/ActiveDirectoryCore/Classes/00 - Enums/00 - Enums.ps1 @@ -0,0 +1,9 @@ +# Enums - These are added to the PSM1 first during build +enum ActiveDirectoryCoreLogLevel { + Information + Warning + Error + Debug + Verbose + Quiet +} diff --git a/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AccessRight.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AccessRight.ps1 new file mode 100644 index 0000000..8522ed9 --- /dev/null +++ b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AccessRight.ps1 @@ -0,0 +1,19 @@ +[Flags()] +enum AccessRight : uint { + GenericRead = 0x80000000u + GenericWrite = 0x40000000 + GenericExecute = 0x20000000 + GenericAll = 0x10000000 + AccessSystemSecurity = 0x01000000 + Synchronize = 0x00100000 + WriteOwner = 0x00080000 + WriteDacl = 0x00040000 + ReadControl = 0x00020000 + Delete = 0x00010000 + ControlAccess = 0x00000100 + CreateChild = 0x00000001 + DeleteChild = 0x00000002 + ReadProperty = 0x00000010 + WriteProperty = 0x00000020 + ValidatedWrite = 0x00000008 +} diff --git a/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceFlags.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceFlags.ps1 new file mode 100644 index 0000000..5c89041 --- /dev/null +++ b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceFlags.ps1 @@ -0,0 +1,10 @@ +[Flags()] +enum AceFlags : byte { + ObjectInherit = 0x01 + ContainerInherit = 0x02 + NoPropagateInherit = 0x04 + InheritOnly = 0x08 + Inherited = 0x10 + SuccessfulAccess = 0x40 + FailedAccess = 0x80 +} diff --git a/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceType.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceType.ps1 new file mode 100644 index 0000000..02f78f2 --- /dev/null +++ b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceType.ps1 @@ -0,0 +1,20 @@ +enum AceType : byte { + Allow + Deny + Audit + Alarm + AllowCompound + AllowObject + DenyObject + AuditObject + AlarmObject + AllowCallback + AllowCallbackObject + AuditCallback + AlarmCallback + AuditCallbackObject + AlarmCallbackObject + MandatoryLabel + ResourceAttribute + ScopedPolicyID +} diff --git a/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - ObjectAceFlags.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - ObjectAceFlags.ps1 new file mode 100644 index 0000000..31a66a5 --- /dev/null +++ b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - ObjectAceFlags.ps1 @@ -0,0 +1,6 @@ +[Flags()] +enum ObjectAceFlags : uint { + None + ObjectTypePresent + InheritedObjectTypePresent +} diff --git a/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - SecurityDescriptorControl.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - SecurityDescriptorControl.ps1 new file mode 100644 index 0000000..f3d4b4f --- /dev/null +++ b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - SecurityDescriptorControl.ps1 @@ -0,0 +1,19 @@ +[Flags()] +enum SecurityDescriptorControl : ushort { + SelfRelative = 0x0000 + RMControlValid = 0x0001 + SaclProtected = 0x0002 + DaclProtected = 0x0004 + SaclAutoInherited = 0x0008 + DaclAutoInherited = 0x0010 + SaclComputedInheritanceRequired = 0x0020 + DaclComputedInheritanceRequired = 0x0040 + ServerSecurity = 0x0080 + DaclTrusted = 0x0100 + SaclDefaulted = 0x0200 + SaclPresent = 0x0400 + DaclDefaulted = 0x0800 + DaclPresent = 0x1000 + GroupDefaulted = 0x2000 + OwnerDefaulted = 0x4000 +} diff --git a/ActiveDirectoryCore/Classes/01 - Base Classes/00 - SID.ps1 b/ActiveDirectoryCore/Classes/01 - Base Classes/00 - SID.ps1 index b293983..99165a5 100644 --- a/ActiveDirectoryCore/Classes/01 - Base Classes/00 - SID.ps1 +++ b/ActiveDirectoryCore/Classes/01 - Base Classes/00 - SID.ps1 @@ -74,7 +74,7 @@ class SID : IEquatable[Object] { } # Return the security identifier as a byte array. - [byte[]] ToBinary() { + [byte[]] GetBytes() { $sidBytes = [byte[]]::new($this.BinaryLength) $sidBytes[0] = $this.revisionLevel $sidBytes[1] = $this.subAuthorities.Count diff --git a/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Ace.ps1 b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Ace.ps1 new file mode 100644 index 0000000..8c3201d --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Ace.ps1 @@ -0,0 +1,37 @@ +class Ace { + [AceType] $Type + [AceFlags] $Flags + [AccessRight] $AccessRights + [Sid[]] $IdentityReference + + hidden [ushort] $Size + + Ace() { } + + Ace([System.IO.BinaryReader] $binaryReader) { + $this.Type = $binaryReader.ReadByte() + $this.Flags = $binaryReader.ReadByte() + $this.Size = $binaryReader.ReadUInt16() + $this.AccessRights = $binaryReader.ReadUInt32() + + $bytesRemaining = $this.Size + $this.IdentityReference = while ($bytesRemaining -gt $this.Size) { + $sid = [Sid]::new($binaryReader) + $bytesRemaining -= $sid.BinaryLength + $sid + } + } + + [byte[]] GetBytes() { + $bytes = [System.Collections.Generic.List[byte]]::new() + $bytes.Add($this.Type) + $bytes.Add($this.Flags) + $bytes.AddRange([BitConverter]::GetBytes($this.AccessRights)) + + foreach ($sid in $this.Sid) { + $bytes.AddRange($sid.GetBytes()) + } + + return $bytes.ToArray() + } +} diff --git a/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Acl.ps1 b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Acl.ps1 new file mode 100644 index 0000000..47390a2 --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Acl.ps1 @@ -0,0 +1,61 @@ +class AclEnumerator : System.Collections.IEnumerator { + hidden [int] $position = -1 + hidden [object] $Current + hidden [object] ${IEnumerator.Current} + hidden [Ace[]] $_ace + + AclEnumerator([Ace[]] $ace) { + $this._ace = $ace + } + + [bool] MoveNext() { + $this.position++ + $this.Current = $this.'IEnumerator.Current' = $this._ace[$this.position] + return $this.position -lt $this._ace.Length + } + + [void] Reset() { + $this.Current = $this.{IEnumerator.Current} = $null + $this.Position = -1 + } +} + +class Acl : System.Collections.IEnumerable { + hidden [byte] $revision + hidden [byte] $sbz1 + hidden [ushort] $aclSize + hidden [ushort] $aceCount + hidden [ushort] $sbz2 + hidden [Ace[]] $_ace + + Acl([System.IO.BinaryReader] $binaryReader) { + $this.revision = $binaryReader.ReadByte() + $this.sbz1 = $binaryReader.ReadByte() + $this.aclSize = $binaryReader.ReadUInt16() + $this.aceCount = $binaryReader.ReadUInt16() + $this.sbz2 = $binaryReader.ReadUInt16() + + $this._ace = for ($i = 0; $i -lt $this.aceCount; $i++) { + [Ace]::new($binaryReader) + } + } + + [System.Collections.IEnumerator] GetEnumerator() { + return [AclEnumerator]::new($this._ace) + } + + [Byte[]] GetBytes([Ace[]] $ace) { + $bytes = [System.Collections.Generic.List[byte]]::new() + $bytes.Add($this.revision) + $bytes.Add($this.sbz1) + $bytes.AddRange([BitConverter]::GetBytes($this.aclSize)) + $bytes.AddRange([BitConverter]::GetBytes($this.aceCount)) + $bytes.AddRange([BitConverter]::GetBytes($this.sbz2)) + + foreach ($ace in $this._ace) { + $bytes.AddRange($ace.GetBytes()) + } + + return $bytes.ToArray() + } +} diff --git a/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - ObjectAce.ps1 b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - ObjectAce.ps1 new file mode 100644 index 0000000..f1a3b02 --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - ObjectAce.ps1 @@ -0,0 +1,4 @@ +class ObjectAce : Ace { + [Guid] $ObjectType + [Guid] $InheritedObjectType +} diff --git a/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - SecurityDescriptor.ps1 b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - SecurityDescriptor.ps1 new file mode 100644 index 0000000..9587158 --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - SecurityDescriptor.ps1 @@ -0,0 +1,58 @@ +class SecurityDescriptor { + [ushort] $Control + [SID] $OwnerSid + [SID] $GroupSid + [Acl] $Audit + [Acl] $Access + + hidden [byte] $revision + hidden [byte] $sbz1 + hidden [uint] $offsetOwner + hidden [uint] $offsetGroup + hidden [uint] $offsetSacl + hidden [uint] $offsetDacl + + SecurityDescriptor([byte[]] $securityDescriptorBytes) { + $binaryReader = [System.IO.BinaryReader][System.IO.MemoryStream]$securityDescriptorBytes + + $this.revision = $binaryReader.ReadByte() + $this.sbz1 = $binaryReader.ReadByte() + $this.Control = $binaryReader.ReadUInt16() + $this.offsetOwner = $binaryReader.ReadUInt16() + $this.offsetGroup = $binaryReader.ReadUInt16() + $this.offsetSacl = $binaryReader.ReadUInt16() + $this.offsetDacl = $binaryReader.ReadUInt16() + + $this.Owner = [Sid]::new($binaryReader) + $this.Group = [Sid]::new($binaryReader) + $this.Audit = [Acl]::new($binaryReader) + $this.Dacl = [Acl]::new($binaryReader) + } + + [byte[]] GetBytes() { + $bytes = [System.Collections.Generic.List[byte]]::new() + $bytes.Add($this.revision) + $bytes.Add($this.sbz1) + $bytes.AddRange([BitConverter]::GetBytes($this.Control)) + $bytes.AddRange([BitConverter]::GetBytes($this.offsetOwner)) + $bytes.AddRange([BitConverter]::GetBytes($this.offsetGroup)) + $bytes.AddRange([BitConverter]::GetBytes($this.offsetSacl)) + $bytes.AddRange([BitConverter]::GetBytes($this.offsetDacl)) + $bytes.AddRange($this.Owner.GetBytes()) + $bytes.AddRange($this.Group.GetBytes()) + $bytes.AddRange($this.Audit.GetBytes()) + $bytes.AddRange($this.Access.GetBytes()) + + return $bytes.ToArray() + } + + hidden static [System.DirectoryServices.ActiveDirectorySecurity] op_Implicit([SecurityDescriptor] $securityDescriptor) { + try { + $securityDescriptor = [System.DirectoryServices.ActiveDirectorySecurity]::new() + # Fill this in. + return $securityDescriptor + } catch { + throw + } + } +} diff --git a/Tests/Classes/01 - Base Classes/SID.Tests.ps1 b/Tests/Classes/01 - Base Classes/SID.Tests.ps1 index 78df781..88c1481 100644 --- a/Tests/Classes/01 - Base Classes/SID.Tests.ps1 +++ b/Tests/Classes/01 - Base Classes/SID.Tests.ps1 @@ -25,7 +25,7 @@ InModuleScope ActiveDirectoryCore { It 'can convert the SID string to binary' -TestCases $testCases { param ( [string]$SID, [string]$SIDBytes ) - [SID]::new($SID).ToBinary() | Should -Be ([Convert]::FromBase64String($SIDBytes)) + [SID]::new($SID).GetBytes() | Should -Be ([Convert]::FromBase64String($SIDBytes)) } It 'can convert the SID bytes to the SID string ' -TestCase $testCases { From 5f96f670d342d3a3cd5a524aa720e40a23dfa966 Mon Sep 17 00:00:00 2001 From: Chris Dent Date: Fri, 3 Apr 2020 17:38:48 +0100 Subject: [PATCH 3/7] Fixes SecurityDescriptor parser --- ActiveDirectoryCore/ActiveDirectoryCore.psd1 | 2 +- .../NTSecurityDescriptor/00 - AccessRight.ps1 | 19 ----- .../00 - AceFlags.ps1 | 0 .../00 - AceType.ps1 | 0 .../00 - DSSDControl.ps1} | 2 +- .../00 - IdentifierAuthority.ps1 | 0 .../00 - ObjectAceFlags.ps1 | 0 .../00 - EndianBinaryReader.ps1 | 29 +++++++ .../{02 - ADObject.ps1 => 011 - ADObject.ps1} | 0 .../012 - ADPrincipal.ps1} | 0 .../02 - Intermediate Classes/02 - Ace.ps1 | 37 --------- .../02 - Intermediate Classes/02 - Acl.ps1 | 61 --------------- .../02 - ObjectAce.ps1 | 4 - .../02 - SecurityDescriptor.ps1 | 58 -------------- .../020 - Sid.ps1} | 77 +++++++++---------- .../Classes/02 - Security/021 - Ace.ps1 | 59 ++++++++++++++ .../02 - Security/022 - CallbackAce.ps1 | 23 ++++++ .../Classes/02 - Security/022 - ObjectAce.ps1 | 29 +++++++ .../02 - Security/023 - AuditObjectAce.ps1 | 38 +++++++++ .../Classes/02 - Security/024 - Acl.ps1 | 20 +++++ .../025 - SecurityDescriptor.ps1 | 74 ++++++++++++++++++ 21 files changed, 310 insertions(+), 222 deletions(-) delete mode 100644 ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AccessRight.ps1 rename ActiveDirectoryCore/Classes/00 - Enums/{NTSecurityDescriptor => Security}/00 - AceFlags.ps1 (100%) rename ActiveDirectoryCore/Classes/00 - Enums/{NTSecurityDescriptor => Security}/00 - AceType.ps1 (100%) rename ActiveDirectoryCore/Classes/00 - Enums/{NTSecurityDescriptor/00 - SecurityDescriptorControl.ps1 => Security/00 - DSSDControl.ps1} (92%) rename ActiveDirectoryCore/Classes/00 - Enums/{SID => Security}/00 - IdentifierAuthority.ps1 (100%) rename ActiveDirectoryCore/Classes/00 - Enums/{NTSecurityDescriptor => Security}/00 - ObjectAceFlags.ps1 (100%) create mode 100644 ActiveDirectoryCore/Classes/01 - Base Classes/00 - EndianBinaryReader.ps1 rename ActiveDirectoryCore/Classes/01 - Base Classes/{02 - ADObject.ps1 => 011 - ADObject.ps1} (100%) rename ActiveDirectoryCore/Classes/{02 - Intermediate Classes/02 - ADPrincipal.ps1 => 01 - Base Classes/012 - ADPrincipal.ps1} (100%) delete mode 100644 ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Ace.ps1 delete mode 100644 ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Acl.ps1 delete mode 100644 ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - ObjectAce.ps1 delete mode 100644 ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - SecurityDescriptor.ps1 rename ActiveDirectoryCore/Classes/{01 - Base Classes/00 - SID.ps1 => 02 - Security/020 - Sid.ps1} (53%) create mode 100644 ActiveDirectoryCore/Classes/02 - Security/021 - Ace.ps1 create mode 100644 ActiveDirectoryCore/Classes/02 - Security/022 - CallbackAce.ps1 create mode 100644 ActiveDirectoryCore/Classes/02 - Security/022 - ObjectAce.ps1 create mode 100644 ActiveDirectoryCore/Classes/02 - Security/023 - AuditObjectAce.ps1 create mode 100644 ActiveDirectoryCore/Classes/02 - Security/024 - Acl.ps1 create mode 100644 ActiveDirectoryCore/Classes/02 - Security/025 - SecurityDescriptor.ps1 diff --git a/ActiveDirectoryCore/ActiveDirectoryCore.psd1 b/ActiveDirectoryCore/ActiveDirectoryCore.psd1 index b231a06..0c0eabb 100644 --- a/ActiveDirectoryCore/ActiveDirectoryCore.psd1 +++ b/ActiveDirectoryCore/ActiveDirectoryCore.psd1 @@ -119,4 +119,4 @@ # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. # DefaultCommandPrefix = '' -} +} diff --git a/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AccessRight.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AccessRight.ps1 deleted file mode 100644 index 8522ed9..0000000 --- a/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AccessRight.ps1 +++ /dev/null @@ -1,19 +0,0 @@ -[Flags()] -enum AccessRight : uint { - GenericRead = 0x80000000u - GenericWrite = 0x40000000 - GenericExecute = 0x20000000 - GenericAll = 0x10000000 - AccessSystemSecurity = 0x01000000 - Synchronize = 0x00100000 - WriteOwner = 0x00080000 - WriteDacl = 0x00040000 - ReadControl = 0x00020000 - Delete = 0x00010000 - ControlAccess = 0x00000100 - CreateChild = 0x00000001 - DeleteChild = 0x00000002 - ReadProperty = 0x00000010 - WriteProperty = 0x00000020 - ValidatedWrite = 0x00000008 -} diff --git a/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceFlags.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/Security/00 - AceFlags.ps1 similarity index 100% rename from ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceFlags.ps1 rename to ActiveDirectoryCore/Classes/00 - Enums/Security/00 - AceFlags.ps1 diff --git a/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceType.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/Security/00 - AceType.ps1 similarity index 100% rename from ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - AceType.ps1 rename to ActiveDirectoryCore/Classes/00 - Enums/Security/00 - AceType.ps1 diff --git a/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - SecurityDescriptorControl.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/Security/00 - DSSDControl.ps1 similarity index 92% rename from ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - SecurityDescriptorControl.ps1 rename to ActiveDirectoryCore/Classes/00 - Enums/Security/00 - DSSDControl.ps1 index f3d4b4f..afcb8c4 100644 --- a/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - SecurityDescriptorControl.ps1 +++ b/ActiveDirectoryCore/Classes/00 - Enums/Security/00 - DSSDControl.ps1 @@ -1,5 +1,5 @@ [Flags()] -enum SecurityDescriptorControl : ushort { +enum DSSDControl : ushort { SelfRelative = 0x0000 RMControlValid = 0x0001 SaclProtected = 0x0002 diff --git a/ActiveDirectoryCore/Classes/00 - Enums/SID/00 - IdentifierAuthority.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/Security/00 - IdentifierAuthority.ps1 similarity index 100% rename from ActiveDirectoryCore/Classes/00 - Enums/SID/00 - IdentifierAuthority.ps1 rename to ActiveDirectoryCore/Classes/00 - Enums/Security/00 - IdentifierAuthority.ps1 diff --git a/ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - ObjectAceFlags.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/Security/00 - ObjectAceFlags.ps1 similarity index 100% rename from ActiveDirectoryCore/Classes/00 - Enums/NTSecurityDescriptor/00 - ObjectAceFlags.ps1 rename to ActiveDirectoryCore/Classes/00 - Enums/Security/00 - ObjectAceFlags.ps1 diff --git a/ActiveDirectoryCore/Classes/01 - Base Classes/00 - EndianBinaryReader.ps1 b/ActiveDirectoryCore/Classes/01 - Base Classes/00 - EndianBinaryReader.ps1 new file mode 100644 index 0000000..a76a079 --- /dev/null +++ b/ActiveDirectoryCore/Classes/01 - Base Classes/00 - EndianBinaryReader.ps1 @@ -0,0 +1,29 @@ +class EndianBinaryReader : System.IO.BinaryReader { + EndianBinaryReader([System.IO.Stream]$BaseStream) : base($BaseStream) { } + + [ushort] ReadUInt16([bool] $isBigEndian) { + if ($isBigEndian) { + return [ushort](([ushort]$this.ReadByte() -shl 8) -bor $this.ReadByte()) + } else { + return $this.ReadUInt16() + } + } + + [uint] ReadUInt32([bool] $isBigEndian) { + if ($isBigEndian) { + return [UInt32]( + ([UInt32]$this.ReadByte() -shl 24) -bor + ([UInt32]$this.ReadByte() -shl 16) -bor + ([UInt32]$this.ReadByte() -shl 8) -bor + $this.ReadByte()) + } else { + return $this.ReadUInt32() + } + } + + [Byte] PeekByte() { + $value = $this.ReadByte() + $this.BaseStream.Seek(-1, 'Current') + return $value + } +} diff --git a/ActiveDirectoryCore/Classes/01 - Base Classes/02 - ADObject.ps1 b/ActiveDirectoryCore/Classes/01 - Base Classes/011 - ADObject.ps1 similarity index 100% rename from ActiveDirectoryCore/Classes/01 - Base Classes/02 - ADObject.ps1 rename to ActiveDirectoryCore/Classes/01 - Base Classes/011 - ADObject.ps1 diff --git a/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - ADPrincipal.ps1 b/ActiveDirectoryCore/Classes/01 - Base Classes/012 - ADPrincipal.ps1 similarity index 100% rename from ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - ADPrincipal.ps1 rename to ActiveDirectoryCore/Classes/01 - Base Classes/012 - ADPrincipal.ps1 diff --git a/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Ace.ps1 b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Ace.ps1 deleted file mode 100644 index 8c3201d..0000000 --- a/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Ace.ps1 +++ /dev/null @@ -1,37 +0,0 @@ -class Ace { - [AceType] $Type - [AceFlags] $Flags - [AccessRight] $AccessRights - [Sid[]] $IdentityReference - - hidden [ushort] $Size - - Ace() { } - - Ace([System.IO.BinaryReader] $binaryReader) { - $this.Type = $binaryReader.ReadByte() - $this.Flags = $binaryReader.ReadByte() - $this.Size = $binaryReader.ReadUInt16() - $this.AccessRights = $binaryReader.ReadUInt32() - - $bytesRemaining = $this.Size - $this.IdentityReference = while ($bytesRemaining -gt $this.Size) { - $sid = [Sid]::new($binaryReader) - $bytesRemaining -= $sid.BinaryLength - $sid - } - } - - [byte[]] GetBytes() { - $bytes = [System.Collections.Generic.List[byte]]::new() - $bytes.Add($this.Type) - $bytes.Add($this.Flags) - $bytes.AddRange([BitConverter]::GetBytes($this.AccessRights)) - - foreach ($sid in $this.Sid) { - $bytes.AddRange($sid.GetBytes()) - } - - return $bytes.ToArray() - } -} diff --git a/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Acl.ps1 b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Acl.ps1 deleted file mode 100644 index 47390a2..0000000 --- a/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - Acl.ps1 +++ /dev/null @@ -1,61 +0,0 @@ -class AclEnumerator : System.Collections.IEnumerator { - hidden [int] $position = -1 - hidden [object] $Current - hidden [object] ${IEnumerator.Current} - hidden [Ace[]] $_ace - - AclEnumerator([Ace[]] $ace) { - $this._ace = $ace - } - - [bool] MoveNext() { - $this.position++ - $this.Current = $this.'IEnumerator.Current' = $this._ace[$this.position] - return $this.position -lt $this._ace.Length - } - - [void] Reset() { - $this.Current = $this.{IEnumerator.Current} = $null - $this.Position = -1 - } -} - -class Acl : System.Collections.IEnumerable { - hidden [byte] $revision - hidden [byte] $sbz1 - hidden [ushort] $aclSize - hidden [ushort] $aceCount - hidden [ushort] $sbz2 - hidden [Ace[]] $_ace - - Acl([System.IO.BinaryReader] $binaryReader) { - $this.revision = $binaryReader.ReadByte() - $this.sbz1 = $binaryReader.ReadByte() - $this.aclSize = $binaryReader.ReadUInt16() - $this.aceCount = $binaryReader.ReadUInt16() - $this.sbz2 = $binaryReader.ReadUInt16() - - $this._ace = for ($i = 0; $i -lt $this.aceCount; $i++) { - [Ace]::new($binaryReader) - } - } - - [System.Collections.IEnumerator] GetEnumerator() { - return [AclEnumerator]::new($this._ace) - } - - [Byte[]] GetBytes([Ace[]] $ace) { - $bytes = [System.Collections.Generic.List[byte]]::new() - $bytes.Add($this.revision) - $bytes.Add($this.sbz1) - $bytes.AddRange([BitConverter]::GetBytes($this.aclSize)) - $bytes.AddRange([BitConverter]::GetBytes($this.aceCount)) - $bytes.AddRange([BitConverter]::GetBytes($this.sbz2)) - - foreach ($ace in $this._ace) { - $bytes.AddRange($ace.GetBytes()) - } - - return $bytes.ToArray() - } -} diff --git a/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - ObjectAce.ps1 b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - ObjectAce.ps1 deleted file mode 100644 index f1a3b02..0000000 --- a/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - ObjectAce.ps1 +++ /dev/null @@ -1,4 +0,0 @@ -class ObjectAce : Ace { - [Guid] $ObjectType - [Guid] $InheritedObjectType -} diff --git a/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - SecurityDescriptor.ps1 b/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - SecurityDescriptor.ps1 deleted file mode 100644 index 9587158..0000000 --- a/ActiveDirectoryCore/Classes/02 - Intermediate Classes/02 - SecurityDescriptor.ps1 +++ /dev/null @@ -1,58 +0,0 @@ -class SecurityDescriptor { - [ushort] $Control - [SID] $OwnerSid - [SID] $GroupSid - [Acl] $Audit - [Acl] $Access - - hidden [byte] $revision - hidden [byte] $sbz1 - hidden [uint] $offsetOwner - hidden [uint] $offsetGroup - hidden [uint] $offsetSacl - hidden [uint] $offsetDacl - - SecurityDescriptor([byte[]] $securityDescriptorBytes) { - $binaryReader = [System.IO.BinaryReader][System.IO.MemoryStream]$securityDescriptorBytes - - $this.revision = $binaryReader.ReadByte() - $this.sbz1 = $binaryReader.ReadByte() - $this.Control = $binaryReader.ReadUInt16() - $this.offsetOwner = $binaryReader.ReadUInt16() - $this.offsetGroup = $binaryReader.ReadUInt16() - $this.offsetSacl = $binaryReader.ReadUInt16() - $this.offsetDacl = $binaryReader.ReadUInt16() - - $this.Owner = [Sid]::new($binaryReader) - $this.Group = [Sid]::new($binaryReader) - $this.Audit = [Acl]::new($binaryReader) - $this.Dacl = [Acl]::new($binaryReader) - } - - [byte[]] GetBytes() { - $bytes = [System.Collections.Generic.List[byte]]::new() - $bytes.Add($this.revision) - $bytes.Add($this.sbz1) - $bytes.AddRange([BitConverter]::GetBytes($this.Control)) - $bytes.AddRange([BitConverter]::GetBytes($this.offsetOwner)) - $bytes.AddRange([BitConverter]::GetBytes($this.offsetGroup)) - $bytes.AddRange([BitConverter]::GetBytes($this.offsetSacl)) - $bytes.AddRange([BitConverter]::GetBytes($this.offsetDacl)) - $bytes.AddRange($this.Owner.GetBytes()) - $bytes.AddRange($this.Group.GetBytes()) - $bytes.AddRange($this.Audit.GetBytes()) - $bytes.AddRange($this.Access.GetBytes()) - - return $bytes.ToArray() - } - - hidden static [System.DirectoryServices.ActiveDirectorySecurity] op_Implicit([SecurityDescriptor] $securityDescriptor) { - try { - $securityDescriptor = [System.DirectoryServices.ActiveDirectorySecurity]::new() - # Fill this in. - return $securityDescriptor - } catch { - throw - } - } -} diff --git a/ActiveDirectoryCore/Classes/01 - Base Classes/00 - SID.ps1 b/ActiveDirectoryCore/Classes/02 - Security/020 - Sid.ps1 similarity index 53% rename from ActiveDirectoryCore/Classes/01 - Base Classes/00 - SID.ps1 rename to ActiveDirectoryCore/Classes/02 - Security/020 - Sid.ps1 index 99165a5..e1b4281 100644 --- a/ActiveDirectoryCore/Classes/01 - Base Classes/00 - SID.ps1 +++ b/ActiveDirectoryCore/Classes/02 - Security/020 - Sid.ps1 @@ -1,32 +1,38 @@ -class SID : IEquatable[Object] { +class Sid : IEquatable[Object] { [int] $BinaryLength [string] $AccountDomainSid [string] $Value - hidden [byte] $revisionLevel + hidden [byte] $revisionLevel hidden [IdentifierAuthority] $identifierAuthority - hidden [uint[]] $subAuthorities + hidden [uint[]] $subAuthorities - # Create an instance of SID from a string - SID([string] $sidString) { - $this.ConvertFromString($sidString) + # Create an instance of Sid from a string + Sid([string] $SidString) { + $this.ConvertFromString($SidString) } - # Create an instance of SID from the SecurityIdentifier class - SID([System.Security.Principal.SecurityIdentifier]$securityIdentifier) { + # Create an instance of Sid from the SecurityIdentifier class + Sid([System.Security.Principal.SecurityIdentifier]$securityIdentifier) { $this.ConvertFromString($securityIdentifier.ToString()) } - SID([byte[]] $sidBytes) { - $this.BinaryLength = $sidBytes.Count + Sid([byte[]] $SidBytes) { + $this.ConvertFromByte([EndianBinaryReader][System.IO.MemoryStream]$SidBytes) + } + + Sid([EndianBinaryReader] $binaryReader) { + $this.ConvertFromByte($binaryReader) + } - $this.revisionLevel = $sidBytes[0] - $subAuthorityCount = $sidBytes[1] + hidden [void] ConvertFromByte([EndianBinaryReader] $binaryReader) { + $this.revisionLevel = $binaryReader.ReadByte() + $subAuthorityCount = $binaryReader.ReadByte() $identifierAuthorityBytes = [byte[]]::new(8) [Array]::Copy( - $sidBytes, - 2, + $binaryReader.ReadBytes(6), + 0, $identifierAuthorityBytes, 2, 6 @@ -34,13 +40,9 @@ class SID : IEquatable[Object] { [Array]::Reverse($identifierAuthorityBytes) $this.identifierAuthority = [BitConverter]::ToUInt64($identifierAuthorityBytes) - $this.subAuthorities = for ($i = 8; $i -lt 8 + ($subAuthorityCount * 4); $i += 4) { - [BitConverter]::ToUInt32([byte[]]( - $sidBytes[$i], - $sidBytes[$i + 1], - $sidBytes[$i + 2], - $sidBytes[$i + 3] - )) + $this.BinaryLength = 8 + ($subAuthorityCount * 4) + $this.subAuthorities = for ($i = 0; $i -lt $subAuthorityCount; $i++) { + [BitConverter]::ToUInt32($binaryReader.ReadBytes(4)) } $this.Value = $this.ToString() @@ -49,35 +51,28 @@ class SID : IEquatable[Object] { $this.AccountDomainSid = $this } elseif ($this.subAuthorities.Count -gt 4) { - $accountDomainSidBytes = [byte[]]::new($this.BinaryLength - 4) - [Array]::Copy( - $sidBytes, - $accountDomainSidBytes, - $accountDomainSidBytes.Count - ) - $accountDomainSidBytes[1] = $this.subAuthorities.Count - 1 - $this.AccountDomainSid = [Sid]::new($accountDomainSidBytes) + $this.AccountDomainSid = [Sid]::new($this.Value -replace '-\d+$') } } - hidden ConvertFromString([string] $sidString) { - $null, $this.RevisionLevel, $this.identifierAuthority, $this.subAuthorities = $sidString -split '-' + hidden ConvertFromString([string] $SidString) { + $null, $this.RevisionLevel, $this.identifierAuthority, $this.subAuthorities = $SidString -split '-' $this.BinaryLength = 8 + ($this.subAuthorities.Count * 4) $this.Value = $this.ToString() if ($this.subAuthorities.Count -eq 4) { - $this.AccountDomainSid = $sidString + $this.AccountDomainSid = $SidString } elseif ($this.subAuthorities.Count -gt 4) { - $this.AccountDomainSid = $sidString -replace '-\d+$' + $this.AccountDomainSid = $SidString -replace '-\d+$' } } # Return the security identifier as a byte array. [byte[]] GetBytes() { - $sidBytes = [byte[]]::new($this.BinaryLength) - $sidBytes[0] = $this.revisionLevel - $sidBytes[1] = $this.subAuthorities.Count + $SidBytes = [byte[]]::new($this.BinaryLength) + $SidBytes[0] = $this.revisionLevel + $SidBytes[1] = $this.subAuthorities.Count $identifierAuthorityBytes = [BitConverter]::GetBytes([ulong]$this.identifierAuthority) [Array]::Reverse($identifierAuthorityBytes) @@ -85,7 +80,7 @@ class SID : IEquatable[Object] { [Array]::Copy( $identifierAuthorityBytes, 2, - $sidBytes, + $SidBytes, 2, 6 ) @@ -95,13 +90,13 @@ class SID : IEquatable[Object] { [Array]::Copy( $subAuthorityBytes, 0, - $sidBytes, + $SidBytes, (8 + ($i * 4)), 4 ) } - return $sidBytes + return $SidBytes } [string] ToString() { @@ -118,7 +113,7 @@ class SID : IEquatable[Object] { return $this.ToString() -eq $object.ToString() } - hidden static [System.Security.Principal.SecurityIdentifier] op_Implicit([SID] $sid) { - return [System.Security.Principal.SecurityIdentifier]$sid.ToString() + hidden static [System.Security.Principal.SecurityIdentifier] op_Implicit([Sid] $Sid) { + return [System.Security.Principal.SecurityIdentifier]$Sid.ToString() } } diff --git a/ActiveDirectoryCore/Classes/02 - Security/021 - Ace.ps1 b/ActiveDirectoryCore/Classes/02 - Security/021 - Ace.ps1 new file mode 100644 index 0000000..1dfeeb3 --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Security/021 - Ace.ps1 @@ -0,0 +1,59 @@ +class Ace { + [AceType] $AceType + [AceFlags] $AceFlags + [int] $AccessMask + [Sid] $IdentityReference + + hidden [ushort] $aceSize + hidden [byte[]] $otherData + + hidden Ace( + [AceType] $aceType, + [AceFlags] $aceFlags, + [ushort] $aceSize, + [EndianBinaryReader] $binaryReader + ) { + $this.AceType = $aceType + $this.AceFlags = $aceFlags + $this.aceSize = $aceSize + $this.AccessMask = $binaryReader.ReadUInt32() + + $this.ReadAce($binaryReader) + } + + hidden [void] ReadAce([EndianBinaryReader] $binaryReader) { + $this.IdentityReference = [Sid]::new($binaryReader) + $remainingSize = $this.aceSize - 8 - $this.IdentityReference.BinaryLength + + if ($remainingSize -gt 0) { + $this.otherData = $binaryReader.ReadBytes($remainingSize) + } + } + + hidden static [Ace] Parse([EndianBinaryReader] $binaryReader) { + $type = $binaryReader.ReadByte() + $flags = $binaryReader.ReadByte() + $size = $binaryReader.ReadUInt16() + + $aceObjectType = switch ([AceType]$type) { + ([AceType]::AllowObject) { [ObjectAce] } + ([AceType]::DenyObject) { [ObjectAce] } + ([AceType]::AuditObject) { [AuditObjectAce] } + default { [Ace] } + } + return $aceObjectType::new($type, $flags, $size, $binaryReader) + } + + [byte[]] GetBytes() { + $bytes = [System.Collections.Generic.List[byte]]::new() + $bytes.Add($this.Type) + $bytes.Add($this.Flags) + $bytes.AddRange([BitConverter]::GetBytes($this.AccessRights)) + + foreach ($sid in $this.Sid) { + $bytes.AddRange($sid.GetBytes()) + } + + return $bytes.ToArray() + } +} diff --git a/ActiveDirectoryCore/Classes/02 - Security/022 - CallbackAce.ps1 b/ActiveDirectoryCore/Classes/02 - Security/022 - CallbackAce.ps1 new file mode 100644 index 0000000..a4cda1a --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Security/022 - CallbackAce.ps1 @@ -0,0 +1,23 @@ +class CallbackAce : Ace { + [byte[]] $ApplicationData + + hidden CallbackAce( + [AceType] $aceType, + [AceFlags] $aceFlags, + [ushort] $aceSize, + [EndianBinaryReader] $binaryReader + ) : base( + $aceType, + $aceFlags, + $aceSize, + $binaryReader + ) { } + + hidden [void] ReadAce([EndianBinaryReader] $binaryReader) { + $this.IdentityReference = [Sid]::new($binaryReader) + $applicationDataSize = $this.AceSize - 8 - $this.IdentityReference.BinaryLength + if ($applicationDataSize -gt 0) { + $this.ApplicationData = $binaryReader.ReadBytes($applicationDataSize) + } + } +} diff --git a/ActiveDirectoryCore/Classes/02 - Security/022 - ObjectAce.ps1 b/ActiveDirectoryCore/Classes/02 - Security/022 - ObjectAce.ps1 new file mode 100644 index 0000000..6c8154f --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Security/022 - ObjectAce.ps1 @@ -0,0 +1,29 @@ +class ObjectAce : Ace { + [ObjectAceFlags] $Flags + [Guid] $ObjectType + [Guid] $InheritedObjectType + + hidden ObjectAce( + [AceType] $aceType, + [AceFlags] $aceFlags, + [ushort] $aceSize, + [EndianBinaryReader] $binaryReader + ) : base( + $aceType, + $aceFlags, + $aceSize, + $binaryReader + ) { } + + hidden [void] ReadAce([EndianBinaryReader] $binaryReader) { + $this.Flags = $binaryReader.ReadUInt32() + + if ($this.Flags.HasFlag([ObjectAceFlags]::ObjectTypePresent)) { + $this.ObjectType = $binaryReader.ReadBytes(16) + } + if ($this.Flags.HasFlag([ObjectAceFlags]::InheritedObjectTypePresent)) { + $this.InheritedObjectType = $binaryReader.ReadBytes(16) + } + $this.IdentityReference = [Sid]::new($binaryReader) + } +} diff --git a/ActiveDirectoryCore/Classes/02 - Security/023 - AuditObjectAce.ps1 b/ActiveDirectoryCore/Classes/02 - Security/023 - AuditObjectAce.ps1 new file mode 100644 index 0000000..f3001cd --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Security/023 - AuditObjectAce.ps1 @@ -0,0 +1,38 @@ +class AuditObjectAce : ObjectAce { + [byte[]] $ApplicationData + + hidden AuditObjectAce( + [AceType] $aceType, + [AceFlags] $aceFlags, + [ushort] $aceSize, + [EndianBinaryReader] $binaryReader + ) : base( + $aceType, + $aceFlags, + $aceSize, + $binaryReader + ) { } + + hidden [void] ReadAce([EndianBinaryReader] $binaryReader) { + $this.Flags = $binaryReader.ReadUInt32() + + if ($this.Flags.HasFlag([ObjectAceFlags]::ObjectTypePresent)) { + $this.ObjectType = $binaryReader.ReadBytes(16) + } + if ($this.Flags.HasFlag([ObjectAceFlags]::InheritedObjectTypePresent)) { + $this.InheritedObjectType = $binaryReader.ReadBytes(16) + } + $this.IdentityReference = [Sid]::new($binaryReader) + + $applicationDataSize = $this.AceSize - 12 - $this.IdentityReference.BinaryLength + if ($this.ObjectType) { + $applicationDataSize -= 16 + } + if ($this.InheritedObjectType) { + $applicationDataSize -= 16 + } + if ($applicationDataSize -gt 0) { + $this.ApplicationData = $binaryReader.ReadBytes($applicationDataSize) + } + } +} diff --git a/ActiveDirectoryCore/Classes/02 - Security/024 - Acl.ps1 b/ActiveDirectoryCore/Classes/02 - Security/024 - Acl.ps1 new file mode 100644 index 0000000..b9ff9c4 --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Security/024 - Acl.ps1 @@ -0,0 +1,20 @@ +class Acl { + [byte] $revision + [byte] $sbz1 + [ushort] $aclSize + [ushort] $aceCount + [ushort] $sbz2 + [Ace[]] $ace + + Acl([EndianBinaryReader] $binaryReader) { + $this.revision = $binaryReader.ReadByte() + $this.sbz1 = $binaryReader.ReadByte() + $this.aclSize = $binaryReader.ReadUInt16() + $this.aceCount = $binaryReader.ReadUInt16() + $this.sbz2 = $binaryReader.ReadUInt16() + + $this.ace = for ($i = 0; $i -lt $this.aceCount; $i++) { + [Ace]::Parse($binaryReader) + } + } +} diff --git a/ActiveDirectoryCore/Classes/02 - Security/025 - SecurityDescriptor.ps1 b/ActiveDirectoryCore/Classes/02 - Security/025 - SecurityDescriptor.ps1 new file mode 100644 index 0000000..714db07 --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Security/025 - SecurityDescriptor.ps1 @@ -0,0 +1,74 @@ +class SecurityDescriptor { + [DSSDControl] $Control + [SID] $Owner + [SID] $Group + [Ace[]] $Audit + [Ace[]] $Access + + hidden [byte] $revision + hidden [byte] $sbz1 + hidden [uint] $offsetOwner + hidden [uint] $offsetGroup + hidden [uint] $offsetSacl + hidden [uint] $offsetDacl + hidden [Acl] $dacl + hidden [Acl] $sacl + + SecurityDescriptor([byte[]] $securityDescriptorBytes) { + $binaryReader = [EndianBinaryReader][System.IO.MemoryStream]$securityDescriptorBytes + + $this.revision = $binaryReader.ReadByte() + $this.sbz1 = $binaryReader.ReadByte() + $this.Control = $binaryReader.ReadUInt16($true) + $this.offsetOwner = $binaryReader.ReadUInt32() + $this.offsetGroup = $binaryReader.ReadUInt32() + $this.offsetSacl = $binaryReader.ReadUInt32() + $this.offsetDacl = $binaryReader.ReadUInt32() + + if ($this.offsetOwner -gt 0) { + $binaryReader.BaseStream.Seek($this.offsetOwner, 'Begin') + $this.Owner = [Sid]::new($binaryReader) + } + if ($this.offsetGroup -gt 0) { + $binaryReader.BaseStream.Seek($this.offsetGroup, 'Begin') + $this.Group = [Sid]::new($binaryReader) + } + if ($this.offsetSacl) { + $binaryReader.BaseStream.Seek($this.offsetSacl, 'Begin') + $this.sacl = [Acl]::new($binaryReader) + $this.Audit = $this.sacl.Ace + } + if ($this.offsetDacl) { + $binaryReader.BaseStream.Seek($this.offsetDacl, 'Begin') + $this.dacl = [Acl]::new($binaryReader) + $this.Access = $this.dacl.Ace + } + } + + [byte[]] GetBytes() { + $bytes = [System.Collections.Generic.List[byte]]::new() + $bytes.Add($this.revision) + $bytes.Add($this.sbz1) + $bytes.AddRange([BitConverter]::GetBytes($this.Control)) + $bytes.AddRange([BitConverter]::GetBytes($this.offsetOwner)) + $bytes.AddRange([BitConverter]::GetBytes($this.offsetGroup)) + $bytes.AddRange([BitConverter]::GetBytes($this.offsetSacl)) + $bytes.AddRange([BitConverter]::GetBytes($this.offsetDacl)) + # $bytes.AddRange($this.Owner.GetBytes()) + # $bytes.AddRange($this.Group.GetBytes()) + # $bytes.AddRange($this.saclMetadata.GetBytes()) + # $bytes.AddRange($this.daclMetadata.GetBytes()) + + return $bytes.ToArray() + } + + hidden static [System.DirectoryServices.ActiveDirectorySecurity] op_Implicit([SecurityDescriptor] $securityDescriptor) { + try { + $securityDescriptor = [System.DirectoryServices.ActiveDirectorySecurity]::new() + # Fill this in. + return $securityDescriptor + } catch { + throw + } + } +} From 21afa2cd1f136111589d5069b4a20be4b145fc61 Mon Sep 17 00:00:00 2001 From: Chris Dent Date: Fri, 3 Apr 2020 17:53:43 +0100 Subject: [PATCH 4/7] Adds NTSecDesc to ADObject --- .../Classes/01 - Base Classes/011 - ADObject.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ActiveDirectoryCore/Classes/01 - Base Classes/011 - ADObject.ps1 b/ActiveDirectoryCore/Classes/01 - Base Classes/011 - ADObject.ps1 index 73e02a0..f385936 100644 --- a/ActiveDirectoryCore/Classes/01 - Base Classes/011 - ADObject.ps1 +++ b/ActiveDirectoryCore/Classes/01 - Base Classes/011 - ADObject.ps1 @@ -135,6 +135,10 @@ class ADObject { } } } + 'NTSecDesc' { + $converted.Value = [SecurityDescriptor]::new($attribute.ByteValue) + return $true + } { $_ -in 'Unicode', 'OID' } { $converted.Value = foreach ($string in $attribute.StringValueArray) { $string From 9000ffdfb085cc1a865767fd4ecbadf59b794d67 Mon Sep 17 00:00:00 2001 From: Chris Dent Date: Fri, 3 Apr 2020 18:23:15 +0100 Subject: [PATCH 5/7] Prettifies ACE --- .../Classes/02 - Security/021 - Ace.ps1 | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/ActiveDirectoryCore/Classes/02 - Security/021 - Ace.ps1 b/ActiveDirectoryCore/Classes/02 - Security/021 - Ace.ps1 index 1dfeeb3..b6fc1ad 100644 --- a/ActiveDirectoryCore/Classes/02 - Security/021 - Ace.ps1 +++ b/ActiveDirectoryCore/Classes/02 - Security/021 - Ace.ps1 @@ -1,11 +1,15 @@ class Ace { - [AceType] $AceType - [AceFlags] $AceFlags - [int] $AccessMask - [Sid] $IdentityReference + [AceType] $AceType + [System.DirectoryServices.ActiveDirectoryRights] $ActiveDirectoryRights + [Sid] $IdentityReference + [System.Security.AccessControl.InheritanceFlags] $InheritanceFlags + [bool] $IsInherited + [System.Security.AccessControl.PropagationFlags] $PropagationFlags - hidden [ushort] $aceSize - hidden [byte[]] $otherData + hidden [AceFlags] $aceFlags + hidden [int] $accessMask + hidden [ushort] $aceSize + hidden [byte[]] $otherData hidden Ace( [AceType] $aceType, @@ -14,9 +18,13 @@ class Ace { [EndianBinaryReader] $binaryReader ) { $this.AceType = $aceType - $this.AceFlags = $aceFlags + $this.aceFlags = $aceFlags $this.aceSize = $aceSize - $this.AccessMask = $binaryReader.ReadUInt32() + $this.accessMask = $binaryReader.ReadUInt32() + $this.ActiveDirectoryRights = $this.accessMask + $this.InheritanceFlags = $this.aceFlags -band 0x03 + $this.IsInherited = $this.aceFlags.HasFlag([AceFlags]::Inherited) + $this.PropagationFlags = ($this.aceFlags -band 0x0C) -as [int] -shr 2 $this.ReadAce($binaryReader) } From a1822338b78f31c46b789c5fb68d144aa1ead681 Mon Sep 17 00:00:00 2001 From: Chris Dent Date: Fri, 3 Apr 2020 19:26:23 +0100 Subject: [PATCH 6/7] Prettifies SecurityDescriptor --- .../025 - SecurityDescriptor.ps1 | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/ActiveDirectoryCore/Classes/02 - Security/025 - SecurityDescriptor.ps1 b/ActiveDirectoryCore/Classes/02 - Security/025 - SecurityDescriptor.ps1 index 714db07..a7234f7 100644 --- a/ActiveDirectoryCore/Classes/02 - Security/025 - SecurityDescriptor.ps1 +++ b/ActiveDirectoryCore/Classes/02 - Security/025 - SecurityDescriptor.ps1 @@ -1,30 +1,35 @@ class SecurityDescriptor { - [DSSDControl] $Control [SID] $Owner [SID] $Group [Ace[]] $Audit [Ace[]] $Access + [bool] $AreAccessRulesProtected + [bool] $AreAuditRulesProtected - hidden [byte] $revision - hidden [byte] $sbz1 - hidden [uint] $offsetOwner - hidden [uint] $offsetGroup - hidden [uint] $offsetSacl - hidden [uint] $offsetDacl - hidden [Acl] $dacl - hidden [Acl] $sacl + hidden [DSSDControl] $control + hidden [byte] $revision + hidden [byte] $sbz1 + hidden [uint] $offsetOwner + hidden [uint] $offsetGroup + hidden [uint] $offsetSacl + hidden [uint] $offsetDacl + hidden [Acl] $dacl + hidden [Acl] $sacl SecurityDescriptor([byte[]] $securityDescriptorBytes) { $binaryReader = [EndianBinaryReader][System.IO.MemoryStream]$securityDescriptorBytes $this.revision = $binaryReader.ReadByte() $this.sbz1 = $binaryReader.ReadByte() - $this.Control = $binaryReader.ReadUInt16($true) + $this.control = $binaryReader.ReadUInt16($true) $this.offsetOwner = $binaryReader.ReadUInt32() $this.offsetGroup = $binaryReader.ReadUInt32() $this.offsetSacl = $binaryReader.ReadUInt32() $this.offsetDacl = $binaryReader.ReadUInt32() + $this.AreAccessRulesProtected = $this.control.HasFlag([DSSDControl]::DaclProtected) + $this.AreAuditRulesProtected = $this.control.HasFlag([DSSDControl]::SaclProtected) + if ($this.offsetOwner -gt 0) { $binaryReader.BaseStream.Seek($this.offsetOwner, 'Begin') $this.Owner = [Sid]::new($binaryReader) From e261e295b22d5485de5733399e4f6acbbe4601f9 Mon Sep 17 00:00:00 2001 From: Chris Dent Date: Sat, 4 Apr 2020 18:51:09 +0100 Subject: [PATCH 7/7] Adding well known SID handler --- .../00 - Enums/Security/00 - WellKnownSid.ps1 | 56 ++++++++++++++++ .../013 - SecurityPrincipal.ps1 | 3 + .../020 - ADSecurityPrincipal.ps1 | 11 ++++ .../Classes/02 - Security/020 - Sid.ps1 | 2 +- .../02 - Security/020 - WellKnownSid.ps1 | 66 +++++++++++++++++++ .../Classes/02 - Security/021 - Ace.ps1 | 2 +- .../025 - SecurityDescriptor.ps1 | 12 ++-- 7 files changed, 144 insertions(+), 8 deletions(-) create mode 100644 ActiveDirectoryCore/Classes/00 - Enums/Security/00 - WellKnownSid.ps1 create mode 100644 ActiveDirectoryCore/Classes/01 - Base Classes/013 - SecurityPrincipal.ps1 create mode 100644 ActiveDirectoryCore/Classes/02 - Security/020 - ADSecurityPrincipal.ps1 create mode 100644 ActiveDirectoryCore/Classes/02 - Security/020 - WellKnownSid.ps1 diff --git a/ActiveDirectoryCore/Classes/00 - Enums/Security/00 - WellKnownSid.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/Security/00 - WellKnownSid.ps1 new file mode 100644 index 0000000..34311a4 --- /dev/null +++ b/ActiveDirectoryCore/Classes/00 - Enums/Security/00 - WellKnownSid.ps1 @@ -0,0 +1,56 @@ +enum WellKnownSid : ulong { + CREATORGROUP = 0x0100000000 + DIALUP = 0x0100000000 + CONSOLELOGON = 0x0100000000 + NETWORK = 0x0200000000 + CREATOROWNERSERVER = 0x0200000000 + BATCH = 0x0300000000 + CREATORGROUPSERVER = 0x0300000000 + OWNERRIGHTS = 0x0400000000 + INTERACTIVE = 0x0400000000 + SERVICE = 0x0600000000 + ANONYMOUSLOGON = 0x0700000000 + PROXY = 0x0800000000 + ENTERPRISEDOMAINCONTROLLERS = 0x0900000000 + SELF = 0x0A00000000 + AuthenticatedUsers = 0x0B00000000 + RESTRICTED = 0x0C00000000 + TERMINALSERVERUSER = 0x0D00000000 + ThisOrganization = 0x0F00000000 + SYSTEM = 0x1200000000 + LOCALSERVICE = 0x1300000000 + NETWORKSERVICE = 0x1400000000 + Wellknown = 0x1500000000 # Check name + Administrators = 0x2000000220 + Users = 0x2000000221 + Guests = 0x2000000222 + PowerUsers = 0x2000000223 + AccountOperators = 0x2000000224 # Check name + ServerOperators = 0x2000000225 # Check name + PrintOperators = 0x2000000226 # Check name + BackupOperators = 0x2000000227 + Replicator = 0x2000000228 + PreWindows2000CompatibleAccess = 0x200000022A # Check name + RemoteDesktopUsers = 0x200000022B + NetworkConfigurationOperators = 0x200000022C + IncomingForestTrustBuilders = 0x200000022D # Check name + PerformanceMonitorUsers = 0x200000022E + PerformanceLogUsers = 0x200000022F + WindowsAuthorizationAccessGroup = 0x2000000230 # Check name + TerminalServerLicenseServers = 0x2000000231 # Check name + DistributedCOMUsers = 0x2000000232 + CryptographicOperators = 0x2000000239 + EventLogReaders = 0x200000023D + CertificateServiceDCOMAccess = 0x200000023E # Check name + RDSRemoteAccessServers = 0x200000023F # Check name + RDSEndpointServers = 0x2000000240 # Check name + RDSManagementServers = 0x2000000241 # Check name + HyperVAdministrators = 0x2000000242 + AccessControlAssistanceOperators = 0x2000000243 + RemoteManagementUsers = 0x2000000244 + StorageReplicaAdministrators = 0x2000000246 # Check name + ALLSERVICES = 0x5000000000 + NTService = 0x5000000000 # Check name + VirtualMachines = 0x5300000000 # Check name + WindowManagerGroup = 0x5A00000000 +} diff --git a/ActiveDirectoryCore/Classes/01 - Base Classes/013 - SecurityPrincipal.ps1 b/ActiveDirectoryCore/Classes/01 - Base Classes/013 - SecurityPrincipal.ps1 new file mode 100644 index 0000000..482afc0 --- /dev/null +++ b/ActiveDirectoryCore/Classes/01 - Base Classes/013 - SecurityPrincipal.ps1 @@ -0,0 +1,3 @@ +class SecurityPrincipal { + +} diff --git a/ActiveDirectoryCore/Classes/02 - Security/020 - ADSecurityPrincipal.ps1 b/ActiveDirectoryCore/Classes/02 - Security/020 - ADSecurityPrincipal.ps1 new file mode 100644 index 0000000..e846c9e --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Security/020 - ADSecurityPrincipal.ps1 @@ -0,0 +1,11 @@ +class ADSecurityPrincipal : SecurityPrincipal { + [string] $DomainName + [string] $SamAccountName + [string] $UserPrincipalName + [Sid] $Sid + + + [string] ToString() { + return '{0}\{1}' -f $this.DomainName, $this.SamAccountName + } +} diff --git a/ActiveDirectoryCore/Classes/02 - Security/020 - Sid.ps1 b/ActiveDirectoryCore/Classes/02 - Security/020 - Sid.ps1 index e1b4281..a11adda 100644 --- a/ActiveDirectoryCore/Classes/02 - Security/020 - Sid.ps1 +++ b/ActiveDirectoryCore/Classes/02 - Security/020 - Sid.ps1 @@ -1,4 +1,4 @@ -class Sid : IEquatable[Object] { +class Sid : SecurityPrincipal, IEquatable[Object] { [int] $BinaryLength [string] $AccountDomainSid [string] $Value diff --git a/ActiveDirectoryCore/Classes/02 - Security/020 - WellKnownSid.ps1 b/ActiveDirectoryCore/Classes/02 - Security/020 - WellKnownSid.ps1 new file mode 100644 index 0000000..22c102e --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Security/020 - WellKnownSid.ps1 @@ -0,0 +1,66 @@ +class WellKnownPrincipal : SecurityPrincipal { + [string] $Domain + [string] $Name + [Sid] $Sid + + WellKnownPrincipal([string]$Identity) { + $this.Domain, $this.Name = $Identity -split '\\' + + $value = [WellKnownPrincipal]::SELF + if ([Enum]::TryParse([WellKnownPrincipal], $this.Name -replace '[\s-]', [ref]$value)) { + } + } + + WellKnownPrincipal([Sid]$sid) { + $this.Sid = $sid + + if ($sid.IdentifierAuthority -eq 'World' -and $sid.subAuthorities[0] -eq 0) { + $this.Name = 'Everyone' + } + elseif ($sid.IdentifierAuthority -eq 'NT') { + $this.Domain = switch ($sid.subAuthorities[0]) { + { $_ -le 20 } { 'NT AUTHORITY'; break } + 32 { + if ($Sid.subAuthorities[1] -ge 500 -and $Sid.subAuthorities[1] -lt 600) { + 'BUILTIN' + } + break + } + 80 { 'NT SERVICE'; break } + } + + $wellKnownSid = ([ulong]$sid.subAuthorities[0] -shl 32) + $sid.subAuthorities[1] + + if ($sidName = [Enum]::GetName([WellKnownSid], $wellKnownSid)) { + $this.Name = $sidName -creplace '(?<=.)([A-Z])', ' $1' + } + + $this.Name = switch ($this.Name) { + 'PreWindows 2000 Compatible Access' { 'Pre-Windows 2000 Compatible Access' } + 'HyperV Administrators' { 'Hyper-V Administrators' } + default { $_ } + } + } + } + + # WellKnownSid($sidType, $domainSid) { + + # } + + # [Sid] GetDomainSid() { + # } + + # [Sid] GetForestSid() { + # } + + [string] ToString() { + if ($this.Domain) { + return '{0}\{1}' -f $this.Domain, $this.Name + } + else { + return $this.Name + } + } +} + +[WellKnownPrincipal][Sid]'S-1-5-32-580' diff --git a/ActiveDirectoryCore/Classes/02 - Security/021 - Ace.ps1 b/ActiveDirectoryCore/Classes/02 - Security/021 - Ace.ps1 index b6fc1ad..0c72eb3 100644 --- a/ActiveDirectoryCore/Classes/02 - Security/021 - Ace.ps1 +++ b/ActiveDirectoryCore/Classes/02 - Security/021 - Ace.ps1 @@ -1,7 +1,7 @@ class Ace { [AceType] $AceType [System.DirectoryServices.ActiveDirectoryRights] $ActiveDirectoryRights - [Sid] $IdentityReference + [SecurityPrincipal] $IdentityReference [System.Security.AccessControl.InheritanceFlags] $InheritanceFlags [bool] $IsInherited [System.Security.AccessControl.PropagationFlags] $PropagationFlags diff --git a/ActiveDirectoryCore/Classes/02 - Security/025 - SecurityDescriptor.ps1 b/ActiveDirectoryCore/Classes/02 - Security/025 - SecurityDescriptor.ps1 index a7234f7..5427c65 100644 --- a/ActiveDirectoryCore/Classes/02 - Security/025 - SecurityDescriptor.ps1 +++ b/ActiveDirectoryCore/Classes/02 - Security/025 - SecurityDescriptor.ps1 @@ -1,10 +1,10 @@ class SecurityDescriptor { - [SID] $Owner - [SID] $Group - [Ace[]] $Audit - [Ace[]] $Access - [bool] $AreAccessRulesProtected - [bool] $AreAuditRulesProtected + [SecurityPrincipal] $Owner + [SecurityPrincipal] $Group + [Ace[]] $Audit + [Ace[]] $Access + [bool] $AreAccessRulesProtected + [bool] $AreAuditRulesProtected hidden [DSSDControl] $control hidden [byte] $revision