4
votes

This is similar to " how create medium integrity level process from low integrity level process? ", but I'm coming from a slightly different angle. (And that isn't answered anyway.) :)

If a file is saved as low integrity (typically from a low integrity app such as a browser) then it is marked with a Low Integrity Mandatory Label. (This label can also be applied with icacls /setintegritylevel low.) If such a file is executed, it becomes a low integrity process, understandably.

Is there some way to elevate (via consent UI) this process back to medium integrity? It's possible to go to high integrity if the app is marked with a requiresAdministrator manifest, or if it calls ShellExecute with the runas verb, but obviously this requires admin permissions as well. Going to medium integrity doesn't require admin permissions and it still unlocks a lot of permissions unavailable to low integrity processes.

Obviously any mechanism to do so should require the user consent UI (it should be impossible to do it silently, otherwise what's the point?), but how can that be invoked?

The only discussion on this topic that I've found involves having an originally-medium-integrity process of your own and spinning off the low-integrity process from it; this permits elevation by communication back to the medium-integrity process and getting it to launch whatever. But this doesn't help when it's the OS itself that initially starts the process with low integrity.

2
A process becomes a Low integrity if it has the Low Mandatory Integrity Level label (S-1-16-4096). i'm looking at the MSDN code now where you duplicate your current token, and add the LowIL sid. Presumably creating a medium integrity level process is similarly easy - adding a Medium Integrity Level label (S-1-16-8192). - Ian Boyd
Nevermind, that doesn't work. The call to SetTokenInformation, attempting to add the higher integrity label fails with 1314 - A required privilege is not held by the client. - Ian Boyd
@Miral: have you been able to reproduce this problem? - Harry Johnston
@HarryJohnston: I haven't been able to reproduce a file being saved as low integrity from IE9, no (that idea was based on a user report, but may have been caused by something else). I have reproduced the case I mention above where a file marked as low integrity via unspecified-means-not-relevant-to-the-question will run as a low integrity process and be unable to elevate itself to medium, only to high. Which seems weird. I accept that consent UI must be required for this elevation, I'm just surprised there doesn't seem to be a standard broker for it as with high integrity. - Miral
@Miral: I think the bottom line is that files aren't supposed to be marked as low integrity without a good reason. The proper solution is not for the executable to be able to ask a non-privileged user for permission to elevate itself back up to medium, but to identify and correct the problem that caused it to be marked as low integrity in the first place. - Harry Johnston

2 Answers

1
votes

I have never seen or heard of a way to get a user's consent to elevate a process from low to medium integrity. I would say you are out of luck.

Please also see this blog article for reference: Internet Explorer in Protected Mode – How the Low Integrity Environment Gets Created

1
votes

You will have to do what Internet Explorer (and Chrome) do. The browser tabs themselves are separate processes running at Low Mandatory Integrity Level. But there is still a Medium level parent process.

The client processes communicate back to the "parent" process though named pipes, asking the parent to perform some action. Since the parent is medium, it can launch something at medium.


Update: Here's an example of how you cannot create a medium integrity process from a low integrity process:

void CreateLowProcess(String szProcessName; String IntegritySid)
{
    hToken: THandle;
    hNewToken: THandle;
    szIntegritySid: WideString;
    pIntegritySid: PSID;
    TIL: TOKEN_MANDATORY_LABEL;
    ProcInfo: PROCESS_INFORMATION;
    startupInfo: TStartupInfo;

    const int SE_GROUP_INTEGRITY = 0x00000020;
    const int TokenIntegrityLevel = 25;

    const String SLowIntegritySid = "S-1-16-4096";
    const String SMediumIntegritySid = "S-1-16-8192";
    const String SHighIntegritySid = "S-1-16-12288";
    const String SSystemIntegritySid = "S-1-16-16384";

    /*
        Designing Applications to Run at a Low Integrity Level
        http://msdn.microsoft.com/en-us/library/bb625960.aspx
    */

    // Low integrity SID
    if IntegritySid == ""
       IntegritySid = SMediumIntegritySid;

    pIntegritySid = null;

    ZeroMemory(@startupInfo, sizeof(startupInfo));


    if (!OpenProcessToken(GetCurrentProcess(), 
          TOKEN_DUPLICATE or TOKEN_ADJUST_DEFAULT or TOKEN_QUERY or TOKEN_ASSIGN_PRIMARY, 
          ref hToken))
    RaiseLastWin32Error;
    try
        if (not DuplicateTokenEx(hToken, 0, nil, SecurityImpersonation, TokenPrimary, {var}hNewToken)) then
            RaiseLastWin32Error;
        try
            if (not ConvertStringSidToSidW(PWideChar(szIntegritySid), {var}pIntegritySid)) then
                RaiseLastWin32Error;
            try
                TIL._Label.Attributes := SE_GROUP_INTEGRITY;
                TIL._Label.Sid := pIntegritySid;

                // Set the process integrity level
                if (not SetTokenInformation(hNewToken, TTokenInformationClass(TokenIntegrityLevel), @TIL,
                        sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(pIntegritySid))) then
                    RaiseLastWin32Error;

                //Create the new process at Low integrity
                Result := CreateProcessAsUserW(
                        hNewToken,
                        nil,
                        PWideChar(szProcessName),
                        nil, //ProcessAttributes
                        nil, //ThreadAttributes
                        False, //bInheritHandles
                        0, //dwCreationFlags
                        nil, //lpEnvironment
                        nil, //lpCurrentDirectory
                        startupInfo,
                        ProcInfo);
            finally
                LocalFree(Cardinal(pIntegritySid));
            end;
        finally
            CloseHandle(hNewToken);
        end;
    finally
        CloseHandle(hToken);
    end;
end;

And i give up transcoding the rest from pascal to C#. It can't be done anyway, that's the answer.