Category Archives: NTFS Security

The lowdown on SIDHistory

Sup’ PSHomies,

SIDHistory is one of those Active Directory attributes you love to hate. When migrating from one domain to another, it let’s you retain access to resources in the Source Domain. This is a great way to transition, but in my experience it also makes for quick-shift migrations.

The first thing I do whenever we start a migration is have a look at SIDHistory. This will let me know quickly what we’re dealing with:

  • Has there been a previous migration? (I’ve seen objects in excess of 5 entries)
  • Did they clean up? (Obviously they didn’t or I wouldn’t see any entries)
  • Do I need to worry about Token-bloat?

Remember the blog I did about SDDL? Well SDDL deals with access based on SIDs. When a user logs on to the system, not only the new SID, but also the old SID is retrieved from the SIDHistory attribute and is added to the user’s access token and used to determine the user’s group memberships. The SIDs of the groups of which the user is a member through either the new SID or the old SID are then also added to the access token, together with any SIDHistory those groups might have.

This is also the reason tokenbloat can be an issue if it isn’t cleaned up after a migration.

So how do you find out about SIDHistory?

Get-ADObject -LDAPFilter "(sIDHistory=*)" -Property objectClass, distinguishedname, samAccountName, objectSID, sIDHistory |
Select-Object objectClass, DistinguishedName, SamAccountName, objectSID -ExpandProperty SIDHistory |
ForEach-Object {
[PSCustomObject]@{
ObjectClass = $_.objectClass
DistinguishedName = $_.DistinguishedName
SamAccountName = $_.SamAccountName
SID = $_.ObjectSID
DomainSID = $_.AccountDomainSID
SIDHistory = $_.Value
}
} |
Out-GridView -Title "AD Objects with SIDHistory"

On the subject of removing SIDHistory

This is tricky. Having and keeping SIDHistory intact will keep many a pesky helpdesk calls at bay… But is it wise to keep it?

From a Data (Read NTFS) perspective, you’ll need to Re-Acl your data structure. If you’ve kept you NTFS ACLs (Access Control List) nice and tidy (Wait, gimme a second to catch my breath from laughing) then you’re golden! This has never been the case in all my migrations  so far. My advice when it comes to Re-Acl, is to recreate the data structure (empty) and assign the correct ACEs (Access Control Entry) to the ACLs. Maybe I need to explain what Re-acl a bit more…

Re-ACL is the process of translating SIDs on Resources. I first came across the term using Quest Migration tools. This gave me the option to:

  • add the target SID to a resource
  • replace source SID on said resource
  • remove source SID from resource if everything is working

Here are the things you need to consider for each option

Adding the targetSID to a Resource

This gives the AD Object  access without having to rely on SIDHistory. This means that once the target SID has been added you can safely clean up SIDHistory. A target SID can only be added if a valid source SID has been found. I’ve seen too many ACLs with unknown ACEs in migrations I did over the years. This does nothing to clean up those unknown ACEs. Adding a target SID will expand you ACLs, which can have an impact on processing time

Replacing the sourceSID on a Resource

This makes for a cleaner ACL. Again, this does nothing for unknown ACEs. Replacing adds the targetSID and removes the sourceSID in the same process. A bold move, reverting SIDHistory isn’t as easy a writing to other AD object attributes and for good reason.

Remove sourceSID from Resource once everything has been verified to be working

Most are quite content that everything is working and don’t bother with this. Again, if your structure is up to date, this shouldn’t be an issue. What I’ll usually hear is: “We’ll create a new structure later on and get that cleaned up…” This rarely happens…

To wrap up

SIDHistory is a great way to retain access to source Resources, just make cleanup a part of the migration (If possible).This will vastly improve tokensize and improve your security

Re-Acl only makes sense if you’re content with your current NTFS data structure. If not, then I’d suggest redefining your Data structure. It’s a chore but well worth it.

Hope it’s worth something to you…

Ttyl,

Urv

ACLs Folder class

‘Sup PSHomies,

I recently had to make a quick Backup & Restore of ACLs three levels deep. Nothing fancy, just two functions, but that got me thinking…

Why not make a class of this?

And so I did! Here’s the framework for the class:

classACLFolders

Here’s a list of the methods:

  • Backup. Backup SDDL from the property $Folder of the class
  • Restore. Restore SDDL to the property $Folder of the class
  • Clone. Clone will take a target Folder and clone the SDDL of $Folder to it
  • ConvertSDDLToAccess. This will enumerate what the SDDL stands for

Default Constructor

classACLDefConstructor

The default constructor will evaluate the folder used to instantiate the object. If successful, the SDDL, Owner and Access is retrieved using  the Backup() method. All actions are registered for future reference.

Instantiating is pretty straightforward:

instantiateClass

Backup()

classACLBackup

This will retrieve the SDDL for the folder and enumerate the Access.

Restore()

classACLRestore

Restore is a bit tricky. For one you need to make sure it isn’t empty. Set-Acl has no problem setting an empty SDDL, blowing everything open (worst case scenario, and that’s why you should test this in a lab first!). The other challenge is having a valid SDDL string. You can change the SDDL string if you want to something gibberish, hence the typecast as a precaution.

Clone()

classACLDefClone

The same goes for cloning. In this case we need to test the target path. Alternatively, you could  also change the Folder to a new path… It works, you’d just have misleading ActionHistory entries… I wonder if there’s a way to make this read-only,  just thinking out loud here… (note to self)

ConvertSDDLToAccess()

This is just a lil’ something extra. Like I said in a previous blog SDDL really gives more information. For one, the SID will let you know which domain this object belongs to. One thing I ran into with ReACL is that SIDHistory will resolve to the current NTAccount. This had me puzzled for a while until I saw that the SIDs in SDDL where different.

Here’s what the ouput looks like:

convertSDDLToAccess

Now for those of you that are wondering just what is this AccessMask, wonder no more! 🙂

Remember the RoboCopy ExitCodes blog I did a while back? Well it’s the same principal 🙂 This is why classes & everything related should be on your radar…

enumAccessmask

Here’s how this works…

Say I wanted to evaluate the AccessMask of a SDDL entry

AccessMaskEnum
classACLConvertSDDLToAccess

Here I have the SID & the NTAccount. This is the builtin administrators account but it also works for Domain accounts.

There’s a private function that will translate the SID accordingly.

To see what the account can actually do we can enumerate the AccessMask

AccessMaskEnum1
AdvancedPermissions

This is what we’d see using the advanced Security GUI tab of a folder.

Not bad… Not bad at all…

I can’t state this enough, SDDL is NOT to be be trifled with. Yes you need admin rights and please try this is a testlab first.  SDDL is very potent, if used with caution, it could do a whole bit of good!

So finally, here’s the code…

