Skip to content

Windows User Privileges

Windows Authorization Process

Windows Authorization Process in a nugshell:  the process started when a user attempts to access a securable object such as a folder on a file share. During this process, the user's access token (including their user SID, SIDs for any groups they are members of, privilege list, and other access information) is compared against Access Control Entries (ACEs) within the object's security descriptor (which contains security information about a securable object such as access rights (discussed below) granted to users or groups). Once this comparison is complete, a decision is made to either grant or deny access. This entire process happens almost instantaneously whenever a user tries to access a resource on a Windows host. As part of our enumeration and privilege escalation activities, we attempt to use and abuse access rights and leverage or insert ourselves into this authorization process to further our access towards our goal.

Rights and Privileges in Windows

Group Description
Default Administrators Domain Admins and Enterprise Admins are "super" groups.
Server Operators Members can modify services, access SMB shares, and backup files.
Backup Operators Members are allowed to log onto DCs locally and should be considered Domain Admins. They can make shadow copies of the SAM/NTDS database, read the registry remotely, and access the file system on the DC via SMB. This group is sometimes added to the local Backup Operators group on non-DCs.
Print Operators Members can log on to DCs locally and "trick" Windows into loading a malicious driver.
Hyper-V Administrators If there are virtual DCs, any virtualization admins, such as members of Hyper-V Administrators, should be considered Domain Admins.
Account Operators Members can modify non-protected accounts and groups in the domain.
Remote Desktop Users Members are not given any useful permissions by default but are often granted additional rights such as Allow Login Through Remote Desktop Services and can move laterally using the RDP protocol.
Remote Management Users Members can log on to DCs with PSRemoting (This group is sometimes added to the local remote management group on non-DCs).
Group Policy Creator Owners Members can create new GPOs but would need to be delegated additional permissions to link GPOs to a container such as a domain or OU.
Schema Admins Members can modify the Active Directory schema structure and backdoor any to-be-created Group/GPO by adding a compromised account to the default object ACL.
DNS Admins Members can load a DLL on a DC, but do not have the necessary permissions to restart the DNS server. They can load a malicious DLL and wait for a reboot as a persistence mechanism. Loading a DLL will often result in the service crashing. A more reliable way to exploit this group is to create a W

Depending on group membership, and other factors such as privileges assigned via domain and local Group Policy, users can have various rights assigned to their account.

Setting Constant Setting Name Standard Assignment Description
SeNetworkLogonRight Access this computer from the network Administrators, Authenticated Users Determines which users can connect to the device from the network. This is required by network protocols such as SMB, NetBIOS, CIFS, and COM+.
SeRemoteInteractiveLogonRight Allow log on through Remote Desktop Services Administrators, Remote Desktop Users This policy setting determines which users or groups can access the login screen of a remote device through a Remote Desktop Services connection. A user can establish a Remote Desktop Services connection to a particular server but not be able to log on to the console of that same server.
SeBackupPrivilege Back up files and directories Administrators This user right determines which users can bypass file and directory, registry, and other persistent object permissions for the purposes of backing up the system.
SeSecurityPrivilege Manage auditing and security log Administrators This policy setting determines which users can specify object access audit options for individual resources such as files, Active Directory objects, and registry keys. These objects specify their system access control lists (SACL). A user assigned this user right can also view and clear the Security log in Event Viewer.
SeTakeOwnershipPrivilege Take ownership of files or other objects Administrators This policy setting determines which users can take ownership of any securable object in the device, including Active Directory objects, NTFS files and folders, printers, registry keys, services, processes, and threads.
SeDebugPrivilege Debug programs Administrators This policy setting determines which users can attach to or open any process, even a process they do not own. Developers who are debugging their applications do not need this user right. Developers who are debugging new system components need this user right. This user right provides access to sensitive and critical operating system components.
SeImpersonatePrivilege Impersonate a client after authentication Administrators, Local Service, Network Service, Service This policy setting determines which programs are allowed to impersonate a user or another specified account and act on behalf of the user.
SeLoadDriverPrivilege Load and unload device drivers Administrators This policy setting determines which users can dynamically load and unload device drivers. This user right is not required if a signed driver for the new hardware already exists in the driver.cab file on the device. Device drivers run as highly privileged code.
SeRestorePrivilege Restore files and directories Administrators This security setting determines which users can bypass file, directory, registry, and other persistent object permissions when they restore backed up files and directories. It determines which users can set valid security principals as the owner of an object.

What are my privileges?

whoami /priv

Some rights are only available to administrative users and can only be listed/leveraged when running an elevated cmd or PowerShell session.

