Click here to Skip to main content
15,885,366 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am working on a project where I have to create a windows token for a given SID. The intention is to generate an elevated token for a standard user. I am aware of an undocumented function "NtCreateToken()" which could do that but I dont get through much workable examples to achieve it.

The following is the code written for that :

typedef NTSTATUS(__stdcall* NtCreateToken)(

PHANDLE TokenHandle,
ACCESS_MASK DesiredAccess,
TokenGeneratorTypes::POBJECT_ATTRIBUTES ObjectAttributes,
TOKEN_TYPE TokenType,
PLUID AuthenticationId,
PLARGE_INTEGER ExpirationTime,
PTOKEN_USER User,
PTOKEN_GROUPS Groups,
TokenGeneratorTypes::PTOKEN_PRIVILEGES Privileges,
PTOKEN_OWNER Owner,
PTOKEN_PRIMARY_GROUP PrimaryGroup,
PTOKEN_DEFAULT_DACL DefaultDacl,
PTOKEN_SOURCE TokenSource
);

LUID GetLuidOfPrivilege(LPCWSTR privilegeName)
{

  PLUID pluid = nullptr;
  LUID luid;
  LookupPrivilegeValue(nullptr, privilegeName, pluid);

  luid.LowPart = pluid->LowPart;
  luid.HighPart = pluid->HighPart;

  return luid;
}


PHANDLE GenerateElevatedToken(LPCWSTR sid)
{
HMODULE hModule = GetModuleHandle(TEXT("ntdll.dll"));
NtCreateToken CreateToken = nullptr;
PSID* psid = nullptr;
TOKEN_PRIMARY_GROUP pgroup;
TOKEN_USER user;
static TOKEN_SOURCE source = { {"User32 "} };
static TOKEN_DEFAULT_DACL tdd;
static TokenGeneratorTypes::_SID Administrators = { SID_REVISION,2,SECURITY_NT_AUTHORITY,{SECURITY_BUILTIN_DOMAIN_RID,DOMAIN_ALIAS_RID_ADMINS} };
static TOKEN_GROUPS groups = { 1,{{&Administrators,SE_GROUP_ENABLED | SE_GROUP_MANDATORY}} };
static SECURITY_QUALITY_OF_SERVICE sqos = {
            sizeof(sqos), SecurityImpersonation, SECURITY_DYNAMIC_TRACKING
};
PHANDLE tokenHandle = nullptr;

static TokenGeneratorTypes::OBJECT_ATTRIBUTES oa = {
    sizeof oa, 0, 0, 0, 0, &sqos
};

HANDLE currentToken;
TOKEN_STATISTICS tstats;
DWORD returnLength;

OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, ¤tToken);

GetTokenInformation(currentToken, TOKEN_INFORMATION_CLASS::TokenStatistics, &tstats, sizeof(tstats), &returnLength);

TokenGeneratorTypes::TOKEN_PRIVILEGES Privileges = {
            25, {
                { {GetLuidOfPrivilege(SE_INCREASE_QUOTA_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_SECURITY_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_TAKE_OWNERSHIP_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_LOAD_DRIVER_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_SYSTEM_PROFILE_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_SYSTEMTIME_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_PROF_SINGLE_PROCESS_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_INC_BASE_PRIORITY_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_CREATE_PAGEFILE_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_BACKUP_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_RESTORE_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_SHUTDOWN_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_DEBUG_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_SYSTEM_ENVIRONMENT_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_CHANGE_NOTIFY_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_REMOTE_SHUTDOWN_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_UNDOCK_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_MANAGE_VOLUME_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_IMPERSONATE_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_CREATE_GLOBAL_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_INC_WORKING_SET_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_TIME_ZONE_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_CREATE_SYMBOLIC_LINK_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_DELEGATE_SESSION_USER_IMPERSONATE_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT },
                { { GetLuidOfPrivilege(SE_TCB_NAME) }, SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT }

            } };

if (hModule != 0)
{
    CreateToken = (NtCreateToken)GetProcAddress(hModule, "NtCreateToken");

    if (CreateToken == 0)
    {
        return nullptr;
    }
}
else
{
    return nullptr;
}

ConvertStringSidToSidW(sid,psid);

pgroup = { psid };
user = { psid };

LUID sessionId = {1,0 };
PLUID psessionId = &sessionId;

CreateToken(tokenHandle, TOKEN_ALL_ACCESS, &oa, TokenPrimary,psessionId, &tstats.ExpirationTime, &user,
    &groups, (TokenGeneratorTypes::PTOKEN_PRIVILEGES) & Privileges, 0, &pgroup, &tdd, &source);

return tokenHandle;
}


The token generated from the above function is used to create a process in session id 1. The following is the code for the same :

wstring processName = _T("notepad.exe"); 
TCHAR* name = (wchar_t*)processName.c_str(); 
PROCESS_INFORMATION processInformation; STARTUPINFO startupInfo = GetStartupInfo(); 
ZeroMemory(&processInformation, sizeof(processInformation)); 
std::wstring sid = "....." //Some Valid SID.
PHANDLE tkn = GenerateElevatedToken(sid.c_str()); 
CreateProcessAsUser(tkn, nullptr, name, nullptr, 
nullptr, false, 0, nullptr, nullptr, &startupInfo,  &processInformation);



The isssue I am facing is that, the process simply starts and exits after a few seconds. I can provide more context (including for TokenGeneratorTypes and GetStartupInfo()) if required. Please point out the error with the above code.

What I have tried:

I have tried executing this program with the SeCreateTokenPrivilege enabled. However, still process simply exits.
Posted
Comments
Stefan_Lang 17-Jan-21 12:59pm    
I've never done anything like this, so I'm not posting a solution.

From a quick search, it looks like you have access to server system functionality, so that is something not many developers will have any experience with. The info I got for SeCreateTokenPrvilege only shows you have the right to create a token - not to create one with elevated rights.

This raises the question, why does it need elevated rights?

I suspect that you're calling functions that return with an error because the rights you have are not sufficient. Either that or there is simply an error in your code.

Either way, why don't you use a debugger to find out what is going wrong?

In any case, you should spend more effort into checking the results and errors of functions you call, specifically system functions that are not guranteed to always do what you want depending on various conditions.
JoesephMU 17-Jan-21 13:51pm    
Hi,
I am developing this on Visual Studio, so I assume you are mentioning its in-built debugger. The problem with debuging is that, a) I am executing the process in a VM (but developing in the host) and b) SeCreateTokenPrivilege is available only with lsass.exe. So I have developed a curated program which acquires the token from lsass.exe and then executes the program written above. To acheive this both the parent and child process will need to run in an elevated context. I am not aware how to intercept into these programs simultaneously with a debugger in such a situation (If you could provide pointers on that, It would be helpful).
Secondly, the reason I am creating a token with elevated rights is because my project requires me to create an elevated token for a standard user so that he/she could perform privileged operations (this is kind of similar to what corporate privilege managers do, but not exactly the same).
Stefan_Lang 17-Jan-21 14:25pm    
As for debugging, I've developped embedded progams and was able to debug them right from my desktop PC. So I assume that something like that should be possible on a VM too. But I've never done that myself. Also that was 15 years ago, and I wasn't the one who set up the debugger. But I suspect that if it is possible at all, there should be useful info at Microsoft. Otherwise you should consider adding logging functionality to help you find out what your program is doing.

As for the rest, that's entirely outside my experience.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900