The tokenLib::
library was originaly developed by me for a Shark Cage project at HTWG university. Its purpose was to capture a token of user that is currently using a computer, modify it to add a local group present on the system to only this instance of the token (i.e. without user becoming a member of said group) to allow a certain programs to run with privileges attributed to that group.
Since then, it has been extracted from the project, moved into a standalone open-source project and distributed as a DLL to be used. Now it is possible to add multiple user groups and multiple privileges into a token. However, there are still some drawbacks that need to be addressed as well as some implementation challenges.
The core of the library is a family of functions modifying token. These functions create a token that is exactly the same as the token of a user currently logged to a session that is attached to the physical console, but with selected modifications applied. Modification functions include:
constructUserTokenWithGroup()
: creates a token identical to the one of physical console, with one group addedconstructUserTokenWithMultipleGroups()
: the same as above, but with multiple groupsconstructUserTokenWithMultiplePrivileges()
: the same, but with privileges
The library also includes a set of auxialiary functions design to simplify its use:
aquireTokenWithPrivilegesForTokenManipulation()
: function designed to search the system for token with privileges neccessary to perform privilege manipulationcreateLocalGroup()
,deleteLocalGroup()
,destroySid()
: these functions are a remnant of a time when the library was only used to add groups to the token, they need to stay as a legacy, to not break old projects using this APIs
Expected usage of the library is demonstrated the best in a two process environment (expressed chronologically):
Process 1 (Parent):
- Uses
aquireTokenWithPrivilegesForTokenManipulation()
function to acquire a token with all the needed privileges. - Starts a child process with the acquired token.
Process 2 (Child):
- Creates (or uses one present in the system) a local group(s) or privilege(s) to be added to a token.
- obtains a modified token by invoking some of
constructUserTokenWith...()
functions. - uses the obtained token for whatever it needs to be used.
It is, of course, possible to obtain privileges in Process 2 any other viable way or to skip the two process procedure altogether, if the original process has all necessary privileges.
To use the library and perform token modification, the following criteria must be met:
For token modification family of functions (constructUserTokenWith...()
) to work, the library requires a special set of privileges and conditions to be satisfied:
- the process must hold
SeCreateTokenPrivilege
andSeTcbPrivilege
- the process must run under
LocalSystem
context
To achieve this state, a function aquireTokenWithPrivilegesForTokenManipulation()
was created. It relies on a fact that at least one process in the system satisfies all the conditions needed. It goes through all the processes, finds the satisfactory process, acquires its token and returns a handle to a duplicate of such a process.
To call aquireTokenWithPrivilegesForTokenManipulation()
function, calling process must have SeDebugPrivilege
. Although, this is not a semantic requirement, the process must run under LocalSystem
context, in order to obtain any useful result from the function call. (If not, processes under LocalSystem could not be accessed and aquireTokenWithPrivilegesForTokenManipulation()
will think there are no processes in the system fulfilling all criteria)