When a privilege is listed for our account in the Disabled state, it means that our account has the specific privilege assigned. Still, it cannot be used in an access token to perform the associated actions until it is enabled.

Enable a privilege: alternative #1

Windows does not provide a built-in command or PowerShell cmdlet to enable privileges, so we need some scripting to help us out.

See PoshPrivilege: Scripts/Enable-Privilege.ps1:

Function Enable-Privilege {  
    <#  
        .SYNOPSIS  
            Enables specific privilege or privileges on the current process.  

        .DESCRIPTION  
            Enables specific privilege or privileges on the current process.  
          
        .PARAMETER Privilege  
            Specific privilege/s to enable on the current process  
          
        .NOTES  
            Name: Enable-Privilege  
            Author: Boe Prox  
            Version History:  
                1.0 - Initial Version  

        .EXAMPLE  
        Enable-Privilege -Privilege SeBackupPrivilege  

        Description  
        -----------  
        Enables the SeBackupPrivilege on the existing process  

        .EXAMPLE  
        Enable-Privilege -Privilege SeBackupPrivilege, SeRestorePrivilege, SeTakeOwnershipPrivilege  

        Description  
        -----------  
        Enables the SeBackupPrivilege, SeRestorePrivilege and SeTakeOwnershipPrivilege on the existing process  
          
    #>  
    [cmdletbinding(  
        SupportsShouldProcess = $True  
    )]  
    Param (  
        [parameter(Mandatory = $True)]  
        [Privileges[]]$Privilege  
    )      
    If ($PSCmdlet.ShouldProcess("Process ID: $PID", "Enable Privilege(s): $($Privilege -join ', ')")) {  
        #region Constants  
        $SE_PRIVILEGE_ENABLED = 0x00000002  
        $SE_PRIVILEGE_DISABLED = 0x00000000  
        $TOKEN_QUERY = 0x00000008  
        $TOKEN_ADJUST_PRIVILEGES = 0x00000020  
        #endregion Constants  

        $TokenPriv = New-Object TokPriv1Luid  
        $HandleToken = [intptr]::Zero  
        $TokenPriv.Count = 1  
        $TokenPriv.Attr = $SE_PRIVILEGE_ENABLED  
      
        #Open the process token  
        $Return = [PoshPrivilege]::OpenProcessToken(  
            [PoshPrivilege]::GetCurrentProcess(),  
            ($TOKEN_QUERY -BOR $TOKEN_ADJUST_PRIVILEGES),   
            [ref]$HandleToken  
        )      
        If (-NOT $Return) {  
            Write-Warning "Unable to open process token! Aborting!"  
            Break  
        }  
        ForEach ($Priv in $Privilege) {  
            $PrivValue = $Null  
            $TokenPriv.Luid = 0  
            #Lookup privilege value  
            $Return = [PoshPrivilege]::LookupPrivilegeValue($Null, $Priv, [ref]$PrivValue)               
            If ($Return) {  
                $TokenPriv.Luid = $PrivValue  
                #Adjust the process privilege value  
                $return = [PoshPrivilege]::AdjustTokenPrivileges(  
                    $HandleToken,   
                    $False,   
                    [ref]$TokenPriv,   
                    [System.Runtime.InteropServices.Marshal]::SizeOf($TokenPriv),   
                    [IntPtr]::Zero,   
                    [IntPtr]::Zero  
                )  
                If (-NOT $Return) {  
                    Write-Warning "Unable to enable privilege <$priv>! "  
                }  
            }  
        }  
    }  
}

Enable a privilege: alternative #2

Another script for enabling privileges from: https://www.leeholmes.com/adjusting-token-privileges-in-powershell/

param(    ## The privilege to adjust. This set is taken from
    ## http://msdn.microsoft.com/en-us/library/bb530716(VS.85).aspx

    [ValidateSet(
        "SeAssignPrimaryTokenPrivilege", "SeAuditPrivilege", "SeBackupPrivilege",
        "SeChangeNotifyPrivilege", "SeCreateGlobalPrivilege", "SeCreatePagefilePrivilege",
        "SeCreatePermanentPrivilege", "SeCreateSymbolicLinkPrivilege", "SeCreateTokenPrivilege",
        "SeDebugPrivilege", "SeEnableDelegationPrivilege", "SeImpersonatePrivilege", "SeIncreaseBasePriorityPrivilege",
        "SeIncreaseQuotaPrivilege", "SeIncreaseWorkingSetPrivilege", "SeLoadDriverPrivilege",
        "SeLockMemoryPrivilege", "SeMachineAccountPrivilege", "SeManageVolumePrivilege",
        "SeProfileSingleProcessPrivilege", "SeRelabelPrivilege", "SeRemoteShutdownPrivilege",
        "SeRestorePrivilege", "SeSecurityPrivilege", "SeShutdownPrivilege", "SeSyncAgentPrivilege",
        "SeSystemEnvironmentPrivilege", "SeSystemProfilePrivilege", "SeSystemtimePrivilege",
        "SeTakeOwnershipPrivilege", "SeTcbPrivilege", "SeTimeZonePrivilege", "SeTrustedCredManAccessPrivilege",
        "SeUndockPrivilege", "SeUnsolicitedInputPrivilege")]
    $Privilege,

    ## The process on which to adjust the privilege. Defaults to the current process.
    $ProcessId = $pid,

    ## Switch to disable the privilege, rather than enable it.
    [Switch] $Disable
)