[Flags()] Enum AccessMask{
Read = 1
Write = 2
Append = 4
ReadExtendedAttributes = 8
WriteExtendedAttributes = 16
Execute = 32
DeleteDirectory = 64
ReadAttributes = 128
WriteAttributes = 256
Delete = 65536
ReadSecurity = 131072
WriteACL = 262144
WriteOwner = 524288
Synchronize = 1048576
}
class aclsFolder{
[String]$Folder
[String]$SDDL
[String]$Owner
[PSObject[]]$Access
[PSObject[]]$ActionHistory
#Default Constructor
aclsFolder($fldr){
if(Test-Path -Path $fldr){
$this.Folder = $fldr
$Tags = @('Default','Constructor','valid')
$MessageData = "Path $($fldr) found"
$this.ActionHistory += Write-Information -MessageData $MessageData 6>&1 -Tags $Tags | Select-Object *
$this.Backup()
}
else{
$Tags = @('Default','Constructor','invalid')
$MessageData = "Path $($fldr) not found"
$this.ActionHistory += Write-Information -MessageData $MessageData 6>&1 -Tags $Tags | Select-Object *
}
}
#Methods
Backup(){
if(Test-Path $this.Folder){
$result = Get-Acl $this.Folder
$this.SDDL = $result.Sddl
$this.Owner = $result.Owner
$this.Access = $($result.Access | Select-Object File*,Access*,Identity*,IsInherited,*Flags)
$Tags = @('Backup','Success')
$MessageData = "Backup SDDL of $($this.Folder) was successful"
$this.ActionHistory += Write-Information -MessageData $MessageData 6>&1 -Tags $Tags | Select-Object *
}
else{
Write-Warning "Invalid Path $($this.Folder)"
$Tags = @('Backup','Failed')
$MessageData = "Backup SDDL of $($this.Folder) has failed"
$this.ActionHistory += Write-Information -MessageData $MessageData 6>&1 -Tags $Tags | Select-Object *
}
}
Restore(){
if((Test-Path $this.Folder) -and
![string]::isNullOrEmpty($this.SDDL) -and
[Security.AccessControl.RawSecurityDescriptor]$this.SDDL){
$acl = Get-Acl -Path $this.Folder
$acl.SetSecurityDescriptorSddlForm($this.SDDL)
Set-Acl -Path $($this.Folder) -AclObject $($acl)
$Tags = @('Restore', 'Success')
$MessageData = "Restoring SDDL on $($this.Folder) was succesful"
$this.ActionHistory += Write-Information -MessageData $MessageData 6>&1 -Tags $Tags | Select-Object *
#Reset values
$this.Backup()
}
else{
Write-Warning "Invalid Path $($this.Folder) or SDDL is invalid"
$Tags = @('Restore', 'Failed')
$MessageData = "Restoring SDDL on $($this.Folder) has failed"
$this.ActionHistory += Write-Information -MessageData $MessageData 6>&1 -Tags $Tags | Select-Object *
}
}
Clone($tgt){
if((Test-Path -Path $tgt) -and
![string]::isNullOrEmpty($this.SDDL) -and
[Security.AccessControl.RawSecurityDescriptor]$this.SDDL){
$acl = Get-Acl -Path $tgt
$acl.SetSecurityDescriptorSddlForm($this.SDDL)
Set-Acl -Path $($tgt) -AclObject $($acl)
$Tags = @('Clone', 'Success')
$MessageData = "Cloning SDDL on $($this.Folder) was succesful"
$this.ActionHistory += Write-Information -MessageData $MessageData 6>&1 -Tags $Tags | Select-Object *
}
else{
Write-Warning "Invalid Path $($this.Folder) or SDDL is invalid"
$Tags = @('Clone', 'Failed')
$MessageData = "Cloning SDDL on $($this.Folder) has failed"
$this.ActionHistory += Write-Information -MessageData $MessageData 6>&1 -Tags $Tags | Select-Object *
}
}
[PSObject]ConvertSDDLToAccess(){
Function Convert-SID2NTAccount{
param(
$SID
)
$objSID = New-Object System.Security.Principal.SecurityIdentifier($SID)
$objUser = $objSID.Translate( [System.Security.Principal.NTAccount])
$objUser
}
$accessSDDL = ([Security.AccessControl.RawSecurityDescriptor]$this.SDDL).DiscretionaryAcl |
ForEach-Object{
[PSCustomObject]@{
SID = $_.SecurityIdentifier
NTAccount = (Convert-SID2NTAccount -SID $_.SecurityIdentifier)
AceQualifier = $_.AceQualifier
AccessMask = $_.AccessMask
AceType = $_.AceType
AceFlags = $_.AceFlags
IsInherited = $_.IsInherited
InheritanceFlags = $_.InheritanceFlags
}
}
return $accessSDDL
}
}

Hope it’s worth something to you…

Ttyl,

Urv

Revisiting NTFS Longpaths issue

wpid-wp-1433338305313.jpg

‘Sup PSHomies! It will be a thing… trust me…

