Post

On Disabled Windows Privileges

On a recent video someone asked a good question in the comments about why we can shutdown a box when our user has SeShutdownPrivilege listed as disabled:

1
2
3
4
5
6
7
8
9
whoami /all
...
Privilege Name                Description                          State
============================= ==================================== ========
SeShutdownPrivilege           Shut down the system                 Disabled
SeChangeNotifyPrivilege       Bypass traverse checking             Enabled
SeUndockPrivilege             Remove computer from docking station Disabled
SeIncreaseWorkingSetPrivilege Increase a process working set       Disabled
SeTimeZonePrivilege           Change the time zone                 Disabled

As with all of these Privileges, disabling them does not actually prevent the user from using them – it is just supposed to prevent accidental misuse. The idea is that you have to explicitly enable them again in code in order to use them.

Let’s confirm that for SeShutdownPrivilege using C++:

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <windows.h>

#pragma comment(lib, "user32.lib")

int main()
{
    bool result = ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER);
    if (!result) {
        std::cout << "Shutdown failed!" << std::endl;
    }
}
1
2
C:\Users\xct\source\repos\TokenPrivileges\x64\Release>TokenPrivileges.exe
Shutdown failed!

We can however enable that privilege using AdjustTokenPrivileges:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
#include <windows.h>

#pragma comment(lib, "user32.lib")
#pragma comment(lib, "advapi32.lib")

int main()
{
    HANDLE hToken;
    TOKEN_PRIVILEGES tkp;

    OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken); // get token for current process
    LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid); // get LUID for shutdown priv
    tkp.PrivilegeCount = 1;  // change 1 priv
    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // set it to enabled
    AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0); // adjust privilege

    bool result = ExitWindowsEx(EWX_REBOOT, SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER);
    if (!result) {
        std::cout << "Shutdown failed!" << std::endl;
    }
}

Now the shutdown is possible. So to summarize, shutting down a box with SeShutdownPrivilege disabled is possible because “shutdown.exe” is using AdjustTokenPrivileges to enable the Privilege before calling the required Windows API function. As for other Privileges, you can follow the same methodology to enable & use them.

This post is licensed under CC BY 4.0 by the author.