3

I have the following scenario where I (admin) applied the (DE,W) deny permissions to the following folder test_folder for test_user who already has inherited modify permissions from parent folder:

B:\>icacls test_folder
test_folder     test_user:(I)(OI)(CI)(M)
                admin:(I)(OI)(CI)(M)

B:\>icacls test_folder /deny test_user:(DE,W)

B:\>icacls test_folder
test_folder     test_user:(DENY)(W,D)
                test_user:(I)(OI)(CI)(M)
                admin:(I)(OI)(CI)(M)

The end result I would expected is test_user being able to have read/execute access to test_folder without being able to delete/rename the folder and add folders/files to it.

However, the result was test_folder not being visible to test_user at all. The test_folder is still visible to me (admin).

While I deny only DE however:

B:\>icacls test_folder
test_folder     test_user:(I)(OI)(CI)(M)
                admin:(I)(OI)(CI)(M)

B:\>icacls test_folder /deny test_user:(DE)

B:\>icacls test_folder
test_folder     test_user:(DENY)(D)
                test_user:(I)(OI)(CI)(M)
                admin:(I)(OI)(CI)(M)

test_user was able to see test_folder. So somehow W is causing an issue.

Any idea why this is happening?

kiwidude89
  • 55
  • 2

1 Answers1

3

Both (W) and (M) are macros; they expand to multiple actual access flags.

In particular, (W) like FILE_GENERIC_WRITE grants these rights:

  • "Synchronize" (S)
  • "Write data" (WD)
  • "Append data" (AD)
  • "Write EAs" (WEA)
  • "Write attributes" (WA)

The "Synchronize" right is rather obscure (and not even shown in the GUI), but it's one that is necessary for practically any kind of useful access to the file – it's needed for both reading and writing, and is therefore included in both "(R)" and "(W)" sets.

So when you deny (W) access, you also end up denying the "Synchronize" right, which is required for many programs to operate on the file at all.

Microsoft's file access documentation also notes this:

Note that you cannot use an access-denied ACE to deny only GENERIC_READ or only GENERIC_WRITE access to a file. This is because for file objects, the generic mappings for both GENERIC_READ or GENERIC_WRITE include the SYNCHRONIZE access right. If an ACE denies GENERIC_WRITE access to a trustee, and the trustee requests GENERIC_READ access, the request will fail because the request implicitly includes SYNCHRONIZE access which is implicitly denied by the ACE, and vice versa. Instead of using access-denied ACEs, use access-allowed ACEs to explicitly allow the permitted access rights.

If you must use a "deny" ACE, you'll need to individually deny the four other rights that (W) includes, i.e. (WD,AD,WEA,WA), but note that such an ACE tends to confuse ACL editing tools a little. (Many will still collapse it to a generic "Write" and you won't be able to tell the difference.)

The older cacls tool is particularly useful here, as it doesn't know many new macros/aliases and as a result shows you all the individual access rights. Alternatively, PowerShell's Get-Acl is normally too fine-grained to be useful, but in this case it's fine-grained just enough to be useful:

PS C:\> icacls test /grant "user:(OI)(CI)(R,X)"
PS C:\> icacls test /deny "user:(OI)(CI)(W)"

PS C:\> Get-Acl test | fl
Access : FOO\user Deny  Write, Synchronize
         NT AUTHORITY\SYSTEM Allow  FullControl
         BUILTIN\Administrators Allow  FullControl
         FOO\user Allow  ReadAndExecute, Synchronize

PS C:\> cacls test  
C:\test FOO\user (OI)(CI)(DENY)(special access:)
                                  SYNCHRONIZE
                                  FILE_WRITE_DATA
                                  FILE_APPEND_DATA
                                  FILE_WRITE_EA
                                  FILE_WRITE_ATTRIBUTES
        FOO\user:(OI)(CI)(DENY)(special access:)
                                  DELETE
                                  SYNCHRONIZE
        BUILTIN\Administrators:(OI)(CI)F
        NT AUTHORITY\SYSTEM:(OI)(CI)F
u1686_grawity
  • 426,297
  • 64
  • 894
  • 966
  • gotcha. So it seems denying `(R)` or `(W)` is a bad idea as it messes with the `(S)` which is crucial. Will try to restructure, thanks for the tip! – kiwidude89 Aug 05 '22 at 14:18
  • 2
    Many (most?) applications don't use "synchronize", but *because it's included in the GENERIC_READ and GENERIC_WRITE sets* they request it anyway when they request generic read or write. – user253751 Aug 05 '22 at 14:25