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/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/Security/00 - AceFlags.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/Security/00 - AceFlags.ps1 new file mode 100644 index 0000000..5c89041 --- /dev/null +++ b/ActiveDirectoryCore/Classes/00 - Enums/Security/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/Security/00 - AceType.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/Security/00 - AceType.ps1 new file mode 100644 index 0000000..02f78f2 --- /dev/null +++ b/ActiveDirectoryCore/Classes/00 - Enums/Security/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/Security/00 - DSSDControl.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/Security/00 - DSSDControl.ps1 new file mode 100644 index 0000000..afcb8c4 --- /dev/null +++ b/ActiveDirectoryCore/Classes/00 - Enums/Security/00 - DSSDControl.ps1 @@ -0,0 +1,19 @@ +[Flags()] +enum DSSDControl : 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/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/Security/00 - ObjectAceFlags.ps1 b/ActiveDirectoryCore/Classes/00 - Enums/Security/00 - ObjectAceFlags.ps1 new file mode 100644 index 0000000..31a66a5 --- /dev/null +++ b/ActiveDirectoryCore/Classes/00 - Enums/Security/00 - ObjectAceFlags.ps1 @@ -0,0 +1,6 @@ +[Flags()] +enum ObjectAceFlags : uint { + None + ObjectTypePresent + InheritedObjectTypePresent +} 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/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 94% rename from ActiveDirectoryCore/Classes/01 - Base Classes/02 - ADObject.ps1 rename to ActiveDirectoryCore/Classes/01 - Base Classes/011 - ADObject.ps1 index 73e02a0..f385936 100644 --- a/ActiveDirectoryCore/Classes/01 - Base Classes/02 - 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 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/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/01 - Base Classes/00 - SID.ps1 b/ActiveDirectoryCore/Classes/02 - Security/020 - Sid.ps1 similarity index 52% rename from ActiveDirectoryCore/Classes/01 - Base Classes/00 - SID.ps1 rename to ActiveDirectoryCore/Classes/02 - Security/020 - Sid.ps1 index b293983..a11adda 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 : SecurityPrincipal, 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[]] ToBinary() { - $sidBytes = [byte[]]::new($this.BinaryLength) - $sidBytes[0] = $this.revisionLevel - $sidBytes[1] = $this.subAuthorities.Count + [byte[]] GetBytes() { + $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/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 new file mode 100644 index 0000000..0c72eb3 --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Security/021 - Ace.ps1 @@ -0,0 +1,67 @@ +class Ace { + [AceType] $AceType + [System.DirectoryServices.ActiveDirectoryRights] $ActiveDirectoryRights + [SecurityPrincipal] $IdentityReference + [System.Security.AccessControl.InheritanceFlags] $InheritanceFlags + [bool] $IsInherited + [System.Security.AccessControl.PropagationFlags] $PropagationFlags + + hidden [AceFlags] $aceFlags + hidden [int] $accessMask + 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.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) + } + + 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..5427c65 --- /dev/null +++ b/ActiveDirectoryCore/Classes/02 - Security/025 - SecurityDescriptor.ps1 @@ -0,0 +1,79 @@ +class SecurityDescriptor { + [SecurityPrincipal] $Owner + [SecurityPrincipal] $Group + [Ace[]] $Audit + [Ace[]] $Access + [bool] $AreAccessRulesProtected + [bool] $AreAuditRulesProtected + + 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.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) + } + 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 + } + } +} 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 {