SeImpersonatePrivilege

 

NOTE - I wrote this up more than a year back and for some mysterious reasons forgot to post it! Much of what is written here applies to Vista UAC accounts as well.

QUESTION - Under Windows Server 2003, can a "limited user" impersonate an "administrator"?

ANSWER –  As you are aware, there are four impersonation levels, each of which indicates the degree to which one user can impersonate another – SecurityAnonymous, SecurityIdentification, SecurityImpersonation, and SecurityDelegation. A limited user on Windows Server 2003 (or UAC admin on vista) needs SE_IMPERSONATE_PRIVILEGE enabled in order to impersonate the context of an "administrator" at any level above "SecurityIdentification".

Consider this snippet of code executed in the context of a limited user (non-admin). An admin's token is first obtained and duplicated to create an impersonation token at security level "SecurityImpersonation". The limited user then attempts to impersonate the admin. If impersonation succeeds, then it tries some operation that requires admin privileges (In this case, creating a key under HKLM\Software\Microsoft with write access).  

void wmain ()

{

    HANDLE hPrivToken ;

    HANDLE hPrivTokenImperson ;

    if ( 0 == LogonUser( L"administrator", L"MyMachine", L"MyPassWord",

                         LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,

                         & hPrivToken ) )

    {

        wprintf( L"Failed to logon admin. Last Error = %d\n",

                 GetLastError() ) ;

        return ;

    }

    if ( 0 == DuplicateTokenEx( hPrivToken, TOKEN_QUERY | TOKEN_IMPERSONATE, NULL,

                                SecurityImpersonation, TokenImpersonation,

                    & hPrivTokenImperson ) )

    {

        wprintf( L"Failed to obtain impersonation token. Last Error = %d\n",

                 GetLastError() ) ;

        return ;

    }

    if ( 0 == SetThreadToken( NULL, hPrivTokenImperson ) )

    {

        wprintf( L"Failed to impersonate administrator. Last Error = %d\n",

                 GetLastError() ) ;

        return ;

    }

    //

    // Do something that requires admin privileges…………

    //

    if ( ERROR_SUCCESS != RegCreateKeyEx( HKEY_LOCAL_MACHINE,

                                          L"Software\\Microsoft\\RandomKey", 0, NULL,

                                          REG_OPTION_NON_VOLATILE, KEY_READ | KEY_WRITE,

                                          NULL, & hKey, & dwDisposition ) )

    {

        wprintf( L"RegCreateKeyEx FAILED. Last Error = %d\n",

                 GetLastError() ) ;

    }

    else

    {

        wprintf( L"RegCreateKeyEx SUCCEEDED.\n" ) ;

    }

    SetThreadToken( NULL, NULL ) ; // revert back

}

Under Windows XP, the limited user is successfully able to impersonate the admin at level SecurityImpersonation. However on Windows 2003 and Vista things are a bit different because of the security changes related to SE_IMPERSONATE_PRIVILEGE that I described above. Although the first call to SetThreadToken() succeeds, the impersonation is being sneakily carried out at level SecurityIdentification. As a result of which your privileged operation (writing to HKLM in this case) fails with an access-denied error. Sweet! On Windows Server 2003 and above, the ability to impersonate at SecurityImpersonation and above is given only to Network Service, Local Service, Local System and Administrators (On Vista you need to be running elevated as well to have SE_IMPERSONATE_PRIVILEGE enabled in the token).