Before the NTFSSecurity module there was a little known trick I used to get the NTFS rights on longpath folders: \\?\

There’s just one catch… It only works with windows command utilities. ICACLS, MD, ATTRIB can all make use of this prefix.

Let’s say I wanted to read the NTFS rights on a longpath folder using icacls. The command for this would be:

icacls “\\?\<Driveletter:>\LongPath” 

Notice the <DriveLetter:> syntax? Well that’s because \\?\ can only be used as a prefix in front of a DriveLetter. It did mean that I had to make a drivemapping, an inconvenience I didn’t mind one bit!

Ok I’ll admit that I tried using a UNCPath, but that didn’t work… can’t blame a brother for trying eh? 😉

While I was using the NTFSSecurity module (Did I mention how much I love this module?) I got an access denied on a folder (No that’s not the exciting part). What I did noticed was a familiar prefix of sorts: \\?\UNC\

So you can use the UNCPath as well! All I had to do was omit the ‘\\’ from the path. Say I wanted to read the NTFS rights on ‘\\SERVERX\SHARE\Longpath’ the syntax would be:

‘\\?\UNC\SERVERX\SHARE\LongPath’

Awesome right?!!! Now you might be asking yourself: ‘Well that’s all gravy Urv, but why bother? Why not just use the NTFSSecurity module?”

There’s an old saying that goes: “A poor workman always blames his tools…”

There may be times when PowerShell isn’t readily available to you (I know perish the thought!). Sometimes you have to make do with what’s available! When it comes to manipulating NTFS rights you should be proficient in using different tools/utilities. I’ll admit while I love PowerShell Set-Acl has to be my least favorite cmdlet!

So what’s next?

Well imagine enumerating a longpath folder without errors and retrieving the NTFS rights.

example ICACLS

Looking at the output, you should be able to do some neat formatting using regular expressions!  Hey! I didn’t say you weren’t allowed to use PowerShell at all… Regular Expressions… Not my forte… Any takers in the PowerShell community? 🙂

Having alternative methods for retrieving NTFS rights is always a good thing. You can always use an alternative methods for verification. Get-Acl (Get-Acl2 if using NTFSSecurity), ICACLS and the security tab (Always use Advanced mode) are my methods of choice for verification.

Hope it’s worth something to you

Ttyl,

Urv

PS. powershell.com has some great posts how to handle NTFS the PowerShell way! 😉

SDDL gives more NTFS insight

I’ve been doing migrations, oh say for the past 10 years (Hmmm, that’s long if I do say so myself) Data Migrations can be complex depending what needs to be achieved. I remember using ScriptLogic to map drives depending on which subnet a user was on, that was way before DFS was available… Good times…

I’ve had my share of headaches when it comes to Data migrations. The biggest challenge is interoperability, when Target Resources keeps on using Source Resources until all Source Resources have been migrated. Sometimes it’s just not possible to migrate all Source Resources at once (what we affectionately call ‘big bang’). If data is being mutated by different departments/projects that aren’t migrated at the same time then interoperability is your only choice… Still tricky though…

Ok so here’s the scenario: Migrate Resources from one AD Forest to another (with a trust in place). I’ll take you through the Data part 🙂

The key component is to use SIDHistory. SIDHistory will help resolve whether you have access or not to a Source Resource. My favorite replication tool has to be robocopy! It wasn’t love at first sight, but once I figured out all the parameters, then there isn’t much you can’t accomplish with it!

For interoperability we usually redirect Target Resources to the Source. This way Data mutation can still be achieved without disturbing Production. In the mean time data is being synced to the Target Domain with ACLs intact! Why? We’ll get to that later… Or might as well get into it now… 🙂

Ok so ACL (Access Control List) is that list you get when you open up a file or folder security tab. The accounts are referred to as ACE (Access Control Entry). That’s where you’d grant/remove an account read/write/full/etc access to said file or folder. When using SIDHistory you’re token access will resolve correctly, but here’s where it gets tricky

