From: Corinna Vinschen on
Stefan Kuhr wrote:
> Hi Kerem,
>
> On 2/24/2010 9:42 AM, Kerem Gümrükcü wrote:
>> Does someone have a good idea, possibly not
>> something with a second process runing non-elevated
>> and expecting some signal or antother IPC data to
>> spawn the non-elevated process, or like the example
>> above duplicating the token from a process,...
>
> I think the answer is given in the article you mentioned: Since you want
> the process to run under the same user account as the elevated process,
> but just run it without the elevation, then "launch the new process with
> that “dumbed down” token".
>
> Have you tried creating a restricted token from your elevated token and
> then use CreateProcessAsUser? I have never tried this but I assume this
> is the way to go.

CreateRestrictedToken works fine, but there's a warning in MSDN that
CreateRestrictedToken is still a bit of a security problem:

"Warning Applications that use restricted tokens should run the
restricted application on desktops other than the default desktop.
This is necessary to prevent an attack by a restricted application,
using SendMessage or PostMessage, to unrestricted applications on
the default desktop. If necessary, switch between desktops for your
application purposes."

Other than that, I experimented a lot with GetTokenInformation info
class TokenLinkedToken, and as far as I remember, if you're running in
an elevated process, the linked token is the non-elevated token.

So, in theory, if I remember right, what you could do is this, just
roughly outlined:

TOKEN_LINKED_TOKEN linked;
TOKEN_TYPE type;

token = OpenProcessToken (GetCurrentProcess ());
if (!GetTokenInformation (token, TokenLinkedToken, &linked))
/* bail out */
new_token = linked.LinkedToken;
if (GetTokenInformation (linked.LinkedToken, TokenType, &type)
&& type != TokenPrimary)
{
/* Ok, that's a bit tricky now. If the linked token is the
elevated token, and if the process running this code does not
have TCB privs, then the linked token is an impersonation token
*and* DuplicateTokenEx fails when trying to create a primary
token from this impersonation token. However, that doesn't mean
it won't work for the non-elevated token. */
if (!DuplicateTokenEx (linked.LinkedToken, ... TokenPrimary,
&new_token))
/* bail out */
}
CloseHandle (token);
CreateProcessAsUser (new_token, ...);

If it doesn't work..., well, maybe it was worth a try?


Corinna

--
Corinna Vinschen
Cygwin Project Co-Leader
Red Hat
From: m on

this risk exists as soon as there are both elevated and non-elevated
processes running on the same desktop, since they must communicate to
maintain basic state, and what you would need to do has little impact on the
overall security of the system since you are already running an elevated
process, and just talking about starting a restricted one. This note just
reinforces the fact that the elevated / restricted token is not a hard
security barrier, but just another layer in a layered defence

"Corinna Vinschen" <corinna(a)community.nospam> wrote in message
news:hm3o7o$9g1$1(a)perth.hirmke.de...
> Stefan Kuhr wrote:
>> Hi Kerem,
>>
>> On 2/24/2010 9:42 AM, Kerem Gümrükcü wrote:
>>> Does someone have a good idea, possibly not
>>> something with a second process runing non-elevated
>>> and expecting some signal or antother IPC data to
>>> spawn the non-elevated process, or like the example
>>> above duplicating the token from a process,...
>>
>> I think the answer is given in the article you mentioned: Since you want
>> the process to run under the same user account as the elevated process,
>> but just run it without the elevation, then "launch the new process with
>> that “dumbed down” token".
>>
>> Have you tried creating a restricted token from your elevated token and
>> then use CreateProcessAsUser? I have never tried this but I assume this
>> is the way to go.
>
> CreateRestrictedToken works fine, but there's a warning in MSDN that
> CreateRestrictedToken is still a bit of a security problem:
>
> "Warning Applications that use restricted tokens should run the
> restricted application on desktops other than the default desktop.
> This is necessary to prevent an attack by a restricted application,
> using SendMessage or PostMessage, to unrestricted applications on
> the default desktop. If necessary, switch between desktops for your
> application purposes."
>
> Other than that, I experimented a lot with GetTokenInformation info
> class TokenLinkedToken, and as far as I remember, if you're running in
> an elevated process, the linked token is the non-elevated token.
>
> So, in theory, if I remember right, what you could do is this, just
> roughly outlined:
>
> TOKEN_LINKED_TOKEN linked;
> TOKEN_TYPE type;
>
> token = OpenProcessToken (GetCurrentProcess ());
> if (!GetTokenInformation (token, TokenLinkedToken, &linked))
> /* bail out */
> new_token = linked.LinkedToken;
> if (GetTokenInformation (linked.LinkedToken, TokenType, &type)
> && type != TokenPrimary)
> {
> /* Ok, that's a bit tricky now. If the linked token is the
> elevated token, and if the process running this code does not
> have TCB privs, then the linked token is an impersonation token
> *and* DuplicateTokenEx fails when trying to create a primary
> token from this impersonation token. However, that doesn't mean
> it won't work for the non-elevated token. */
> if (!DuplicateTokenEx (linked.LinkedToken, ... TokenPrimary,
> &new_token))
> /* bail out */
> }
> CloseHandle (token);
> CreateProcessAsUser (new_token, ...);
>
> If it doesn't work..., well, maybe it was worth a try?
>
>
> Corinna
>
> --
> Corinna Vinschen
> Cygwin Project Co-Leader
> Red Hat

