1

I'm trying to modify Windows access rights to a file in a way that only the owner (not even other Administrators) can access the file. Somewhat the equivalent of unix chmod 700 file.

I've played with denying rights to the general group (EVERYONE, ADMINISTRATORS) and granting them to the current user, but the current user always also loses the rights.

I tried to change the order (eas[0], eas[1]) and stuff, but without success.

Ideas anyone?

    EXPLICIT_ACCESSA ea= { 0, }, eas[5]= { { 0, }, };
    PACL pacl= 0;

    ea.grfAccessPermissions = GENERIC_ALL;
    ea.grfAccessMode = DENY_ACCESS ;
    ea.grfInheritance = NO_INHERITANCE;
    ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
    ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea.Trustee.ptstrName = "EVERYONE";
    eas[0]= ea;


    ea.grfAccessPermissions = GENERIC_ALL;
    ea.grfAccessMode = GRANT_ACCESS ;
    ea.grfInheritance = NO_INHERITANCE;
    ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
    ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
    ea.Trustee.ptstrName = "CURRENT_USER";
    eas[1]= ea;

    rc= SetEntriesInAcl(2, &eas[0], NULL, &pacl);

    rc= SetNamedSecurityInfoA((LPSTR)filename, SE_FILE_OBJECT,
                                    DACL_SECURITY_INFORMATION,
                                    NULL, NULL, pacl, NULL);
Anachronism
  • 408
  • 3
  • 10
  • Can't the admin just take ownership? – David Heffernan Feb 09 '17 at 19:28
  • any who have `SE_TAKE_OWNERSHIP_PRIVILEGE` can do this. admin usually (by default) have this. but from UI this (take ownership) need do explicity – RbMm Feb 09 '17 at 19:33
  • 2
    Deny overrides permit, so if you have a "deny all" then no one can access it at all. – Jonathan Potter Feb 09 '17 at 20:44
  • @all. Yes, admin can take ownership. But I started doing this, and then I couldn't get it to work the way I wanted and it sort of turned into a research project, even if it has little practical additional security. – Anachronism Feb 10 '17 at 09:41

3 Answers3

4

In most cases, deny entries take precedent over allow entries. Since access is denied by default, you don't need the deny entry, however you will need to disable inherited permissions. You can do this by using the PROTECTED_DACL_SECURITY_INFORMATION flag.

#include <Windows.h>
#include <Aclapi.h>

#include <stdio.h>

