How to CreateProcess NOT as administrator

One of our modules is an executable that will always be run as administrator (after getting permission from user). One of its screens allows the user to run a different executable, which the code currently does by CreateProcess. The problem is that since the first process is running as admin, CreateProcess has the second process run as admin also. This is undesirable because it is a security breach (the second process can open browse dialogs that should not have admin privileges in this scenario). How do I get the second to run without admin privileges? I do NOT want attach a manifest to the second exe that says it does not want admin privileges because under certain circumstances (not from the first exe), it SHOULD be run with admin privileges. I would have expected CreateProcess to allow control over the privileges to be given to the child process, but can not find any documentation for this. Help!
[921 byte] By [efratian] at [2007-12-24]
# 1
I guess the rough idea is to create a restricted token, and the call CreateProcessWithToken()
( or similar ) for the second process
HermannS at 2007-10-8 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 2
How does one restrict the token (API), and is there just one kind of restricted token? Theoretically, there could be any number of privileges one could take away from a token. There has got to be a simple way to do this...
efratian at 2007-10-8 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 3

OK. I just stumbled up on this article. It has sample code that does exactly what we want. Unfortunately, it uses undocumented structures and values which I can't find anywhere.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ietechcol/dnwebgen/protectedmode.asp

The following forum might be worth watching:

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=288831&SiteID=1

christophilus at 2007-10-8 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 4

OK, the above can be found in the DDK. And to clarify, what I really want to do is launch a process which runs in virtualization mode. The following should do the trick, except that the calling process (whose TokenVirtualization flags are set to false) doesn't have permission to modify said flags on my new token.

Which is stupid.

I can understand being unable to set the flags to false, as that would allow developers to give tokens access rights they shouldn't have. However, I should always be able to lower the access rights of a token (such as by setting virtualization to true).

*SIGH*

Here's what I'm trying:

DWORD True = 1;

if (!::SetTokenInformation(hNewToken, TokenVirtualizationAllowed, &True, sizeof(True)))

{throw SystemException("LaunchMediumIntegrityProcess2.SetTokenInformation(3)");}

if (!::SetTokenInformation(hNewToken, TokenVirtualizationEnabled, &True, sizeof(True)))

{throw SystemException("LaunchMediumIntegrityProcess2.SetTokenInformation(4)");}

christophilus at 2007-10-8 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 5
I'm just learning some of these APIs myself, but I would try just using CreateRestrictedToken() specifying a restricting SID of Users and perhaps a list of privileges to be removed, then CreateProcessAsUser() and see if the system would take care of using virtualization for the new process.
lfutrell at 2007-10-8 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 6

Folks, this is getting very complicated. All I want to do is, in a process running with elevated (i.e. administrator) rights, to start a process that has the ordinary set of rights that it would get if it were started by the user from explorer. I do not want to turn virtualization on or off. I do not want to start a low integrity process (as is described in http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ietechcol/dnwebgen/protectedmode.asp). I just want to get a plain, ordinary process. I do not want to turn off specific rights, one-by-one. That is too complicated and bug-prone. Who says that tomorrow an elevated process won't get yet another super-duper right that I also have to turn off, if I am turning off specific rights one-by-one? This is really a very simple thing, and there has to be a simple way to do it. Is anyone from Microsoft listening out there?

efratian at 2007-10-8 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 7
Ok, here is a solution: use the SAFER API, introduced in XP and 2003. The code sample is in http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncode/html/secure11152004.asp, and it actually works. I still think that Microsoft should have defined new flags for CreateProcess to make this still easier, but this is good enough.
efratian at 2007-10-8 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 8

I have experimented a little with using SaferCreateLevel() and SaferComputeTokenFromLevel() to create a "normal user" process from an administrator process. I found that the normal user process created this way on a Vista system still had the "Mandatory Label\High Mandatory Level" SID in its token, whereas a default process created by Vista for an administrator user has instead the "Mandatory Label\Medium Mandatory Level" SID in its token. I was able to correct this by adding code such as the following after SaferCreateTokenFromLevel() and before CreateProcessAsUser():

SID_IDENTIFIER_AUTHORITY siaMLA = SECURITY_MANDATORY_LABEL_AUTHORITY;
PSID pSidMedium = NULL;
TOKEN_MANDATORY_LABEL TIL = {0};

