Home > database >  SetTokenInformation fails with 24, but the length is correct
SetTokenInformation fails with 24, but the length is correct

Time:03-17

I'm trying to create a elevated SYSTEM token, but the code below fails:

#include <windows.h>
#include <stdio.h>

BOOL Elevate()
{
    PSID pSID = NULL;
    HANDLE hToken = NULL, hToken2 = NULL;
    SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
    {
        fprintf(stderr, "OpenProcessToken(): %d\n", GetLastError());
        goto done;
    }

    if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hToken2))
    {
        fprintf(stderr, "DuplicateTokenEx(): %d\n", GetLastError());
        goto done;
    }

    if (!AllocateAndInitializeSid(
        &NtAuthority,
        1,
        SECURITY_MANDATORY_SYSTEM_RID,
        0,
        0, 0, 0, 0, 0, 0,
        &pSID))
    {
        fprintf(stderr, "AllocateAndInitializeSid(): %d\n", GetLastError());
        goto done;
    }

    if (!SetTokenInformation(hToken2, TokenIntegrityLevel, &pSID, sizeof(pSID)))
    {
        fprintf(stderr, "SetTokenInformation(): %d\n", GetLastError());
        goto done;
    }

done:
    if (pSID)
    {
        FreeSid(pSID);
        pSID = NULL;
    }

    CloseHandle(hToken);
    CloseHandle(hToken2);

    return TRUE;
}

int main(int argc, char** argv)
{
    Elevate();
}

It fails on SetTokenInformation, and the error code is 24: ERROR_BAD_LENGTH. Does anyone know what's wrong?

EDIT

Remy Lebeau was right, and I found an example here: https://wiki.sei.cmu.edu/confluence/display/c/WIN02-C. Restrict privileges when spawning child processes

CodePudding user response:

Per the TOKEN_INFORMATION_CLASS documentation

TokenIntegrityLevel
The buffer receives a TOKEN_MANDATORY_LABEL structure that specifies the token's integrity level.

Where TOKEN_MANDATORY_LABEL is defined as:

typedef struct _SID_AND_ATTRIBUTES {
#if ...
  PISID Sid;
#else
  PSID  Sid;
#endif
  DWORD Attributes;
} SID_AND_ATTRIBUTES, *PSID_AND_ATTRIBUTES;

typedef struct _TOKEN_MANDATORY_LABEL {
  SID_AND_ATTRIBUTES Label;
} TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL;

So, you need to give SetTokenInformation() a pointer to a TOKEN_MANDATORY_LABEL, not a pointer to a SID, eg:

#include <windows.h>
#include <stdio.h>

BOOL Elevate()
{
    TOKEN_MANDATORY_LABEL tml = {};
    HANDLE hToken = NULL, hToken2 = NULL;
    SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
    BOOL result = FALSE;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken))
    {
        fprintf(stderr, "OpenProcessToken(): %ul\n", GetLastError());
        goto done;
    }

    if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hToken2))
    {
        fprintf(stderr, "DuplicateTokenEx(): %ul\n", GetLastError());
        goto done;
    }

    if (!AllocateAndInitializeSid(
        &NtAuthority,
        1,
        SECURITY_MANDATORY_SYSTEM_RID,
        0,
        0, 0, 0, 0, 0, 0,
        &(tml.Label.SID)))
    {
        fprintf(stderr, "AllocateAndInitializeSid(): %ul\n", GetLastError());
        goto done;
    }

    tml.Label.Attributes = ...;

    if (!SetTokenInformation(hToken2, TokenIntegrityLevel, &tml, sizeof(tml)))
    {
        fprintf(stderr, "SetTokenInformation(): %ul\n", GetLastError());
        goto done;
    }

    result = TRUE;

done:
    if (tml.Label.SID) FreeSid(tml.Label.SID);
    if (hToken) CloseHandle(hToken);
    if (hToken2) CloseHandle(hToken2);

    return result;
}

int main(int argc, char** argv)
{
    Elevate();
}
  • Related