int main(int argc, char ** argv)
{
    EXPLICIT_ACCESS eas[1];
    PACL pacl = 0;
    DWORD rc;

    eas[0].grfAccessPermissions = GENERIC_ALL;
    eas[0].grfAccessMode = GRANT_ACCESS;
    eas[0].grfInheritance = NO_INHERITANCE;
    eas[0].Trustee.TrusteeForm = TRUSTEE_IS_NAME;
    eas[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    eas[0].Trustee.ptstrName = L"CURRENT_USER";

    rc = SetEntriesInAcl(1, &eas[0], NULL, &pacl);
    if (rc != ERROR_SUCCESS)
    {
        printf("SetEntriesInAcl: %u\n", rc);
        return 1;
    }

    rc = SetNamedSecurityInfo(L"C:\\working\\test.txt", SE_FILE_OBJECT, 
             DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION, 
             NULL, NULL, pacl, NULL);
    if (rc != ERROR_SUCCESS)
    {
        printf("SetNamedSecurityInfo: %u\n", rc);
        return 1;
    }

    printf("OK!\n");
    return 0;
}

Note that an administrator can always reset the permissions in order to gain access to the file. If you really need to protect the data against other administrators you'll have to encrypt it. (And hope nobody installs a keylogger to steal your encryption password.)

Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
  • I will try your code but I think I've tried this already. The problem was, that without the deny, the inhertited access, administrators get access through inheritance from the enclosing folder. (I know that admins can reset the flags by taking ownership.) – Anachronism Feb 10 '17 at 09:25
  • Ah, I see this is doing what I expected (probably via the extra flag). Missed your initial comment about disabling "inheritance", which was my essential problem I guess. Thanks +1 and check. – Anachronism Feb 10 '17 at 09:33
1

While technically possible, it doesn't buy you much in the way of securing an object. A local administrator may not immediately be able to access a file, given a DACL with appropriate entries, but they can always take ownership of any object in the system. This grants them full control over the object, and they can manipulate its DACL and SACL.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • I know but it still a small extra layer of security (and at some point it turned into a research project, because I couldn't get it to work the way I wanted, even if there's little practical benefit). – Anachronism Feb 10 '17 at 09:36
  • @Anachronism: There is no extra layer of security, however small. It may take an additional step to access an object for a local administrator, but that's it. In case you are looking for a good introduction into this topic, see [Permissions: A Primer, or: DACL, SACL, Owner, SID and ACE Explained](https://helgeklein.com/blog/2009/03/permissions-a-primer-or-dacl-sacl-owner-sid-and-ace-explained/). It will teach you everything you need to know to understand, why [Harry Johnston's answer](http://stackoverflow.com/a/42148843/1889329) works. – IInspectable Feb 10 '17 at 09:51
  • @ll. Acutally I think there is. If a malware isn't aware of the extra necessary steps (taking ownership), it might just fail. Or if another person hasn't enough time. It's slim, marginal, but it's not nothing. And as I said, it turned in to a bit of a research project anyway. – Anachronism Feb 10 '17 at 12:17
1

formally you need next code

DWORD demo(PCWSTR filename)
{
    EXPLICIT_ACCESS ea= { 
        GENERIC_ALL, 
        GRANT_ACCESS, 
        NO_INHERITANCE, 
        { 0, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_NAME, TRUSTEE_IS_USER, L"CURRENT_USER"}
    };
    PACL pacl;

    DWORD err = SetEntriesInAcl(1, &ea, NULL, &pacl);

    if (!err)
    {
        err = ERROR_GEN_FAILURE;

        if (pacl->AceCount == 1)
        {
            union {
                PVOID pvAce;
                PACE_HEADER Header;
                PACCESS_ALLOWED_ACE pAce;
            };

            if (GetAce(pacl, 0, &pvAce) && Header->AceType == ACCESS_ALLOWED_ACE_TYPE)
            {
                HANDLE hFile = CreateFile(filename, WRITE_DAC|WRITE_OWNER, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);

                if (hFile != INVALID_HANDLE_VALUE)
                {
                    SECURITY_DESCRIPTOR sd;
                    InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
                    SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE);
                    SetSecurityDescriptorOwner(&sd, &pAce->SidStart, FALSE);
                    SetSecurityDescriptorControl(&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED);

                    err = SetKernelObjectSecurity(hFile, DACL_SECURITY_INFORMATION|OWNER_SECURITY_INFORMATION, &sd)
                        ? NOERROR : GetLastError();

                    CloseHandle(hFile);
                }
                else
                {
                    err = GetLastError();
                }
            }
        }

        LocalFree(pacl);
    }

    return err;
}

note line

SetSecurityDescriptorControl(&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED);

with this code DACL for file will be have only one entry - GENERIC_ALL for current user. and all what explicitly not allowed in DACL - denied. but of course if user have SE_TAKE_OWNERSHIP_PRIVILEGE privilege - you can open file with WRITE_OWNER access and set self as owner. after this you can open file with WRITE_DAC and change DACL


as noted @Harry Johnston code can be and shorter if use SetNamedSecurityInfo

DWORD demo(PCWSTR filename)
{
    EXPLICIT_ACCESS ea= { 
        GENERIC_ALL, 
        GRANT_ACCESS, 
        NO_INHERITANCE, 
        { 0, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_NAME, TRUSTEE_IS_USER, L"CURRENT_USER"}
    };
    PACL pacl;

    DWORD err = SetEntriesInAcl(1, &ea, NULL, &pacl);

    if (!err)
    {
        err = ERROR_GEN_FAILURE;

        if (pacl->AceCount == 1)
        {
            union {
                PVOID pvAce;
                PACE_HEADER Header;
                PACCESS_ALLOWED_ACE pAce;
            };

            if (GetAce(pacl, 0, &pvAce) && Header->AceType == ACCESS_ALLOWED_ACE_TYPE)
            {
                err = SetNamedSecurityInfo((PWSTR)filename, SE_FILE_OBJECT, 
                    DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION |PROTECTED_DACL_SECURITY_INFORMATION, 
                    &pAce->SidStart, NULL, pacl, NULL);
            }
        }

        LocalFree(pacl);
    }

    return err;
}
RbMm
  • 31,280
  • 3
  • 35
  • 56