'File Security permissions and inheritance writing file during installation

I have some data that I want to use from a process which will run as NT_AUTHORITY\SYSTEM. The data I want to save I want to hide from regular users. So, I create a directory like this during installation during the InstallExecute sequence (it is deferred and not impersonating, so should be running as SYSTEM):

static string CreateProtectedDirectory(string name)
{
    string programData = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);

    var blah = Path.Combine(programData, "Blah");
    var blahInfo = new DirectoryInfo(blah);
    if (!blahInfo.Exists)
        blahInfo.Create();

    var finalPathInfo = new DirectoryInfo(Path.Combine(blah, name));
    
    if (!finalPathInfo.Exists)
    {
        // create with 
        DirectorySecurity ds = new DirectorySecurity();
        var administratorsSID = new SecurityIdentifier(WellKnownSidType.BuiltinAdministratorsSid, null);
        var systemSID = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null);

        var rule1 = new FileSystemAccessRule(administratorsSID, FileSystemRights.FullControl, AccessControlType.Allow);
        var rule2 = new FileSystemAccessRule(systemSID, FileSystemRights.FullControl, AccessControlType.Allow);
        ds.AddAccessRule(rule1);
        ds.AddAccessRule(rule2);
        ds.SetAccessRuleProtection(true, false);
        finalPathInfo.Create(ds);
    }
    return finalPathInfo.ToString();
}

After creating the directory, I write data to it, like this:

var protectedPath = CreateProtectedDirectory("blah2"); // c:\programdata\blah\blah2 where blah2 is protected
var filename = Path.Combine(protectedPath, "blahdata.dat");

var bytes = Encoding.ASCII.GetBytes("ABC123xyz");
File.WriteAllBytes(filename, bytes);

My understanding is that when I create c:\ProgramData\blah directory, that it is readable and writeable from anyone because without a security descriptor when creating it, it just inherits from c:\ProgramData. So, when I create c:\ProgramData\blah\blah2, I specifically set security on it.

When I go to PowerShell and try to view c:\ProgramData\blah\blah2 directory it does not allow me unless I elevate. That all makes sense to me. If I run an elevated PowerShell and switch to that directory and do a dir on the contents, I can see the 'blahdata.dat' file. I can even delete it. However, if I try to copy it or do a Get-Content on the file, I get a security permissions error.

That is surprising to me. Since I have permissions for the blah2 directory, I thought I would have full permissions for the blahdata.dat file within it. But, I do not. It is strange to me that I can delete the file, but not copy or view contents (obviously, copying needs to view contents). So, for some reason, I do not have read permissions on that file.

I killed explorer and re-started it elevated, trying to get more details on the file. It's not clear that it has an owner. Maybe the owner is SYSTEM or ???

I have one other head scratching part. I have basically the same code running in a Service which is running as the LocalSystem. Files created from that service I can view in an elevated process whereas the ones created during the InstallExecute sequence in the installer I cannot view. I have read somewhere that services have a service account associated with files that they create. IDK if that's true or if it makes a difference on who the owner is.

Is there a simple explanation for why the file can be deleted but not read when it is created like in the code above.

===========================

Further info on permissions. When file created during install, file permissions appear like:

Owner  : NT AUTHORITY\SYSTEM
Group  : NT AUTHORITY\SYSTEM
Access : OWNER RIGHTS Allow  ReadPermissions
         NT AUTHORITY\SYSTEM Allow  FullControl
         NT SERVICE\msiserver Allow  FullControl
Audit  :
Sddl   : O:SYG:SYD:(A;;RC;;;OW)(A;;FA;;;SY)(A;;FA;;;S-1-5-80-685333868-2237257676-1431965530-1907094206-2438021966)

When same basic code run on a process running as SYSTEM, permissions are:

Owner  : BUILTIN\Administrators
Group  : NT AUTHORITY\SYSTEM
Access : NT AUTHORITY\SYSTEM Allow  FullControl
         BUILTIN\Administrators Allow  ReadAndExecute, Synchronize
Audit  :
Sddl   : O:BAG:SYD:(A;;FA;;;SY)(A;;0x1200a9;;;BA)

You can see when created running under the installer, the owner is the SYSTEM account (and the msiserver account has access). When running under a system process, the owner is the Administrators group.

For the permissions of the directory that the file is under, the permissions for the directory created under the installer are:

Owner  : NT AUTHORITY\SYSTEM
Group  : NT AUTHORITY\SYSTEM
Access : NT AUTHORITY\SYSTEM Allow  FullControl
         BUILTIN\Administrators Allow  FullControl
Audit  :
Sddl   : O:SYG:SYD:P(A;;FA;;;SY)(A;;FA;;;BA)

Permissions for the directory created when running as a SYSTEM process:

Owner  : BUILTIN\Administrators
Group  : BUILTIN\Administrators
Access : NT AUTHORITY\SYSTEM Allow  FullControl
         BUILTIN\Administrators Allow  FullControl
Audit  :
Sddl   : O:BAG:BAD:P(A;;FA;;;SY)(A;;FA;;;BA)


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source