+++ title = “Windows permissions cheat-sheet” date = 2022-10-21 slug = “windows-permissions-cheat-sheet”

[taxonomies] tags = [ “windows” ]

[extra] keywords = [ “windows”, “permissions”, “icacls”, “net share” ] description = “Building ACLs for a specific directory structure on Windows” +++

I wouldn’t use Windows if I wouldn’t be forced to use it. Unfortunately, trying to evade it is like trying to evade snails after the rain – whatever you do, snails ain’t interested in it. So the best course of action is to embrace it: keep your friends close, but your enemies closer, as they say.

One recent problem that I had was to build a specific Access Control List for a directory structure on a network share. I’m really biased when it comes to Windows; I really dislike its GUI-oriented configuration, mostly because I often don’t understand it. Sometimes in order to decode the actual configuration model is nearly damn impossible when it’s encrypted by the GUI. It’s a lesser problem for an old Windows user who remembers that some particular dialog box is from Windows 3.11, another is from Windows95, but another one is new – it was introduced in the shiny Windows 10, but before Microsoft switched the GUI toolkits again, so we can expect it to go away in Windows 11. I don’t subscribe to such problems. I’m also getting salty, so I’ll leave it there. xxx

Anyway, I wanted to build a directory structure like this:

This would be a directory that nobody else should have access to. This directory should have subdirectories in it. Each of the directories should have their own ACL lists specifying what user is allowed to access a specific directory. So, for example:

This should be only accessible by Bob.

And this should be only accessible by Alice. Bob shouldn’t be able to enter it.

At the same time, both Bob nor Alice shouldn’t be able to access D:.

Such configuration is possible to be created in the console by using two commands: net share and icacls.

Create a network share

Creation of a network share is done by the net share command. Running it without the arguments will list all the shares that are configured on your machine:

PS$ net share 

Share name   Resource                        Remark

-------------------------------------------------------------------------------
C$           C:\                             Default share
D$           D:\                             Default share
E$           E:\                             Default share
IPC$                                         Remote IPC
ADMIN$       C:\WINDOWS                      Remote Admin
share        d:\share
The command completed successfully.

Ignore the shares ending with the $ character. I bet even MVPs don’t understand why they’re really there. If you’re curious, then you can read about them here.

In order to create a share, just run the net share command like this:

PS$ net share sharename=D:\directory /grant:everyone,read

The sharename is the name of your share, which will be later displayed to the user which is connecting to your machine via CIFS. The d:\directory is – as expected – the directory which you would like to share. The /grant option is interesting, becuase it’s the first layer of user permission setting. Here we allow everyone to access the share; you can limit what users can access it right here, but also you can specify the “everyone” rule, and configure the ACL list later by using icacls.

Viewing ACLs

It seems that nobody knows why the default ACL editor, icacls, is named this way. However, I have some suggestions:

On Windows there is also a deprecated command called cacls, which might mean “control ACLs”. After checking out its help page I’ve noticed that the main difference between cacls and icacls is that cacls is missing options related to ACL inheritance, so actually icacls could also mean something like this:

So anyway, by using icacls we can build up a list with usernames and bind some permissions to those usernames. This will be the second layer of security, so if you have any permission-denied problems during your adventues, please first re-check if those problems aren’t really inside the first layer (the net share layer of permission setting, described above).

PS D:\SHARE$ icacls .
. BUILTIN\Administrators:(I)(F)
  BUILTIN\Administrators:(I)(OI)(CI)(IO)(F)
  NT AUTHORITY\SYSTEM:(I)(F)
  NT AUTHORITY\SYSTEM:(I)(OI)(CI)(IO)(F)
  NT AUTHORITY\Authenticated Users:(I)(M)
  NT AUTHORITY\Authenticated Users:(I)(OI)(CI)(IO)(M)
  BUILTIN\Users:(I)(RX)
  BUILTIN\Users:(I)(OI)(CI)(IO)(GR,GE)

Successfully processed 1 files; Failed processing 0 files

First thing you need to realize is that this list doesn’t have a proof strong enough to judge that the icacls designer was using LSD. It’s not enough, though it’s damn close.

Each line is one rule. These strange keywords between ( and ) are actually flags, and they describe the rule itself. There are 3 classes of flags.

Allow/deny flags

There are just two flags here. The (DENY) flag, if exists, means that this rule describes a DENY rule instead of ALLOW rule. Example:

There is also the (N) flag, which denies access completely for this particular user.

Inheritance control flags

There is just one. It’s either specified, or missing:

Those flags are most commonly used in combos:

Permission control flags

These flags actually describe the user permissions: what users can do.

Building the ACL

More of less that’s it, we can proceed with building our list or ACEs.

In my particular case, the first layer of security related to the net share command was to allow everyone to the share. The first layer contains a pretty primitive tools for specifying access, so best would be to completely bypass it by allowing everyone to enter, and just rely on ACLs to filter people out.

First step is to disable access to everyone except myself to the root directory of the share. It’s possible to do it by disabling inheritance on the D:\SHARE directory and by adding an explicit rule to allow access from my account:

PS$ icacls d:\share /grant "antek:(CI)(OI)F" /inheritance:r

This will effectively mark the d:\share directory as impossible to read by anyone that is not me.

Next, create two directories for Bob and Alice:

PS$ mkdir d:\share\alice
PS$ mkdir d:\share\bob

and set the necessary read and traverse rights:

PS$ icacls d:\share\alice /grant "alice:(CI)(OI)RX"
PS$ icacls d:\share\bob /grant "bob:(CI)(OI)RX"

And that’s really it. Bob can access the share by entering directly to the \\antek\share\bob share, and Alice can enter directly the \\antek\share\alice directory. Bob can’t enter Alice’s directory, and Alice can’t enter Bob’s directory. While the owner of the machine can enter all directories.

The silly thing is that it’s harder to configure that by using the GUI, and it’s pretty clear how ACLs work when spending some time on the command line docs. One interesting thing for future research would be to abuse the ACL files generated by the /save command. Those files can be “restored” by using the /restore command. Is it possible to create ACLs that would be impossible to build using the GUI or icacls command? The default order of rule evaluation is:

but is this order enforced by the ACL subsystem, or just by the tools used to build ACLs?

Maybe it’s worth leaving some questions unaswered!