## Taken from P/Invoke.NET with minor adjustments.
$definition = @'
using System;

using System.Runtime.InteropServices;
public class AdjPriv
{
    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
        ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);

    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);

    [DllImport("advapi32.dll", SetLastError = true)]
    internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct TokPriv1Luid
    {
        public int Count;
        public long Luid;
        public int Attr;
    }

    internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
    internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
    internal const int TOKEN_QUERY = 0x00000008;
    internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;

    public static bool EnablePrivilege(long processHandle, string privilege, bool disable)
    {
        bool retVal;
        TokPriv1Luid tp;
        IntPtr hproc = new IntPtr(processHandle);
        IntPtr htok = IntPtr.Zero;
        retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
        tp.Count = 1;
        tp.Luid = 0;

        if(disable)
        {
            tp.Attr = SE_PRIVILEGE_DISABLED;
        }
        else
        {
            tp.Attr = SE_PRIVILEGE_ENABLED;
        }

        retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
        retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
        return retVal;
    }
}
'@

$processHandle = (Get-Process -id $ProcessId).Handle
$type = Add-Type $definition -PassThru
$type[0]::EnablePrivilege($processHandle, $Privilege, $Disable)

🤷 Abusing SeImpersonate and SeAssignPrimaryToken

In Windows, every process has a token that has information about the account that is running it. These tokens are not considered secure resources, as they are just locations within memory.

To utilize the token, the SeImpersonate privilege is needed.  It is only given to administrative accounts.

We will often run into this privilege after gaining remote code execution via an application that runs in the context of a service account.

List our privileges

whoami /priv

If the command whoami /priv confirms that SeImpersonatePrivilege is listed, we may use it to impersonate a privileged account such as NT AUTHORITY\SYSTEM.

For that there are several tools such as JuicyPotatoPrintSpoofer, or RoguePotato to escalate to SYSTEM level privileges, depending on the target host.

🥔 JuicyPotato: SeImpersonate or SeAssignPrimaryToken

RottenPotatoNG and its variants leverages the privilege escalation chain based on BITS service having the MiTM listener on 127.0.0.1:6666 and when you have SeImpersonate or SeAssignPrimaryToken privileges. During a Windows build review we found a setup where BITS was intentionally disabled and port 6666 was taken.

See more on JuicyPotato

🖨️ PrintNightmare

PrintNightmare is the nickname given to two vulnerabilities (CVE-2021-34527 and CVE-2021-1675) found in the Print Spooler service that runs on all Windows operating systems.

See more on PrintNightmare

The Print Spooler exploitation leverages the Windows Print Spooler service in conjunction with the SeImpersonatePrivilege privilege. The goal is to impersonate a SYSTEM token to escalate privileges. Tools like PrintSpoofer automate this process effectively. Below are detailed steps for exploiting this vulnerability:

See more on PrintSpoofer

🗒️ Abusing SeDebugPrivilege

This privilege can be used to capture sensitive information from system memory, or access/modify kernel and application structures. A user might be assigned the SeDebugPrivilege without belonging to the administrators group.

See more on SeDebugPrivilege.

🅾️ SeTakeOwnershipPrivilege

SeTakeOwnershipPrivilege grants a user the ability to take ownership of any "securable object," meaning Active Directory objects, NTFS files/folders, printers, registry keys, services, and processes. This privilege assigns WRITE_OWNER rights over an object, meaning the user can change the owner within the object's security descriptor.

See more on SeTakeOwnershipPrivilege.

Detection

By logging event 4672: Special privileges assigned to new logon which will generate an event if certain sensitive privileges are assigned to a new logon session. This can be fine-tuned in many ways, such as by monitoring privileges that should never be assigned or those that should only ever be assigned to specific accounts.

Other resources

Last update: 2025-03-15
Created: February 23, 2025 21:12:05