Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Windows 2003: How to get SE_CREATE_TOKEN_NAME as service running in the SYSTEM account?

6 views
Skip to first unread message

Daniel Lohmann

unread,
Jun 15, 2003, 5:34:50 PM6/15/03
to
Hi folks,

Windows 2003 provides the new SE_PRIVILEGE_REMOVED flag for
AdjustTokenPrivileges to permanently remove a privilege from a token.

It seems that Windows 2003 uses this new feature to remove
SeCreateTokenPrivilege even from the SYSTEM token most services are
running under. A short inspection showed me that only the processes
"System", "lsass" and "smss" have this privilege, all other SYSTEM
processes miss it...

Is there any way to get it back inside my own service? Or do I have to
hack into one of the above processes to get a token with
SeCreateTokenPrivilege? (Oh, I really would like to avoid that...)


Thanks

Daniel

Slava M. Usov

unread,
Jun 16, 2003, 6:30:00 AM6/16/03
to
"Daniel Lohmann" <dan...@uni-koblenz.de> wrote in message
news:g6ppev8pvl1q2e95c...@4ax.com...

> Windows 2003 provides the new SE_PRIVILEGE_REMOVED flag for
> AdjustTokenPrivileges to permanently remove a privilege from a token.

[...]

> Is there any way to get it back inside my own service? Or do I have to
> hack into one of the above processes to get a token with
> SeCreateTokenPrivilege? (Oh, I really would like to avoid that...)

Given what MSDN says, you cannot get it back. Even if you could somehow,
they would fix that pretty soon, I guess. Except by invading the processes
that have it, you can create tokens from a driver [can be a major security
hole unless you make the interface bullet-proof], or -- speculating here --
by starting a "BootExecute" native application [same caveat]. Better yet,
find a way to go without fabricated tokens; for example, consider restricted
tokens.

S


Daniel Lohmann

unread,
Jun 16, 2003, 6:42:41 AM6/16/03
to
On Mon, 16 Jun 2003 12:30:00 +0200, "Slava M. Usov"
<stripit...@gmx.net> wrote:

>"Daniel Lohmann" <dan...@uni-koblenz.de> wrote in message
>news:g6ppev8pvl1q2e95c...@4ax.com...
>
>> Windows 2003 provides the new SE_PRIVILEGE_REMOVED flag for
>> AdjustTokenPrivileges to permanently remove a privilege from a token.
>
>[...]
>
>> Is there any way to get it back inside my own service? Or do I have to
>> hack into one of the above processes to get a token with
>> SeCreateTokenPrivilege? (Oh, I really would like to avoid that...)
>

Thanks Slava,

>Given what MSDN says, you cannot get it back. Even if you could somehow,
>they would fix that pretty soon, I guess. Except by invading the processes
>that have it, you can create tokens from a driver [can be a major security
>hole unless you make the interface bullet-proof], or -- speculating here --
>by starting a "BootExecute" native application [same caveat].

:- (((
Uff, this looks like some hard work to do...

> Better yet,
>find a way to go without fabricated tokens; for example, consider restricted
>tokens.

The point is I don't need restricted, but extended tokens...

Daniel

Slava M. Usov

unread,
Jun 16, 2003, 7:24:13 AM6/16/03
to
"Daniel Lohmann" <dan...@uni-koblenz.de> wrote in message
news:sk7rev8o8ba50jdpj...@4ax.com...

[...]

> The point is I don't need restricted, but extended tokens...

Then you need read the definitions more carefully. In a restricted token,
the set of the 'restricted' SIDs can be larger than the set of the original
SIDs.

S

Daniel Lohmann

unread,
Jun 17, 2003, 4:04:22 AM6/17/03
to

Yes, but as far as I understand the docs, one can only add groups with
SE_GROUP_USE_FOR_DENY_ONLY, which is actually not a real "extension"
of the token (it should get _more_ access, not less) Futhermore I I
also have to add some privileges.


Daniel

Slava M. Usov

unread,
Jun 17, 2003, 7:01:14 AM6/17/03
to
"Daniel Lohmann" <dan...@uni-koblenz.de> wrote in message
news:6mitev4ib2fhohruq...@4ax.com...

> Yes, but as far as I understand the docs, one can only add groups with
> SE_GROUP_USE_FOR_DENY_ONLY, which is actually not a real "extension"
> of the token (it should get _more_ access, not less)

There are two groups of SIDs that you can specify for
CreateRestrictedToken(). The first one is named 'SidsToDisable' and indeed
does what you say. The second one, named 'SidsToRestrict', adds a bunch of
"restricted" or "restricting" [there is some dichotomy in the naming] SIDs,
which need not be taken from an existing token.

> Futhermore I also have to add some privileges.

Furthermore, you can delete some privileges from an existing token. And that
will do the trick even though it 'deletes' and not 'adds'. Here is an
example:

Assume that you have a service that runs under some privileged account
[like system] that

(i) already has full access to all objects that the users you create/login
might possibly need, and

(ii) it has all privileges that the users might possibly need. However,

(iii) some users must have more limited access, and fewer privileges.

Assume that

(iv) the objects the users are going to access list some SIDs {A, B, C,
etc}, which are not necessarily present in your service's token, and

(v) there is some specification as to which SIDs of {A, BE, CO, etc} must be
given to each created user, and a

(vi) specification on which privileges must be assigned to each user.

What you're doing now is calling NtCreateToken() [I presume] supplying the
SIDs and the privileges according to the specification (v) and (vi), and the
rest is accomplished by (iv). But you may do the same with
CreateRestrictedToken() as follows:

1. 'SidsToRestrict' must specify the SIDs of {A, B, C, etc} according to the
specification (v).
2. 'PrivilegesToDelete' must specify all the privileges that your services
token has and which are NOT given to the user according to the
specification (vi).

I believe you understand the effect of #2 [follows from (ii) and (vi)], so
let's focus on #1. An excerpt from the article on CreateRestrictedToken():

[begin quote]

The system performs two access checks: one using the token's enabled SIDs,
and another using the list of restricting SIDs. Access is granted only if
both access checks allow the requested access rights.

[end quote]

In your case, the first check will always succeed, as follows from (i), and
the result of the second check is governed only by (iv) and (v), but this is
the same result as you would have using NtCreateToken().

Note that you don't have to run your service as system or any other
privileged account, because you do not need any powerful privileges to call
CreateProcessAsUser() with a restricted token. Rather, you only need the
maximum permissions and the privileges your users may need, and you need
only ONE account for that, which makes security management very simple. As
soon as some admin decides that there is a need for additional permissions
or privileges for your users, they can be granted to your service's account;
likewise they can be easily revoked.

S


Daniel Lohmann

unread,
Jun 17, 2003, 11:39:48 AM6/17/03
to
On Tue, 17 Jun 2003 13:01:14 +0200, "Slava M. Usov"
<stripit...@gmx.net> wrote:

>"Daniel Lohmann" <dan...@uni-koblenz.de> wrote in message
>news:6mitev4ib2fhohruq...@4ax.com...
>
>> Yes, but as far as I understand the docs, one can only add groups with
>> SE_GROUP_USE_FOR_DENY_ONLY, which is actually not a real "extension"
>> of the token (it should get _more_ access, not less)
>
>There are two groups of SIDs that you can specify for
>CreateRestrictedToken(). The first one is named 'SidsToDisable' and indeed
>does what you say. The second one, named 'SidsToRestrict', adds a bunch of
>"restricted" or "restricting" [there is some dichotomy in the naming] SIDs,
>which need not be taken from an existing token.
>
>> Futhermore I also have to add some privileges.
>
>Furthermore, you can delete some privileges from an existing token. And that
>will do the trick even though it 'deletes' and not 'adds'. Here is an
>example:
>

>[...]

Slava,

Thank you very much for your illuminative explanations. It is always
not only helpful, but real fun to discuss such topics with you!

Thanks to your example I know understand what CreateRestrictedToken()
really does. I surely have underestimated its power. But (there is
always a "but", isn't it :-) I am still sure that it does not solve my
problem..

>iv) the objects the users are going to access list some SIDs {A, B, C,
>etc}, which are not necessarily present in your service's token, and
>
>(v) there is some specification as to which SIDs of {A, BE, CO, etc} must be
>given to each created user, and a
>
>(vi) specification on which privileges must be assigned to each user.

The point is that the above specification is not complete:

(vii) there is some specification of the TOKEN_USER the resulting
token needs to represent (based on an existing token).

(viii) there is some specification of the SessionID the resulting
token needs to represent (based on the same existing token).

In your approach I have to pass the SYSTEM token (because privileges
can only be "disabled") as ExistingTokenHandle to
CreateRestrictedToken(). The resulting token would therefore even
represent the user SYSTEM - with modified groups and privileges,
right?

Now assume you have an object with an ACL that allows only account
(not group) A to access it. We could not create a restricted token
based on SYSTEM that is able to access this object. (Assuming we do
not want to have SeTakeOwnershipPrivilege or any ACL-bypassing
privileges in the restricted token.)

Another important point is the HKEY_CURRENT_USER-->HKEY_USERS/xyz
substitution if accessing the registry. It is also based on the
TOKEN_USER of the calling threads' token.

And now I hope you will again tell me that I am wrong :-)


Have fun

Daniel

Slava M. Usov

unread,
Jun 17, 2003, 12:27:58 PM6/17/03
to
"Daniel Lohmann" <dan...@uni-koblenz.de> wrote in message
news:fjauevo8a0tu9ndif...@4ax.com...

> Thank you very much for your illuminative explanations. It is always
> not only helpful, but real fun to discuss such topics with you!

Ah, thanks. Same here, actually.

[...]

> (vii) there is some specification of the TOKEN_USER the resulting
> token needs to represent (based on an existing token).

Can be gotten around by logging the user on, and then "restricting" the
token. However, now the user being logged on must belong to an omni-powerful
group, so that (i) is still valid. From the security point of view, it is
worse than letting just one account create tokens. So if you really need
TOKEN_USER, then you must use NtCreateToken() or LsaLogonUser().

> (viii) there is some specification of the SessionID the resulting
> token needs to represent (based on the same existing token).

Oh, for that you the TCB priv. anyway. So, why can't you use LsaLogonUser()
then?

> In your approach I have to pass the SYSTEM token (because privileges
> can only be "disabled") as ExistingTokenHandle to
> CreateRestrictedToken(). The resulting token would therefore even
> represent the user SYSTEM - with modified groups and privileges,
> right?
>
> Now assume you have an object with an ACL that allows only account
> (not group) A to access it. We could not create a restricted token
> based on SYSTEM that is able to access this object. (Assuming we do
> not want to have SeTakeOwnershipPrivilege or any ACL-bypassing
> privileges in the restricted token.)

You might put A as a restricted SID -- nobody is going to check whether a
SID stands for a group, or for an account.

> Another important point is the HKEY_CURRENT_USER-->HKEY_USERS/xyz
> substitution if accessing the registry. It is also based on the
> TOKEN_USER of the calling threads' token.
>
> And now I hope you will again tell me that I am wrong :-)

Well, since you must have the TCB, then you might constraint yourself to
LsaLogonUser(), only. Anticipating the question about privileges, you can
pre-create a number of local groups each with a particular privilege
granted, and use them to assign privileges. You can even create such groups
on the fly.

S


Daniel Lohmann

unread,
Jun 28, 2003, 4:42:15 AM6/28/03
to
Hi Slava,

Sorry for the delay, I have been off for some days :-)


> [...]
>> (vii) there is some specification of the TOKEN_USER the resulting
>> token needs to represent (based on an existing token).
>
>Can be gotten around by logging the user on, and then "restricting" the
>token. However, now the user being logged on must belong to an omni-powerful
>group, so that (i) is still valid. From the security point of view, it is
>worse than letting just one account create tokens. So if you really need
>TOKEN_USER, then you must use NtCreateToken() or LsaLogonUser().
>
>> (viii) there is some specification of the SessionID the resulting
>> token needs to represent (based on the same existing token).
>
>Oh, for that you the TCB priv. anyway. So, why can't you use LsaLogonUser()
>then?

Well, actually because I just have an existing token, but not a
username/password combo...

>> In your approach I have to pass the SYSTEM token (because privileges
>> can only be "disabled") as ExistingTokenHandle to
>> CreateRestrictedToken(). The resulting token would therefore even
>> represent the user SYSTEM - with modified groups and privileges,
>> right?
>>
>> Now assume you have an object with an ACL that allows only account
>> (not group) A to access it. We could not create a restricted token
>> based on SYSTEM that is able to access this object. (Assuming we do
>> not want to have SeTakeOwnershipPrivilege or any ACL-bypassing
>> privileges in the restricted token.)
>
>You might put A as a restricted SID -- nobody is going to check whether a
>SID stands for a group, or for an account.

Oh, thats an idea.To me it looks a bit unorthodox to put user accounts
in the list of groups, but why not :-)


However, I am getting the feeling that I really would like to keep my
existing approach using NtCreateToken. Now I am looking into a way to
catch a token with SeCreateTokenPrivilege. My first (quick)) attempts
have not been that successful. I tried to duplicate the process token
from smss.exe and and impersonate it, which seemed to work fine (no
errors). But afterwards the calling thread still had not enough
privileges and I got some other strange side effects. Maybe this just
happend because I am debugging the thing from inside a Win2003 TS
session. But I am also fearing that MS made the thing really close and
DuplicateTokenEx() silently removes SeCreateTokenPrivilege. I am going
to check this soon.


So long

Daniel

Slava M. Usov

unread,
Jun 30, 2003, 7:03:45 AM6/30/03
to
"Daniel Lohmann" <dan...@uni-koblenz.de> wrote in message
news:p3kqfvsl05vblqn6k...@4ax.com...

[...]

Given the set of your requirements, you can write a custom LSA
authentication package and specify it when calling LsaLogonUser(). The auth.
pack. returns an arbitrary set of groups and privileges to be included in
the token, as well as the TOKEN_USER, so everything you need will happen
quite naturally. Which is more important, it will happen in way supported by
MS.

S


0 new messages