You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Okay this ended up being a really long-winded one, but bare me with as I really need to lay down the groundwork first to fully demonstrate my point.
Description
As you are probably well aware, Windows doesn't really have a concept of a "root" user nor have access control directly tied to users per-se, but instead is centered around security descriptors which describe privileges, access control lists and security groups. Processes are then tied with access tokens, which are containers of said descriptors. Access control is then managed by comparing the caller process' access token against different combinations of required privileges and group member-/ownerships depending on the situation.
Case example
For example, there is really no such thing as a "TrustedInstaller" user, but it is instead a "SYSTEM"1 user who is a member (and owner) of the "TrustedInstaller"2group.
Let's say you need to modify securable objects3 which can be modified only by "TrustedInstaller", which many times is the case when you need to customize the operating system be it for your own local installation or when configuring Windows images for deployment using the Windows ADK.
Let's look at the two following privileges:
SeBackupPrivilege
This privilege causes the system to grant all read access control to any file, regardless of the access control list (ACL) specified for the file. ...
SeRestorePrivilege
This privilege causes the system to grant all write access control to any file, regardless of the ACL specified for the file. ...
At a first glance, it seems that having those privileges enabled would do the thing. However, those bypass the ACL only for file operations, but not other ones like modifying registry keys or scheduled tasks, and you will run into a "access denied" error. To be able to have full access to the keys, you need to be a member of the "TrustedInstaller" group and there is no privilege to get around that requirement in every case.
Summary
In summary, to be able to have full access to everything means you need to pass whatever access checks the OS throws at you. Like mentioned before, these are combinations of checks against which privileges and groups the token has. In addition to "grant" access checks, there are also "deny" checks to verify that the token is not a member of a specified group, such as "Guests."4.
Also the different API calls, some of which date back to 1993 (Windows NT 3.1), are not always 100% consistent in their access requirements — as using different versions of essentially the same function residing in different modules, or getting to the same end result with a different set of calls — can have differences in their checks and therefore the access needed5.
There really ought to be a "absolutely bypass every single access check" privilege, but alas, that is not the case.
Even something that sounds like it, SeTcbPrivilege6, doesn't achieve that.
In the spirit of "show, don't tell", let's move on to tests for further demonstration.
Tests
All tests were carried out with gsudo v2.4.0 portable inside an official Windows 11 VM (August 2023) from MSDN of following build:
Windows 11 Enterprise Evaluation
Build 22621.ni_release.220506-1250
First, let's view the privileges and groups we acquire using the SYSTEM option, gsudo -s.
#> gsudo -s whoami /all
> gsudo -s whoami /allERROR: Access is denied.
Right, the default integrity level (High) doesn't match the one needed (System). Let's try again.
#> gsudo -s -i System whoami /all
> gsudo -s -i System whoami /allUSER INFORMATION----------------User Name SID =================== ========nt authority\system S-1-5-18GROUP INFORMATION-----------------Group Name Type SID Attributes ====================================== ================ ============ ==================================================BUILTIN\Administrators Alias S-1-5-32-544 Enabled by default, Enabled group, Group owner Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled groupNT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled groupMandatory Label\System Mandatory Level Label S-1-16-16384 PRIVILEGES INFORMATION----------------------Privilege Name Description State =============================== ============================================= ========SeAssignPrimaryTokenPrivilege Replace a process level token DisabledSeIncreaseQuotaPrivilege Adjust memory quotas for a process DisabledSeTcbPrivilege Act as part of the operating system Enabled SeSecurityPrivilege Manage auditing and security log DisabledSeTakeOwnershipPrivilege Take ownership of files or other objects DisabledSeLoadDriverPrivilege Load and unload device drivers DisabledSeProfileSingleProcessPrivilege Profile single process Enabled SeIncreaseBasePriorityPrivilege Increase scheduling priority Enabled SeCreatePermanentPrivilege Create permanent shared objects Enabled SeBackupPrivilege Back up files and directories DisabledSeRestorePrivilege Restore files and directories DisabledSeShutdownPrivilege Shut down the system DisabledSeDebugPrivilege Debug programs Enabled SeAuditPrivilege Generate security audits Enabled SeSystemEnvironmentPrivilege Modify firmware environment values DisabledSeChangeNotifyPrivilege Bypass traverse checking Enabled SeUndockPrivilege Remove computer from docking station DisabledSeManageVolumePrivilege Perform volume maintenance tasks DisabledSeImpersonatePrivilege Impersonate a client after authentication Enabled SeCreateGlobalPrivilege Create global objects Enabled SeTrustedCredManAccessPrivilege Access Credential Manager as a trusted caller Disabled
Okay, now we're in business. Let's do the same for the TrustedInstaller option, gsudo --ti
#> gsudo --ti whoami /all
> gsudo --ti whoami /allUSER INFORMATION----------------User Name SID =================== ========nt authority\system S-1-5-18GROUP INFORMATION-----------------Group Name Type SID Attributes ====================================== ================ ============================================================== ==================================================Mandatory Label\System Mandatory Level Label S-1-16-16384 Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled groupBUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled groupNT AUTHORITY\SERVICE Well-known group S-1-5-6 Mandatory group, Enabled by default, Enabled groupCONSOLE LOGON Well-known group S-1-2-1 Mandatory group, Enabled by default, Enabled groupNT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled groupNT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled groupNT SERVICE\TrustedInstaller Well-known group S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464 Enabled by default, Enabled group, Group owner LOCAL Well-known group S-1-2-0 Mandatory group, Enabled by default, Enabled groupBUILTIN\Administrators Alias S-1-5-32-544 Enabled by default, Enabled group, Group owner PRIVILEGES INFORMATION----------------------Privilege Name Description State ========================================= ================================================================== ========SeAssignPrimaryTokenPrivilege Replace a process level token DisabledSeLockMemoryPrivilege Lock pages in memory Enabled SeIncreaseQuotaPrivilege Adjust memory quotas for a process DisabledSeTcbPrivilege Act as part of the operating system Enabled SeSecurityPrivilege Manage auditing and security log DisabledSeTakeOwnershipPrivilege Take ownership of files or other objects DisabledSeLoadDriverPrivilege Load and unload device drivers DisabledSeSystemProfilePrivilege Profile system performance Enabled SeSystemtimePrivilege Change the system time DisabledSeProfileSingleProcessPrivilege Profile single process Enabled SeIncreaseBasePriorityPrivilege Increase scheduling priority Enabled SeCreatePagefilePrivilege Create a pagefile Enabled SeCreatePermanentPrivilege Create permanent shared objects Enabled SeBackupPrivilege Back up files and directories DisabledSeRestorePrivilege Restore files and directories DisabledSeShutdownPrivilege Shut down the system DisabledSeDebugPrivilege Debug programs Enabled SeAuditPrivilege Generate security audits Enabled SeSystemEnvironmentPrivilege Modify firmware environment values DisabledSeChangeNotifyPrivilege Bypass traverse checking Enabled SeUndockPrivilege Remove computer from docking station DisabledSeManageVolumePrivilege Perform volume maintenance tasks DisabledSeImpersonatePrivilege Impersonate a client after authentication Enabled SeCreateGlobalPrivilege Create global objects Enabled SeIncreaseWorkingSetPrivilege Increase a process working set Enabled SeTimeZonePrivilege Change the time zone Enabled SeCreateSymbolicLinkPrivilege Create symbolic links Enabled SeDelegateSessionUserImpersonatePrivilege Obtain an impersonation token for another user in the same session Enabled
And then the regular Administrator elevation, gsudo with no parameters.
#> gsudo /whoami all
> gsudo whoami /allUSER INFORMATION----------------User Name SID =================== ============================================windev2308eval\user S-1-5-21-376266693-1981222811-751715727-1000GROUP INFORMATION-----------------Group Name Type SID Attributes ============================================================= ================ ============ ===============================================================Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group NT AUTHORITY\Local account and member of Administrators group Well-known group S-1-5-114 Mandatory group, Enabled by default, Enabled group BUILTIN\Administrators Alias S-1-5-32-544 Mandatory group, Enabled by default, Enabled group, Group ownerBUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group BUILTIN\Performance Log Users Alias S-1-5-32-559 Mandatory group, Enabled by default, Enabled group NT AUTHORITY\INTERACTIVE Well-known group S-1-5-4 Mandatory group, Enabled by default, Enabled group CONSOLE LOGON Well-known group S-1-2-1 Mandatory group, Enabled by default, Enabled group NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group NT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled group NT AUTHORITY\Local account Well-known group S-1-5-113 Mandatory group, Enabled by default, Enabled group LOCAL Well-known group S-1-2-0 Mandatory group, Enabled by default, Enabled group NT AUTHORITY\NTLM Authentication Well-known group S-1-5-64-10 Mandatory group, Enabled by default, Enabled group Mandatory Label\High Mandatory Level Label S-1-16-12288 PRIVILEGES INFORMATION----------------------Privilege Name Description State ========================================= ================================================================== ========SeIncreaseQuotaPrivilege Adjust memory quotas for a process DisabledSeSecurityPrivilege Manage auditing and security log DisabledSeTakeOwnershipPrivilege Take ownership of files or other objects DisabledSeLoadDriverPrivilege Load and unload device drivers DisabledSeSystemProfilePrivilege Profile system performance DisabledSeSystemtimePrivilege Change the system time DisabledSeProfileSingleProcessPrivilege Profile single process DisabledSeIncreaseBasePriorityPrivilege Increase scheduling priority DisabledSeCreatePagefilePrivilege Create a pagefile DisabledSeBackupPrivilege Back up files and directories DisabledSeRestorePrivilege Restore files and directories DisabledSeShutdownPrivilege Shut down the system DisabledSeDebugPrivilege Debug programs Enabled SeSystemEnvironmentPrivilege Modify firmware environment values DisabledSeChangeNotifyPrivilege Bypass traverse checking Enabled SeRemoteShutdownPrivilege Force shutdown from a remote system DisabledSeUndockPrivilege Remove computer from docking station DisabledSeManageVolumePrivilege Perform volume maintenance tasks DisabledSeImpersonatePrivilege Impersonate a client after authentication Enabled SeCreateGlobalPrivilege Create global objects Enabled SeIncreaseWorkingSetPrivilege Increase a process working set DisabledSeTimeZonePrivilege Change the time zone DisabledSeCreateSymbolicLinkPrivilege Create symbolic links DisabledSeDelegateSessionUserImpersonatePrivilege Obtain an impersonation token for another user in the same session Disabled
And finally in the unelevated command prompt, without gsudo.
#> whoami /all
> whoami /allUSER INFORMATION----------------User Name SID =================== ============================================windev2308eval\user S-1-5-21-376266693-1981222811-751715727-1000GROUP INFORMATION-----------------Group Name Type SID Attributes ============================================================= ================ ============ ==================================================Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled groupNT AUTHORITY\Local account and member of Administrators group Well-known group S-1-5-114 Group used for deny only BUILTIN\Administrators Alias S-1-5-32-544 Group used for deny only BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled groupBUILTIN\Performance Log Users Alias S-1-5-32-559 Mandatory group, Enabled by default, Enabled groupNT AUTHORITY\INTERACTIVE Well-known group S-1-5-4 Mandatory group, Enabled by default, Enabled groupCONSOLE LOGON Well-known group S-1-2-1 Mandatory group, Enabled by default, Enabled groupNT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled groupNT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled groupNT AUTHORITY\Local account Well-known group S-1-5-113 Mandatory group, Enabled by default, Enabled groupLOCAL Well-known group S-1-2-0 Mandatory group, Enabled by default, Enabled groupNT AUTHORITY\NTLM Authentication Well-known group S-1-5-64-10 Mandatory group, Enabled by default, Enabled groupMandatory Label\Medium Mandatory Level Label S-1-16-8192 PRIVILEGES INFORMATION----------------------Privilege Name Description State ============================= ==================================== ========SeShutdownPrivilege Shut down the system DisabledSeChangeNotifyPrivilege Bypass traverse checking Enabled SeUndockPrivilege Remove computer from docking station DisabledSeIncreaseWorkingSetPrivilege Increase a process working set DisabledSeTimeZonePrivilege Change the time zone Disabled
See those outputs and the differences between them. To further understand the issue here, let's move on to the next part.
The Problem
So we've now talked about how access is controlled by privileges and groups, both of which are contained inside the access token.
The process executing the commands, in this case cmd.exe, has the access token which the sub-process of whoami.exe then inherits and prints the information about the token. The key insight here is that no matter what you are doing, access token is the key.
Comparing the outputs of tests above, we can see how each of them have differing amounts of access. While the integrity level is straight-forward, being either higher or lower; not so much for the groups and privileges.
You can see that while the regular admin elevation is a straight-up upgrade, the SYSTEM and TrustedInstaller options are not. Losing some groups and privileges while gaining others makes using gsudo -s and gsudo --ti options win some, lose some situations.
Furthermore, you can see that not only are many of the privileges disabled, some of them don't even exist in some but do in others.
What's up with that? Well, that brings us to another problem we need to tackle.
Basically, the bouncer at the door checks whether you have a full glass of water, and you can empty or fill up a glass, but you can't fill up a glass which you don't already have.
When access tokens are created, they are assigned privileges which can either be enabled or disabled.
But you cannot add new privileges to an existing token. So when we need additional privileges, enabling existing privileges isn't enough.
The Goal
If you are still reading, kudos to you.
As all of this seems rather complicated and so far we've only added layers of problems on top of another, let's define our goal.
To summarize, these are the components we're working with
a) the integrity level (single, ranging from "low" to "system")
b) sets of different privileges (multiple; can be either enabled/disabled)
c) group memberships (multiple; with attributes enabled, deny-only, owner)
What do we want?
Obviously in a true sudo fashion, all of them.
a) highest integrity level, "system"
b) all privileges, each of them enabled
c) all "good" groups like Administrators, but not the bad ones like Guests
That might seem like a tall order because of the many roadblocks like not being able to enable existing privileges or add new groups when we don't have the privileges to do that, not to mention that adding new privileges can't be done.
There is also some further complexity when it comes to traversing the boundaries between integrity levels, and there also are different types of access tokens like impersonation tokens and then impersonation levels in regards to those, but we'll skip that for now.
For all of these problems, fortunately a rather simple and almost perfect solution exists. Let's finally explore that.
The Solution
So now you understand the problem, and here is the solution.
Presenting the backstage pass, all-you-can-eat combo deal, diplomatic passport equivalent of access tokens – the all-access token.
As we determined that the hardest problem is not being able to add privileges to an existing token, the solution is rather simple – we simply create a new one.
Again in both the spirit of "show, don't tell", and because the technical explanation would take forever in a post that is already too long, I have prepared a working code example in lieu of more words.
And now let's see the output of sudo /whoami all
#> sudo /whoami all
> sudo whoami /allUSER INFORMATION----------------User Name SID =================== ========nt authority\system S-1-5-18GROUP INFORMATION-----------------Group Name Type SID Attributes ============================================================= ================ ============================================================== ===============================================================Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group LOCAL Well-known group S-1-2-0 Mandatory group, Enabled by default, Enabled group, Group ownerCONSOLE LOGON Well-known group S-1-2-1 Mandatory group, Enabled by default, Enabled group NT AUTHORITY\INTERACTIVE Well-known group S-1-5-4 Mandatory group, Enabled by default, Enabled group NT AUTHORITY\SERVICE Well-known group S-1-5-6 Mandatory group, Enabled by default, Enabled group NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group NT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled group NT AUTHORITY\Local account Well-known group S-1-5-113 Mandatory group, Enabled by default, Enabled group NT AUTHORITY\Local account and member of Administrators group Well-known group S-1-5-114 Mandatory group, Enabled by default, Enabled group BUILTIN\Administrators Alias S-1-5-32-544 Mandatory group, Enabled by default, Enabled group, Group ownerBUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group, Group ownerNT AUTHORITY\NTLM Authentication Well-known group S-1-5-64-10 Mandatory group, Enabled by default, Enabled group NT SERVICE\TrustedInstaller Well-known group S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464 Enabled by default, Enabled group, Group owner BUILTIN\Backup Operators Alias S-1-5-32-551 Mandatory group, Enabled by default, Enabled group, Group ownerBUILTIN\Network Configuration Operators Alias S-1-5-32-556 Mandatory group, Enabled by default, Enabled group, Group ownerBUILTIN\Performance Log Users Alias S-1-5-32-559 Mandatory group, Enabled by default, Enabled group, Group ownerBUILTIN\Distributed COM Users Alias S-1-5-32-562 Mandatory group, Enabled by default, Enabled group, Group ownerBUILTIN\Cryptographic Operators Alias S-1-5-32-569 Mandatory group, Enabled by default, Enabled group, Group ownerBUILTIN\Event Log Readers Alias S-1-5-32-573 Mandatory group, Enabled by default, Enabled group, Group ownerBUILTIN\Hyper-V Administrators Alias S-1-5-32-578 Mandatory group, Enabled by default, Enabled group, Group ownerBUILTIN\System Managed Accounts Group Alias S-1-5-32-581 Mandatory group, Enabled by default, Enabled group, Group ownerBUILTIN\Device Owners Alias S-1-5-32-583 Mandatory group, Enabled by default, Enabled group, Group ownerMandatory Label\System Mandatory Level Label S-1-16-16384 PRIVILEGES INFORMATION----------------------Privilege Name Description State ========================================= ================================================================== =======SeCreateTokenPrivilege Create a token object EnabledSeAssignPrimaryTokenPrivilege Replace a process level token EnabledSeLockMemoryPrivilege Lock pages in memory EnabledSeIncreaseQuotaPrivilege Adjust memory quotas for a process EnabledSeMachineAccountPrivilege Add workstations to domain EnabledSeTcbPrivilege Act as part of the operating system EnabledSeSecurityPrivilege Manage auditing and security log EnabledSeTakeOwnershipPrivilege Take ownership of files or other objects EnabledSeLoadDriverPrivilege Load and unload device drivers EnabledSeSystemProfilePrivilege Profile system performance EnabledSeSystemtimePrivilege Change the system time EnabledSeProfileSingleProcessPrivilege Profile single process EnabledSeIncreaseBasePriorityPrivilege Increase scheduling priority EnabledSeCreatePagefilePrivilege Create a pagefile EnabledSeCreatePermanentPrivilege Create permanent shared objects EnabledSeBackupPrivilege Back up files and directories EnabledSeRestorePrivilege Restore files and directories EnabledSeShutdownPrivilege Shut down the system EnabledSeDebugPrivilege Debug programs EnabledSeAuditPrivilege Generate security audits EnabledSeSystemEnvironmentPrivilege Modify firmware environment values EnabledSeChangeNotifyPrivilege Bypass traverse checking EnabledSeRemoteShutdownPrivilege Force shutdown from a remote system EnabledSeUndockPrivilege Remove computer from docking station EnabledSeSyncAgentPrivilege Synchronize directory service data EnabledSeEnableDelegationPrivilege Enable computer and user accounts to be trusted for delegation EnabledSeManageVolumePrivilege Perform volume maintenance tasks EnabledSeImpersonatePrivilege Impersonate a client after authentication EnabledSeCreateGlobalPrivilege Create global objects EnabledSeTrustedCredManAccessPrivilege Access Credential Manager as a trusted caller EnabledSeRelabelPrivilege Modify an object label EnabledSeIncreaseWorkingSetPrivilege Increase a process working set EnabledSeTimeZonePrivilege Change the time zone EnabledSeCreateSymbolicLinkPrivilege Create symbolic links EnabledSeDelegateSessionUserImpersonatePrivilege Obtain an impersonation token for another user in the same session Enabled
As you can see, we have successfully added and enabled every privilege in existence, along with the most important well-known groups and thrown in some additional ones for good measure.
Adding the TrustedInstaller group to the token instead of loaning it from the trustedinstaller.exe process also saves the step of needing to start the trustedinstaller service as we don't need the process anymore is also a plus.
As to why this solution isn't perfect, points back to the fact we started with regarding to access control defined by groups. We can enable all access related to privileges, but it's possible to configure the OS with any combinations of groups and accesses related to them and as such it's infeasible to cover every possible configuration without coloring outside the lines and resorting to dirty hacks. But this should cover most of the typical setups, and those people who have made their unique configurations would already know how to deal with the specifics of them.
For the general user, this should cover pretty much everything, no matter the version or edition from Vista to 11 and the Server counterparts of them. Granted I've only tested this on Windows 7 Ultimate, Windows Server 2012 R2, Windows 10 Home and Windows 11 Enterprise but it should work for all the other ones too, along with 99% of whatever use-cases without running into a "access denied" error.
This is probably the closest you can get to a true "root" user in Windows in a clean manner using existing APIs without hacking, modifying, bypassing or exploiting anything. In essence it's simply a matter of piecing together the correct configuration for the highest level of access, which to be frank is unnecessarily complex, but in the end it all comes together after figuring it out.
Proposed technical details
Use the techniques as shown in the winsudo example.
Glossing over the specifics, here is the rundown:
Elevate to Admin if necessary
Elevate to SYSTEM
Create a new all-access token
a) Copy the attributes of the existing token as a base
b) Add all privileges to it as enabled (tkp_all in the example)
c) Add "good" groups which are guaranteed to exist, with attributes mandatory/enabled/owner where applicable (tkg_good in the example)
d) Add "extra" groups which might or might not exist depending on version and edition of Windows by checking their existence first (tkg_xtra in the example)
e) Modify existing groups, remove deny-only attribute and add enabled attribute wherever applicable
If creation of all-access token fails, fall back to existing method of loaning the system token from another process or starting the trustedinstaller service if needed
That's all folks
The code example does work stand-alone and can be used as-is, but it really is a condensed small application of just the sudo functionality needed without any fancy features of this project like a proper pseudo-terminal, terminal detection, configuration options, etc. So absorbing the core functionality from that to this project would result in a best-in-slot sudo solution.
I see the project uses both .NET and PowerShell, which are kinda the same thing after all in many ways.
As you can call native functions from .NET like you already do, all of the C example code can be transferred to .NET / PS.
If you want it to be faster, another idea could be to keep all the native code in C and compile it as a DLL exporting a function call to "Elevate()" or whatever, then including the DLL in the .NET project as a resource and then using the FindResource / LoadResource / LockResource APIs to load the DLL from a resource to memory and then call the exported function from .NET.
Well, I don't think this fulfills the "concise" rule of creating issues, but I'm not sure I could've explained it properly in any other way. Sorry about that 😅
For example — a) saving a registry key to a file using RegSaveKey or b) querying a registry key with RegQueryValueEx and then saving the result to a file — achieve the same end result, but are different operations requiring different levels of access. ↩
SeTcbPrivilege: "Act as part of the operating system" ↩
The text was updated successfully, but these errors were encountered:
Wow thank you so much for this! This is a incredibly helpfull. I've desired to learn how to create tokens from scratch for so much time, but since I don't monetize gsudo I must focus on other work streams. I've thought of doing something like this in the TokenProvider class class. If we could craft the token there, it is gracefully used in the "token switch".
There is a but... gsudo is intended to be a convenience security tool. We have to consider the overall impact on system security, as we don't want gsudo to be flagged as a malware toolkit by Microsoft or AV vendors. Therefore, we need to be cautious about which features to include in its scope.
I'll give it some thought and circle back to this issue when I have more time.
Okay this ended up being a really long-winded one, but bare me with as I really need to lay down the groundwork first to fully demonstrate my point.
Description
As you are probably well aware, Windows doesn't really have a concept of a "root" user nor have access control directly tied to users per-se, but instead is centered around security descriptors which describe privileges, access control lists and security groups. Processes are then tied with access tokens, which are containers of said descriptors. Access control is then managed by comparing the caller process' access token against different combinations of required privileges and group member-/ownerships depending on the situation.
Case example
For example, there is really no such thing as a "TrustedInstaller" user, but it is instead a "SYSTEM"1 user who is a member (and owner) of the "TrustedInstaller"2 group.
Let's say you need to modify securable objects3 which can be modified only by "TrustedInstaller", which many times is the case when you need to customize the operating system be it for your own local installation or when configuring Windows images for deployment using the Windows ADK.
Let's look at the two following privileges:
SeBackupPrivilege
SeRestorePrivilege
At a first glance, it seems that having those privileges enabled would do the thing. However, those bypass the ACL only for file operations, but not other ones like modifying registry keys or scheduled tasks, and you will run into a "access denied" error. To be able to have full access to the keys, you need to be a member of the "TrustedInstaller" group and there is no privilege to get around that requirement in every case.
Summary
In summary, to be able to have full access to everything means you need to pass whatever access checks the OS throws at you. Like mentioned before, these are combinations of checks against which privileges and groups the token has. In addition to "grant" access checks, there are also "deny" checks to verify that the token is not a member of a specified group, such as "Guests."4.
Also the different API calls, some of which date back to 1993 (Windows NT 3.1), are not always 100% consistent in their access requirements — as using different versions of essentially the same function residing in different modules, or getting to the same end result with a different set of calls — can have differences in their checks and therefore the access needed5.
There really ought to be a "absolutely bypass every single access check" privilege, but alas, that is not the case.
Even something that sounds like it, SeTcbPrivilege6, doesn't achieve that.
In the spirit of "show, don't tell", let's move on to tests for further demonstration.
Tests
All tests were carried out with gsudo v2.4.0 portable inside an official Windows 11 VM (August 2023) from MSDN of following build:
First, let's view the privileges and groups we acquire using the SYSTEM option,
gsudo -s
.#> gsudo -s whoami /all
Right, the default integrity level (High) doesn't match the one needed (System). Let's try again.
#> gsudo -s -i System whoami /all
Okay, now we're in business. Let's do the same for the TrustedInstaller option,
gsudo --ti
#> gsudo --ti whoami /all
And then the regular Administrator elevation,
gsudo
with no parameters.#> gsudo /whoami all
And finally in the unelevated command prompt, without gsudo.
#> whoami /all
See those outputs and the differences between them. To further understand the issue here, let's move on to the next part.
The Problem
So we've now talked about how access is controlled by privileges and groups, both of which are contained inside the access token.
The process executing the commands, in this case
cmd.exe
, has the access token which the sub-process ofwhoami.exe
then inherits and prints the information about the token. The key insight here is that no matter what you are doing, access token is the key.Comparing the outputs of tests above, we can see how each of them have differing amounts of access. While the integrity level is straight-forward, being either higher or lower; not so much for the groups and privileges.
You can see that while the regular admin elevation is a straight-up upgrade, the SYSTEM and TrustedInstaller options are not. Losing some groups and privileges while gaining others makes using
gsudo -s
andgsudo --ti
options win some, lose some situations.Furthermore, you can see that not only are many of the privileges disabled, some of them don't even exist in some but do in others.
What's up with that? Well, that brings us to another problem we need to tackle.
Basically, the bouncer at the door checks whether you have a full glass of water, and you can empty or fill up a glass, but you can't fill up a glass which you don't already have.
When access tokens are created, they are assigned privileges which can either be enabled or disabled.
But you cannot add new privileges to an existing token. So when we need additional privileges, enabling existing privileges isn't enough.
The Goal
If you are still reading, kudos to you.
As all of this seems rather complicated and so far we've only added layers of problems on top of another, let's define our goal.
To summarize, these are the components we're working with
a) the integrity level (single, ranging from "low" to "system")
b) sets of different privileges (multiple; can be either enabled/disabled)
c) group memberships (multiple; with attributes enabled, deny-only, owner)
What do we want?
Obviously in a true sudo fashion, all of them.
a) highest integrity level, "system"
b) all privileges, each of them enabled
c) all "good" groups like Administrators, but not the bad ones like Guests
That might seem like a tall order because of the many roadblocks like not being able to enable existing privileges or add new groups when we don't have the privileges to do that, not to mention that adding new privileges can't be done.
There is also some further complexity when it comes to traversing the boundaries between integrity levels, and there also are different types of access tokens like impersonation tokens and then impersonation levels in regards to those, but we'll skip that for now.
For all of these problems, fortunately a rather simple and almost perfect solution exists. Let's finally explore that.
The Solution
So now you understand the problem, and here is the solution.
Presenting the backstage pass, all-you-can-eat combo deal, diplomatic passport equivalent of access tokens – the all-access token.
As we determined that the hardest problem is not being able to add privileges to an existing token, the solution is rather simple – we simply create a new one.
Again in both the spirit of "show, don't tell", and because the technical explanation would take forever in a post that is already too long, I have prepared a working code example in lieu of more words.
And now let's see the output of
sudo /whoami all
#> sudo /whoami all
As you can see, we have successfully added and enabled every privilege in existence, along with the most important well-known groups and thrown in some additional ones for good measure.
Adding the TrustedInstaller group to the token instead of loaning it from the trustedinstaller.exe process also saves the step of needing to start the trustedinstaller service as we don't need the process anymore is also a plus.
As to why this solution isn't perfect, points back to the fact we started with regarding to access control defined by groups. We can enable all access related to privileges, but it's possible to configure the OS with any combinations of groups and accesses related to them and as such it's infeasible to cover every possible configuration without coloring outside the lines and resorting to dirty hacks. But this should cover most of the typical setups, and those people who have made their unique configurations would already know how to deal with the specifics of them.
For the general user, this should cover pretty much everything, no matter the version or edition from Vista to 11 and the Server counterparts of them. Granted I've only tested this on Windows 7 Ultimate, Windows Server 2012 R2, Windows 10 Home and Windows 11 Enterprise but it should work for all the other ones too, along with 99% of whatever use-cases without running into a "access denied" error.
This is probably the closest you can get to a true "root" user in Windows in a clean manner using existing APIs without hacking, modifying, bypassing or exploiting anything. In essence it's simply a matter of piecing together the correct configuration for the highest level of access, which to be frank is unnecessarily complex, but in the end it all comes together after figuring it out.
Proposed technical details
Use the techniques as shown in the winsudo example.
Glossing over the specifics, here is the rundown:
a) Copy the attributes of the existing token as a base
b) Add all privileges to it as enabled (tkp_all in the example)
c) Add "good" groups which are guaranteed to exist, with attributes mandatory/enabled/owner where applicable (tkg_good in the example)
d) Add "extra" groups which might or might not exist depending on version and edition of Windows by checking their existence first (tkg_xtra in the example)
e) Modify existing groups, remove deny-only attribute and add enabled attribute wherever applicable
The code example does work stand-alone and can be used as-is, but it really is a condensed small application of just the sudo functionality needed without any fancy features of this project like a proper pseudo-terminal, terminal detection, configuration options, etc. So absorbing the core functionality from that to this project would result in a best-in-slot sudo solution.
I see the project uses both .NET and PowerShell, which are kinda the same thing after all in many ways.
As you can call native functions from .NET like you already do, all of the C example code can be transferred to .NET / PS.
If you want it to be faster, another idea could be to keep all the native code in C and compile it as a DLL exporting a function call to "Elevate()" or whatever, then including the DLL in the .NET project as a resource and then using the FindResource / LoadResource / LockResource APIs to load the DLL from a resource to memory and then call the exported function from .NET.
Well, I don't think this fulfills the "concise" rule of creating issues, but I'm not sure I could've explained it properly in any other way. Sorry about that 😅
Footnotes
SYSTEM User SID S-1-5-18 ↩
TrustedInstaller Group SID S-1-5-80-956008885-3418522649-1831038044-1853292631-2271478464 ↩
Securable objects can be files, registry keys, services, processes, jobs, etc. ↩
Guests Group SID S-1-5-32-546 ↩
For example — a) saving a registry key to a file using RegSaveKey or b) querying a registry key with RegQueryValueEx and then saving the result to a file — achieve the same end result, but are different operations requiring different levels of access. ↩
SeTcbPrivilege: "Act as part of the operating system" ↩
The text was updated successfully, but these errors were encountered: