Today we were having a discussion around Internet Explorer in Protected Mode, and the question came up regarding how to launch an arbitrary process with a low integrity level. This is fairly straightforward to do in code.
First, you duplicate the handle of the medium integrity process (the default) that is launching the application. The OpenProcessToken API will find the existing token, and you can then call DuplicateTokenEx to create a copy.
Next, you use SetTokenInformation to lower the duplicate token to low integrity. The SID for low integrity is S-1-16-4096, and the attributes of the TOKEN_MANDATORY_LABEL's label should be set to SE_GROUP_IDENTITY.
Finally, you call CreateProcessAsUser to launch the process with the new integrity level.
This is described, with sample code, on MSDN. See: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ProtectedMode.asp.
Note that you don't have to use a bootstrapper to do this. Rather, you can call CreateProcessAsUser and re-launch yourself. In fact, this is exactly what iexplore.exe does when it is launching. We can watch this with the debugger by setting a few breakpoints.
First, we'll set a breakpoint on ADVAPI32!OpenProcessToken:
0:000> kpChildEBP RetAddr 001ff71c 773a3d59 ADVAPI32!OpenProcessToken001ff748 773a3d0b iertutil!GetTokenIntegrityLevel+0x46001ff75c 773a4154 iertutil!GetProcessIntegrityLevel+0x21001ff76c 773a5fa4 iertutil!IsMICLowProcess+0x11001ff774 013813b8 iertutil!IsProtectedModeProcess+0x19001ffbac 0138131a iexplore!wWinMain+0x85001ffc40 75e03833 iexplore!_initterm_e+0x1b1001ffc4c 771fa9bd kernel32!BaseThreadInitThunk+0xe001ffc8c 00000000 ntdll!_RtlUserThreadStart+0x23
Here, we are checking our integrity level - obviously we only want to launch a new process if the current one isn't already running in low IL or we'd be launching new processes forever!
Later, we call SetTokenInformation:
0:000> kChildEBP RetAddr 001ff6b8 773a631b ADVAPI32!SetTokenInformation001ff6f4 773a6066 iertutil!IESetTokenIntegrityLevel+0xb1001ff714 773a600c iertutil!CreateMICIEProcess+0x4c001ff72c 01384815 iertutil!LaunchIEInProtectedMode+0x2a001ff774 01381488 iexplore!LaunchLoRIEModeIE+0x5e001ffbac 0138131a iexplore!wWinMain+0x253001ffc40 75e03833 iexplore!_initterm_e+0x1b1001ffc4c 771fa9bd kernel32!BaseThreadInitThunk+0xe001ffc8c 00000000 ntdll!_RtlUserThreadStart+0x23
After we have configured the new token, we launch ourselves again, this time with low IL, using CreateProcessAsUser:
0:000> kChildEBP RetAddr 001fe3ec 773a61e1 ADVAPI32!CreateProcessAsUserW001ff6ec 773a6079 iertutil!LaunchProtectedModeIEWithToken+0x163001ff714 773a600c iertutil!CreateMICIEProcess+0x5f001ff72c 01384815 iertutil!LaunchIEInProtectedMode+0x2a001ff774 01381488 iexplore!LaunchLoRIEModeIE+0x5e001ffbac 0138131a iexplore!wWinMain+0x253001ffc40 75e03833 iexplore!_initterm_e+0x1b1001ffc4c 771fa9bd kernel32!BaseThreadInitThunk+0xe001ffc8c 00000000 ntdll!_RtlUserThreadStart+0x23
After we do this, a new iexplore.exe is launched, and it's running with a restricted token. You can certainly do the same with your code, and may want to consider this if you are looking to implement and secure an Internet-facing application that does not require access to local resources.
Chris:
Can i raise a process(A) integrity level to medium from a low integrity process(B). Is it a good practice?
You can launch a medium or high integrity process from a low integrity process. IE does this if you are trying to follow a known path. If you want to use, for example, input type=file, it has to launch ieuser.exe, which runs with medium integrity and can actually see user files. If you want to install an ActiveX control, then it has to launch ieinstal.exe. But you can't elevate "in place" if that is what you mean.
Thanks for your response. What i meant is i want to convert a process from low integrity level to medium integrity level.
I wanted to do the oppposite as the function "CreateLowProcess()" from the below URL
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/IETechCol/dnwebgen/ProtectedMode.asp
-SR
I haven't tried this specifically. The SID for Mandatory Label\Medium Mandatory Level is S-1-16-8192.
Update to my earlier response: iexplore isn't doing anything to create a new process in medium IL from low IL - it's invoking into an existing ieuser.exe to handle that. So, you'd want to have a broker process set up and already running for your process to go the other direction, having the broker process invoked to spin up the new process at higher IL. If we didn't do this, then there would be a clear path for elevation of privilege.
It creates the low integrity process but it doesnt launch it on the desktop. Any way around this?
Hi Ganesh,
I'm not sure what you mean. What is the "it" to which you are referring?
Thanks,
Chris
Chris,
Thanks for your response.
I duplicate the handle of my medium integrity process, set its token information to low integrity and run notepad using CreateProcessAsUser.
Notepad process was created but it was not launched on the desktop.
Ganesh
There's nothing wrong with Notepad running in Low IL - you can test that out by using psexec -l notepad.exe and it launches with Low IL just fine. So, there must be an issue with the particular implementation. Have a code snippet?
Hi Chris,
I just created a console app that start starts notepad with low IL. Here is the code snippet. Its almost same as the one in the site.
{
BOOL fRet;
HANDLE hToken = NULL;
HANDLE hNewToken = NULL;
HWND h;
PSID pIntegritySid = NULL;
TOKEN_MANDATORY_LABEL TIL = {0};
PROCESS_INFORMATION ProcInfo = {0};
STARTUPINFO StartupInfo = {0};
LPSTR wszProcessName = "C:\\Windows\\Notepad.exe";
LPSTR wszIntegritySid = "S-1-16-1024";
pIntegritySid = NULL;
fRet = OpenProcessToken(GetCurrentProcess(),
TOKEN_DUPLICATE |
TOKEN_ADJUST_DEFAULT |
TOKEN_QUERY |
TOKEN_ASSIGN_PRIMARY,
&hToken);
if (!fRet)
printf("Open process failed\n");
goto CleanExit;
}
else
printf("Open process succeeded\n");
fRet = DuplicateTokenEx(hToken,
0,
NULL,
SecurityImpersonation,
TokenPrimary,
&hNewToken);
printf("duplicate token creation failed\n");
printf("duplicate token done\n");
fRet = ConvertStringSidToSid(wszIntegritySid, &pIntegritySid);
printf("Conversion failed\n");
printf("convert done\n");
TIL.Label.Attributes = SE_GROUP_INTEGRITY|SE_GROUP_INTEGRITY_ENABLED;
TIL.Label.Sid = pIntegritySid;
//
// Set the process integrity level
fRet = SetTokenInformation(hNewToken,
TokenIntegrityLevel,
&TIL,
sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(pIntegritySid));
printf("Setting token info failed\n");
printf("setting token done\n");
// Create the new process at Low integrity
StartupInfo.cb= sizeof(STARTUPINFO);
fRet = CreateProcessAsUser(hNewToken,
wszProcessName,
FALSE,
&StartupInfo,
&ProcInfo);
if(!fRet)
printf("Process not created\n");
else{
printf("Process created\n");
CleanExit:
if (ProcInfo.hProcess != NULL)
CloseHandle(ProcInfo.hProcess);
if (ProcInfo.hThread != NULL)
CloseHandle(ProcInfo.hThread);
LocalFree(pIntegritySid);
if (hNewToken != NULL)
CloseHandle(hNewToken);
if (hToken != NULL)
CloseHandle(hToken);
// return fRet;
return 0;
The output is
Open process succeeded
duplicate token done
convert done
setting token done
Process created
But opening notepad has failed with error code 0xc0000022. Message box is displayed as
"The application failed to initialize properly(0xc0000022). Click OK to terminate the application."
Looks like that error has again got to do with privileges. And my UAC is ON.
Ganesh.
Well I managed to solve that low integrity problem. But having an other problem in Vista.
I need to selectively delete certain items from the I.E. cache.
When I iterate through the I.E. cache on Windows Vista, only the entries in Visited container are enumerated.
Has anything changed in Windows Vista to break the FindFirstUrlCacheEntry /
FindNextUrlCacheEntry method of iterating through the cache?
I wasn't looking for your advanced info.; just thought my Protected Mode should be "On".
<duanekisshauer@comcast.net>
Hi Duane,
Is there a question? Is it not turned on? Not sure how you want me to help...?