From: Stefan Kuhr on
Hi Corinna,

On 2/24/2010 6:39 PM, Corinna Vinschen wrote:
> Stefan Kuhr wrote:
>> Hi Kerem,
>>
>> On 2/24/2010 9:42 AM, Kerem Gümrükcü wrote:
>>> Does someone have a good idea, possibly not
>>> something with a second process runing non-elevated
>>> and expecting some signal or antother IPC data to
>>> spawn the non-elevated process, or like the example
>>> above duplicating the token from a process,...
>>
>> I think the answer is given in the article you mentioned: Since you want
>> the process to run under the same user account as the elevated process,
>> but just run it without the elevation, then "launch the new process with
>> that “dumbed down” token".
>>
>> Have you tried creating a restricted token from your elevated token and
>> then use CreateProcessAsUser? I have never tried this but I assume this
>> is the way to go.
>
> CreateRestrictedToken works fine, but there's a warning in MSDN that
> CreateRestrictedToken is still a bit of a security problem:
>
> "Warning Applications that use restricted tokens should run the
> restricted application on desktops other than the default desktop.
> This is necessary to prevent an attack by a restricted application,
> using SendMessage or PostMessage, to unrestricted applications on
> the default desktop. If necessary, switch between desktops for your
> application purposes."
>
> Other than that, I experimented a lot with GetTokenInformation info
> class TokenLinkedToken, and as far as I remember, if you're running in
> an elevated process, the linked token is the non-elevated token.
>

It definitely is worth a try for Kerem. My experience is that the linked
token can only be used for the AccessCheck API and nothing else.
However, since GetTokenInformation with TokenLinkedToken still seems to
be officially undocumented (my Server 08 PlatSDK doesn't document it and
on msdn online, TokenLinkedToken is also not mentioned as a valid
parameter for GetTokenInformation), I wouldn't be surprised if it works
accidentally but breaks with the next service pack.

--
S
From: Corinna Vinschen on
Hey Stefan,

Stefan Kuhr wrote:
> Hi Corinna,
>
> On 2/24/2010 6:39 PM, Corinna Vinschen wrote:
>> Other than that, I experimented a lot with GetTokenInformation info
>> class TokenLinkedToken, and as far as I remember, if you're running in
>> an elevated process, the linked token is the non-elevated token.
>
> It definitely is worth a try for Kerem. My experience is that the linked
> token can only be used for the AccessCheck API and nothing else.

You are definitely right, if the process has no TCB privileges, and if
the process token is the restricted token, not the elevated token. In
this case the linked token is just an impersonation token and the call
to DuplicateTokenEx(PrimaryToken) fails with "access denied".