I’ve copied Data with robocopy keeping security intact. When I opened a folder security tab I noticed the Target account name being displayed. That threw me off because I didn’t reacl the target resource yet.

Quick sidestep ReACL is a term I came across using Quest Active Directory Manager (now DELL). ReACL can be done by adding the Target Account (doubling the amount of ACEs) or doing a cleanup by first adding the Target account and removing the Source Account. You can also rollback if needed but that one is tricky, especially if SIDHistory has more than one entry.

But you wouldn’t know that by looking at the folder Security tab.

If you really want to find out who has access, SDDL will let you know. SDDL uses an object SID to grant or deny access. Thing is SDDL is hard to read hence the Security tab. So the first time I ReACLed a folder adding the Target Account I saw that the ACEs did double, but I only saw the Target Account. I expected to see SOURCE\ACCOUNT;TARGET\ACCOUNT instead I was seeing the TARGET\ACOUNT twice. Here’s where looking at SDDL will give you more insight… Suffice to say we’ll be doing this the PowerShell way… Oh come on! don’t act so surprised! 😛

So first let’s get the ACL of the folder you want to inspect (try this on your folder):

$acl = get-acl '\\162.198.1.129.\g$\GRP\DATA\DEPT-001-XYZ'

To find out who has access  type $acl.Access. This will give you a list of all ACEs in the ACL. This is the list you’d also see in Explorer security tab (advance mind you, I noticed that). Now for the fun part $acl.sddl… Tada!!!

$acl.Sddl

O:S-1-5-21-103234515-1370883554-928726630-1008G:S-1-5-21-103234515-1370883554-928726630-513D:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;0x1301bf;;;S-1-5-21-103234515-1370883554-928726630-4307)(A;OICI;0x1301bf;;;S-1-5-21-103234515-1370883554-928726630-4308)(A;OICI;0x1200a9;;;S-1-5-21-103234515-1370883554-928726630-4309)

Seems complicated, well yes it is, still it’s worth figuring out… Have a look at MSDN for more information.

The tell tale is the Domain SID, every Account begins with it. Looking at the Domain SID tells you who actually has access (or not) to said resource and which Domain that account belongs to.

The Domain SID for the current domain I’m inspecting is:
DomainSID : S-1-5-21-602145358-1453371165-789345543
You can get the Domain SID using Get-ADDomain cmdlet… 😉

I picked an ACE from the $acl.access list:

FileSystemRights : Modify, Synchronize
AccessControlType : Allow
IdentityReference : SOURCE\DEPT-001-XYZ-RXWR
IsInherited : False
InheritanceFlags : ContainerInherit, ObjectInherit
PropagationFlags : None

Let’s get some AD properties from this acount

Get-ADGroup -Identity DEPT-001-XYZ-RXWR -Server source.nl -Properties SID,SIDHistory
..
SamAccountName : DEPT-001-XYZ-RXWR
SID : S-1-5-21-602145358-1453371165-789345543-35829
SIDHistory : S-1-5-21-103234515-1370883554-928726630-4307

Here’s the sddl string once more:

O:S-1-5-21-103234515-1370883554-928726630-1008G:S-1-5-21-103234515-1370883554-928726630-513D:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;0x1301bf;;;S-1-5-21-103234515-1370883554-928726630-4307)(A;OICI;0x1301bf;;;S-1-5-21-103234515-1370883554-928726630-4308)(A;OICI;0x1200a9;;;S-1-5-21-103234515-1370883554-928726630-4309)

This group has access using SIDHistory!!!

Ok now what? Well in an ideal situation the data would have been ReACLed using the current SID instead of the SIDHistory. The reason for that is to cleanup your SIDHistory to avoid tokenbloat. Here’s an excellent blog by the dirteam discussing the perils of tokenbloat.

This only scratched the surface of what you could investigate! There aren’t many tools (Free) that can help. Ashley Mcglone has an excellent series on the matter definitely worth reading.

