3

I'm trying to write a backup and recovery tool. I'm running my code on a WinPE CD (http://en.wikipedia.org/wiki/Windows_Preinstallation_Environment). I'm trying to read the entire C: partition and write it to the network. Just like the tar command, but windows specific. I have everything working except for setting the file owner. Windows seems to be really intolerant to files being owned by unknown SIDs. Since I'm running in WinPE, most of the users defined on C: aren't in the local user database.

Here are some of the functions I've tried:

  • SetFileSecurity (returns 1307)
  • SetSecurityInfo (returns 1307)
  • SetNamedSecurityInfo (returns 1307)
  • BackupWrite (returns 1307)
  • NtSetSecurityObject (returns 0xC000005A)

I know this can be done. SetACL (http://helgeklein.com/setacl/) is able to do it.

So, the question. How do I set the owner of a file to a non-existing user/SID? Any help is greatly appreciated!

Here's a sample of the code I've tried:

#define _WIN32_WINNT 0x0500

#include <windows.h>
#include <sddl.h>
#include <aclapi.h>
#include <tchar.h>

INT _tmain(){

    PSECURITY_DESCRIPTOR psdOwner = LocalAlloc(LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH);

    if (InitializeSecurityDescriptor(psdOwner,SECURITY_DESCRIPTOR_REVISION)){

        PSID psOwner = (PSID)0;

        if (ConvertStringSidToSid(TEXT("S-1-5-21-3626571138-2175758104-1447827851-1013"),&psOwner)){

            if (SetSecurityDescriptorOwner(psdOwner,psOwner,FALSE)){

                DWORD dwError = SetNamedSecurityInfo(TEXT("test.txt"),SE_FILE_OBJECT,OWNER_SECURITY_INFORMATION,psdOwner,NULL,NULL,NULL);

                if (dwError == ERROR_SUCCESS){

                    _tprintf(TEXT("Success!\n"));

                }else{

                    _tprintf(TEXT("Failed to set owner: %u\n"),dwError);

                }

            }else{

                _tprintf(TEXT("Failed to set owner into SD: %u\n"),GetLastError());

            }

        }else{

            _tprintf(TEXT("Failed to covnert Sid string to Sid: %u\n"),GetLastError());

        }

        if (psOwner) LocalFree(psOwner);

    }else{

        _tprintf(TEXT("Failed to initialize SD: %u\n"),GetLastError());

    }

    if (psdOwner) LocalFree(psdOwner);

    return 0;

}
Daniel Knueven
  • 222
  • 1
  • 11

1 Answers1

3

Turns out you need SE_RESTORE_NAME token privilege. You can adjust your process token with the following:

BOOL TakeSecurityPriv(LPCTSTR szPriv){

    BOOL bReturn = FALSE;

    HANDLE hProcToken = (HANDLE)0;

    if (OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,&hProcToken)){

        TOKEN_PRIVILEGES tpTokPriv;

        if (LookupPrivilegeValue(NULL,szPriv,&tpTokPriv.Privileges[0].Luid)){

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

            if (AdjustTokenPrivileges(hProcToken,FALSE,&tpTokPriv,0,NULL,0)){

                bReturn = TRUE;

            }

        }

    }

    return bReturn;

}

Then you can add the following to the beginning of main in my example:

if (TakeSecurityPriv(SE_RESTORE_NAME)){

That gets rid of the 1307 error. Unfortunately there is another bug in my example because the owner isn't set to the correct SID. However, when I switch back to BackupRead/BackupWrite I won't have to create a SID or SECURITY_DESCRIPTOR. I've pondered over what could be the issue for a while now with no luck. Perhaps someone else could answer that part.

Daniel Knueven
  • 222
  • 1
  • 11