Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delete folder for which every API call fails with ERROR_ACCESS_DENIED

I have created a folder with CreateDirectoryW to which I haven't got access. I used nullptr as a security descriptor, but for some reason it didn't copy the parent folder's ACLs, but instead made the folder inaccessible.

I can't view or change the owner. takeown, icacls, SetNamedSecurityInfoW, all from elevated processes or command prompts, fail with ERROR_ACCESS_DENIED.

Do I have any chance of deleting this folder in Windows (Shell or C++) before trying a Linux live CD which hopefully doesn't care about the ACLs?

like image 504
Felix Dombek Avatar asked Dec 21 '25 03:12

Felix Dombek


2 Answers

You just need to enable backup (or restore) privilege:

#include <Windows.h>

#include <stdio.h>

int wmain(int argc, wchar_t ** argv)
{
    // argv[1] must contain the directory to remove

    HANDLE hToken;
    struct 
    {    
        DWORD PrivilegeCount;
        LUID_AND_ATTRIBUTES Privileges[1];    
    } tkp;

    if (OpenProcessToken(GetCurrentProcess(), 
        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) 
    {
        LookupPrivilegeValue(NULL, SE_BACKUP_NAME, &tkp.Privileges[0].Luid);

        tkp.PrivilegeCount = 1;
        tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

        if (!AdjustTokenPrivileges(hToken, FALSE, 
            (PTOKEN_PRIVILEGES)&tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0))
        {
            printf("AdjustTokenPrivileges: %u\n", GetLastError());
            return 1;
        }

        if (GetLastError() != ERROR_SUCCESS)
        {
            // This happens if you don't have the privilege
            printf("AdjustTokenPrivileges: %u\n", GetLastError());
            return 1;
        }

        CloseHandle(hToken);
    }

    if (!RemoveDirectory(argv[1]))
    {
        printf("RemoveDirectory: %u\n", GetLastError());
        return 1;
    }

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

Note that in the interests of conciseness, some error handling has been omitted. Also note that AdjustTokenPrivileges() is one of the few special cases where calling GetLastError() is meaningful even though the call succeeded; it will return ERROR_SUCCESS or ERROR_NOT_ALL_ASSIGNED depending on whether you actually have all of the privileges you were attempting to enable.

This is a fairly general solution for bypassing security permissions on files. It works for most API calls, although in some cases (most notably CreateFile) you must provide a special flag in order to make use of backup privilege. As well as deleting files or removing directories that you don't have permission to, you can change attributes, change permissions, and even assign ownership to somebody else, which is not otherwise permitted.

like image 116
Harry Johnston Avatar answered Dec 22 '25 17:12

Harry Johnston


assume that file not open with incompatible to delete share flags and no section on file.

for delete file enough 2 things - we have FILE_DELETE_CHILD on parent folder. and file is not read only. in this case call ZwDeleteFile (but not DeleteFile or RemoveDirectory - both this api will fail if file have empty DACL) is enough. in case file have read-only attribute - ZwDeleteFile fail with code STATUS_CANNOT_DELETE. in this case we need first remove read only. for this need open file with FILE_WRITE_ATTRIBUTES access. we can do this if we have SE_RESTORE_PRIVILEGE and set FILE_OPEN_FOR_BACKUP_INTENT option in call to ZwOpenFile. so code for delete file can be next:

NTSTATUS DeleteEx(POBJECT_ATTRIBUTES poa)
{
    NTSTATUS status = ZwDeleteFile(poa);

    if (status == STATUS_CANNOT_DELETE)
    {
        BOOLEAN b;
        RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &b);
        HANDLE hFile;

        IO_STATUS_BLOCK iosb;
        if (0 <= (status = NtOpenFile(&hFile, FILE_WRITE_ATTRIBUTES, poa, &iosb, FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT)))
        {
            static FILE_BASIC_INFORMATION fbi = {{},{},{},{}, FILE_ATTRIBUTE_NORMAL};
            status = ZwSetInformationFile(hFile, &iosb, &fbi, sizeof(fbi), FileBasicInformation);
            NtClose(hFile);

            if (0 <= status)
            {
                status = ZwDeleteFile(poa);
            }
        }
    }

    return status;
}
like image 20
RbMm Avatar answered Dec 22 '25 17:12

RbMm



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!