if (AllocateAndInitializeSid(&siaMLA,
1,
SECURITY_MANDATORY_MEDIUM_RID,
0,
0,
0,
0,
0,
0,
0,
&pSidMedium)) {
TIL.Label.Attributes = SE_GROUP_INTEGRITY;
TIL.Label.Sid = pSidMedium;
if (SetTokenInformation(hToken,
TokenIntegrityLevel,
&TIL,
sizeof(TOKEN_MANDATORY_LABEL))) {

lfutrell at 2007-10-8 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 9

Sigh... Indeed it is true that SAFER does not (at least in Vista Beta 2) set the TokenIntegrityLevel to the medium SID, nor TokenVirtualizationAllowed to TRUE, nor even TokenElevationType (whatever its effect is...) to TokenElevationTypeLimited. It does set TokenElevation to FALSE. Please note that there are several more new token information types (e.g. TokenLinkedToken, TokenHasRestrictions, TokenAccessInformation, and TokenMandatoryPolicy) whose meaning I do not understand and which I did not even try checking, so I do not know if SAFER dealt with them. Also note that, as christophilus discovered above, setting TokenVirtualizationAllowed to TRUE does not even work via SetTokenInformation (at least in Beta 2). And also note that when setting TokenIntegrityLevel, TIL.Label.Attributes should probably be set to SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED, not just SE_GROUP_INTEGRITY. And still further note that under Beta 2, it is insufficient to set TokenIntegrityLevel - one must also set TokenIntegrityLevelDesktop (with SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED_DESKTOP). But in the July CTP version of the SDK, TokenIntegrityLevelDesktop has disappeared...

Furthermore, it turns out that processes with a token manipulated by SAFER and SetTokenInformation behave strangely in a number of ways. First, they are not considered to be of the same user as explorer for the purposes of COM, so you can't connect to a COM server running in such a process. Second, at least in the July CTP and pre-RC1, when such processes themselves ShellExecute an exe marked with a requiresAdministrator manifest that would normally result in an elevation dialog, strangely enough no elevation dialog results, and the new process runs without admin privileges (and fails).

At the risk of sounding repetetive, what all this boils down to is a need for Microsoft to provide a simple, single API that will do the same thing that Vista does to the token at logon, with as few options as possible (to minimize the chances of doing it wriong). It should not take ten bug-prone, not-quite-documented API calls to do this. This is not an esoteric task: any installer that wants to support a checkbox at the end to run the product needs it; any administrative program that wants to be able to run notepad to display some text file needs it, and so on. As I said, a single SAFER-type call to do the job would be the minimum acceptable, but a new CreateProcess flag is what's really needed.

efratian at 2007-10-8 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 10
The RC1 is here and, as far as I can tell, nothing has changed. At least I have figured out a method that really does do what we want it to do, although it is extremely roundabout. To run a process with the exact token it would have if run from explorer, you can create, start, and then delete a special-purpose service that uses WTSQueryUserToken to get the session's token (on Vista, this returns the restricted token), then DuplicateTokenEx to make it a primary token, then CreateEnvironmentBlock to create an environment to pass to the process, then CreateProcessAsUser, and then just stop. When starting the service, you pass it as parameters your session id (use ProcessIdToSessionId) and the command line of the new process. I've tried it, it works (on both XP and Vista). The reason you have to do this through a service is that even an admin account usually does not have the SE_ASSIGNPRIMARYTOKEN_NAME privilege necessary to run CreateProcessAsUser on a token different than the calling process's. But an admin account does have the privileges to create, start, and delete services running as Local System...
efratian at 2007-10-8 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 11

I am trying to do the same thing and running into the same problems, it seems that the safer api does not do what we want it to do, the resulting token will have more priveleges entirely removed than the restricted token used by the explorer.

This really is a huge oversite on the part of microsoft, especially considered the goal is to limit the number of process's that have priveleged access. You think the ability to launch a restricted process that has the same user token as the one in explorer (from an admin process) would be the one of the first things put out there for developers.. and it should be something thats recommended for use... Geez?! If you guys are going to go this whole restricted route.. dont go halfway..

PS. let me know what you guys figure out for this.

JonnyDeep at 2007-10-8 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 12
Elevation's a one way trip. If you want to do this, the right way is to have an exe manifested with "asInvoker" that then does a ShellExecute on the admin exe, and have the "asInvoker" exe launch the non-admin exe.

DavidTylerHunt at 2007-10-8 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 13
We are trying to do the same thing. Well we want to CreateProcessAsUser from a running service. Needs to work on XP and Vista. Right now call to CreateEnvironmentBlock fails (only tried on XP so far). Any ideas?
VJJJ at 2007-10-8 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 14

I assume your service is running as Local System. If so, there is probably something wrong with the token you are passing to it. Did you get it from DuplicateTokenEx? We use:

HANDLE hTokenDup = NULL;
if (!DuplicateTokenEx(
hToken, MAXIMUM_ALLOWED, NULL,
SecurityIdentification, TokenPrimary,
&hTokenDup)
) {
CloseHandle(hToken);
return false;
}

LPVOID lpEnvironment = NULL;
if (!CreateEnvironmentBlock(
&lpEnvironment, hTokenDup, FALSE /* do not inherit */)
) {
CloseHandle(hToken);
CloseHandle(hTokenDup);
return false;
}

Also, see the Calling CreateProcessAsUser() from service thread.

efratian at 2007-10-8 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...

Software Development for Windows Vista

Site Classified