I’m currently doing a Data migration (surprise!) so I’ll be adding more tips/tricks/gotchas as the Data migration progresses so stay tuned!

Hope this will steer you in the right direction when it comes to figuring out who has access…
The rabbit hole goes deep…

Ttyl,

Urv

Get-NTFSAccess from the NTFSSecurity module

I’m lovin’ the NTFSSecurity module more and more!

In my first attempt I looked up the NTFS Access on folders that were explicit using Get-ChildItem2 -Recurse. In hindsight this is definitely a WET solution!

Turns out NTFSSecurity module has a cmdlet for getting NTFS Access aptly named:
Get-NTFSAccess!

So there’s no need to reinvent the wheel, think DRY!!!

The code then becomes quiet simple:

Get-ChildItem2 $Path -Recurse -Directory | Get-NTFSAccess -ExcludeInherited

That’s all there is to it! No muss no fuss!!!

Here’s how to get an overview of all the cmdlets in the module with syntax:

Get-Command -Module NTFSSecurity -CommandType Cmdlet -Syntax | Out-GridView

There’s even a Get-NTFSOrphanedAccess cmdlet! Talk about being spoiled!!!

Good watching out for the community raandree! Your code rocks!!!

Ttyl,

Urv

NTFS Rights on Folders exceeding Max_256 chars

As a PowerShell enthusiast you want to do everything in PowerShell, am I right guys? 😉

One of the things that you’ll run into eventually, is the dreaded Max_256 char aka Path too long error, when using Get- or Set-Acl or anything folder related for that matter. It’s one of the reasons why I always revert back to good ol’ icacls!

Sure, there are elaborate workarounds as substitute and you could use PathToLong utility, still…

Why can’t PowerShell just resolve paths exceeding 256 chars? (Pause for emphasis)

Well it turns out there’s a module that can help!  Enter NTFSSecurity

I found this lil’ gem on FaceBook, I know right? I’m just as surprised as you are! Don’t judge me… there’s a PowerShell group on FB… Yes I need a life…

[CmdletBinding()]
param(
  [Parameter(Mandatory=$true)]
  [string]$RootFolder
)

#Import NTFSSecurity to overcome 256 MAX_Path limitation
#You can find it here: https://ntfssecurity.codeplex.com/
#Place it in your PSModulePath of preference.
Import-Module NTFSSecurity
Function Read-ACL{
  param(
    [string]$Folder
  )

  try{
    $aclFolder = Get-NTFSAccess $Folder -excludeinherited -ErrorAction stop

    if ($aclFolder -ne $null){
      Write-Verbose "Explicit Permissions found on $Folder"

      $hshACEsFolder =[PSCustomObject]@{
        Path = ''
        ACE = ''
        ControlType = ''
        AccessRights = ''
      }

      foreach($ace in $aclFolder){
        if ($ace.isinherited -eq $false){
          $hshACEsFolder.Path = $ace.FullName
          $hshACEsFolder.ACE = $ace.account.accountname
          $hshACEsFolder.ControlType = $ace.AccessControlType
          $hshACEsFolder.AccessRights = $ace.AccessRights

          Write-Output $hshACEsFolder
        }
      }
    }
  }
  catch {
    Write-Warning "Cannot access Folder: $($Folder)"
  }
}

#region Main
try{
  $Subfolders = Get-ChildItem2 $RootFolder -recurse |
  Where-Object {
    $_.Attributes -eq 'Directory'
  } -ErrorAction stop
}
catch {
  Write-Warning "Access denied on $RootFolder"
}

Write-Verbose "SubFolders count: $($SubFolders.count)"

foreach ($SubFolder in $SubFolders) {
  Read-ACL $Subfolder.FullName
}
#endregion

I’m only interested in where the NTFS Rights are set explicitly (ExcludeInherited). It works!
I’ve been searching for something like this for quite some time now 🙂

As always be sure to test run first… Guess it’s time to update my NTFS scripts… Hehe…

Ttyl,

Urv