However, I know for a fact (since I'm using this capability in Cygwin)
that the linked, elevated token is a primary token suitable for calls
to CreateProcessAsUser, if the calling process has TCB privileges.
Which makes a lot of sense to me, even if that is nowhere documented.
And I seriously hope for Cygwin that this won't be changed in some
future version of Windows.

In Kerem's case I'm not sure. I never checked in the inverse case
- calling TokenLinkedToken on the elevated token - and without TCB
privileges, if the linked token is an impersonation token for which
DuplicateTokenEx(PrimaryToken) fails. I made the suggestion
nevertheless, because it can be very easily tested.

> However, since GetTokenInformation with TokenLinkedToken still seems to
> be officially undocumented (my Server 08 PlatSDK doesn't document it and
> on msdn online, TokenLinkedToken is also not mentioned as a valid
> parameter for GetTokenInformation), I wouldn't be surprised if it works
> accidentally but breaks with the next service pack.

It is documented as TOKEN_INFORMATION_CLASS member:
http://msdn.microsoft.com/en-us/library/aa379626%28VS.85%29.aspx

And the TOKEN_LINKED_TOKEN structure is documented as well:
http://msdn.microsoft.com/en-us/library/bb530719%28VS.85%29.aspx

It's only missing in the man pages for GetTokenInformation and
SetTokenInformation.

The fact that the TOKEN_LINKED_TOKEN man page refers to
SetTokenInformation is interesting. I assume that you need TCB
privileges as well to link a token to another token, but I never
tried that.


Corinna

--
Corinna Vinschen
Cygwin Project Co-Leader
Red Hat
From: Stefan Kuhr on
Hi Corinna,

On 2/25/2010 3:38 PM, Corinna Vinschen wrote:
> <snip>
> In Kerem's case I'm not sure. I never checked in the inverse case
> - calling TokenLinkedToken on the elevated token - and without TCB
> privileges, if the linked token is an impersonation token for which
> DuplicateTokenEx(PrimaryToken) fails. I made the suggestion
> nevertheless, because it can be very easily tested.
>


Were you thinking about something like the following code? When run
under an elevated token, CPAU fails with 1314 (Privilige not held) and
the linked token is an impersonation token, duplicating it to a primary
token fails with 1346 (bad impersonation level):


int _tmain(int argc, _TCHAR* argv[])
{
TOKEN_LINKED_TOKEN tlt;


HANDLE hProcessToken = NULL;

if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY,
&hProcessToken))
{
DWORD cbLength = 0L;
if (GetTokenInformation(hProcessToken, TokenLinkedToken,
&tlt,sizeof(tlt), &cbLength))
{
TCHAR szCmdLine[] = _T("notepad");

STARTUPINFO si = {0};
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
PROCESS_INFORMATION pi;

if(CreateProcessAsUser(tlt.LinkedToken,
_T("c:\\windows\\notepad.exe"), szCmdLine, NULL,
NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi))
{
_tprintf(_T("It worked\n"));
VERIFY(WAIT_OBJECT_0==WaitForSingleObject(pi.hProcess,
INFINITE));
VERIFY(CloseHandle(pi.hProcess));
VERIFY(CloseHandle(pi.hThread));
}
else
{
DWORD dwLastError = GetLastError();
_tprintf(_T("CPAU failed with %lu (0x%.8x)\n"), dwLastError,
dwLastError);
}

TOKEN_TYPE tt;

if (GetTokenInformation(tlt.LinkedToken, TokenType,
&tt,sizeof(tt), &cbLength))
{
_tprintf(_T("Token is of type %lu\n"), (DWORD) tt);

if(TokenImpersonation==tt)
{
HANDLE hPrimary = NULL;
if(!DuplicateTokenEx(tlt.LinkedToken, 0L, NULL,
SecurityImpersonation, TokenPrimary, &hPrimary))
{
DWORD dwLastError = GetLastError();
_tprintf(_T("DuplicateTokenEx failed with %lu (0x%.8x)\n"),
dwLastError, dwLastError);
}
}

}

VERIFY(CloseHandle(tlt.LinkedToken));
}

VERIFY(CloseHandle(hProcessToken));
}


return 0;
}



Cheers,

--
S