> Windows Syscalls
ntoskrnl.exeT1222T1222.001T1112

NtSetSecurityObject

Writes a new SECURITY_DESCRIPTOR (owner / DACL / SACL / label) onto a kernel object by handle.

Prototype

NTSTATUS NtSetSecurityObject(
  HANDLE               Handle,
  SECURITY_INFORMATION SecurityInformation,
  PSECURITY_DESCRIPTOR SecurityDescriptor
);

Arguments

NameTypeDirDescription
HandleHANDLEinHandle to the target object. Required access depends on the SecurityInformation bits: WRITE_DAC for DACL, WRITE_OWNER for OWNER, ACCESS_SYSTEM_SECURITY for SACL.
SecurityInformationSECURITY_INFORMATIONinBitmask of parts to write — must match the components present in SecurityDescriptor.
SecurityDescriptorPSECURITY_DESCRIPTORinPointer to the self-relative or absolute security descriptor to apply.

Syscall IDs by Windows version

Windows versionSyscall IDBuild
Win10 15070x18Bwin10-1507
Win10 16070x194win10-1607
Win10 17030x19Awin10-1703
Win10 17090x19Dwin10-1709
Win10 18030x19Fwin10-1803
Win10 18090x1A0win10-1809
Win10 19030x1A1win10-1903
Win10 19090x1A1win10-1909
Win10 20040x1A7win10-2004
Win10 20H20x1A7win10-20h2
Win10 21H10x1A7win10-21h1
Win10 21H20x1A9win10-21h2
Win10 22H20x1A9win10-22h2
Win11 21H20x1B2win11-21h2
Win11 22H20x1B6win11-22h2
Win11 23H20x1B6win11-23h2
Win11 24H20x1B9win11-24h2
Server 20160x194winserver-2016
Server 20190x1A0winserver-2019
Server 20220x1AFwinserver-2022
Server 20250x1B9winserver-2025

Kernel module

ntoskrnl.exeNtSetSecurityObject

Related APIs

SetSecurityInfoSetKernelObjectSecuritySetUserObjectSecuritySetFileSecurityWNtQuerySecurityObjectSetNamedSecurityInfoW

Syscall stub

4C 8B D1            mov r10, rcx
B8 B9 01 00 00      mov eax, 0x1B9
F6 04 25 08 03 FE 7F 01   test byte ptr [0x7FFE0308], 1
75 03               jne short +3
0F 05               syscall
C3                  ret
CD 2E               int 2Eh
C3                  ret

Undocumented notes

The write half of the security-descriptor pair. The kernel merges, replaces, or removes ACEs according to which control flags are set on the supplied descriptor (SE_DACL_PROTECTED, SE_SACL_PROTECTED, …). SeAssignSecurityEx performs the actual merge, with inheritance rules applied when the object is a container. Returns STATUS_INVALID_OWNER if the supplied owner SID is not enabled in the caller's token, and STATUS_PRIVILEGE_NOT_HELD when SACL is requested without SE_SECURITY_NAME.

Common malware usage

T1222 *Permissions Modification* is the canonical use. Two scenarios dominate. (1) **Persistence hardening on registry**: weaken the DACL of `HKLM\SYSTEM\CurrentControlSet\Services\<implant>` so a low-priv user can later rewrite ImagePath / Parameters without needing admin (T1222.001). (2) **Implant self-protection on files**: tighten the DACL of the implant's own EXE/DLL so SYSTEM-level AV remediation hits ACCESS_DENIED, or even strip Administrators from the DACL after taking ownership — this is how some ransomware notes (and the encryptor itself) survive deletion attempts (T1222.002). Carbanak/FIN7 have used both patterns against services and scheduled-task files.

Detection opportunities

High-fidelity signal when the *target object* is sensitive. Object-Access Audit Event 4670 (Permissions on an object were changed) fires when SACL audit is configured on the target — but SACLs on `HKLM\System\...` are rarely set by default. Sysmon Event 4 (sysmon service state) does not cover this; *EDR* hooks on NtSetSecurityObject or on the higher-level RtlSetSecurityObject are the practical detection. Look for: any process other than `services.exe`, `TrustedInstaller`, `msiexec`, or domain-policy-driven binaries writing a DACL on a service registry key or on a file under Program Files. A weakened DACL that grants `Everyone:F` or `Authenticated Users:F` to a service ImagePath is essentially a smoking gun.

Direct syscall examples

cWeaken DACL on a service registry key (skeleton)

// Add an explicit Allow-Full-Control ACE for Authenticated Users on the
// service's registry key, enabling later config rewrite without admin.
PSECURITY_DESCRIPTOR sd = NULL;
ULONG sdLen = 0;
ConvertStringSecurityDescriptorToSecurityDescriptorW(
    L"D:(A;OICI;GA;;;AU)",  // Authenticated Users : Generic All, container+object inherit
    SDDL_REVISION_1, &sd, &sdLen);

NTSTATUS st = NtSetSecurityObject(hSvcKey, DACL_SECURITY_INFORMATION, sd);
// hSvcKey must have been opened with WRITE_DAC.
LocalFree(sd);

asmx64 direct stub (Win11 24H2 SSN 0x1B9)

NtSetSecurityObject PROC
    mov  r10, rcx
    mov  eax, 1B9h
    syscall
    ret
NtSetSecurityObject ENDP

rustTake ownership of own binary, then deny Administrators

// Cargo: windows-sys = "0.59", ntapi = "0.4"
// Step 1: take ownership (requires SeTakeOwnershipPrivilege enabled).
unsafe {
    NtSetSecurityObject(h_file,
        OWNER_SECURITY_INFORMATION,
        owner_sd_with_self_sid.as_ptr() as _);
}
// Step 2: now write a DACL that denies Administrators Delete/WriteAttrib.
unsafe {
    NtSetSecurityObject(h_file,
        DACL_SECURITY_INFORMATION,
        deny_admins_dacl.as_ptr() as _);
}

MITRE ATT&CK mappings

Last verified: 2026-05-20