NtQuerySecurityObject
Recupera un SECURITY_DESCRIPTOR auto-relativo de cualquier objeto del kernel expuesto por un handle.
Prototipo
NTSTATUS NtQuerySecurityObject( HANDLE Handle, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR SecurityDescriptor, ULONG Length, PULONG LengthNeeded );
Argumentos
| Name | Type | Dir | Description |
|---|---|---|---|
| Handle | HANDLE | in | Handle a cualquier objeto asegurable (archivo, clave de registro, proceso, token, named pipe, etc.) abierto con READ_CONTROL. |
| SecurityInformation | SECURITY_INFORMATION | in | Máscara de bits de partes a obtener: OWNER_SECURITY_INFORMATION | GROUP_ | DACL_ | SACL_ | LABEL_ | ATTRIBUTE_. |
| SecurityDescriptor | PSECURITY_DESCRIPTOR | out | Búfer asignado por el llamador que recibe el descriptor de seguridad auto-relativo. |
| Length | ULONG | in | Tamaño de SecurityDescriptor en bytes. |
| LengthNeeded | PULONG | out | Recibe el tamaño realmente escrito, o el tamaño requerido en STATUS_BUFFER_TOO_SMALL. |
IDs de syscalls por versión de Windows
| Versión de Windows | ID de syscall | Build |
|---|---|---|
| Win10 1507 | 0x142 | win10-1507 |
| Win10 1607 | 0x148 | win10-1607 |
| Win10 1703 | 0x14E | win10-1703 |
| Win10 1709 | 0x151 | win10-1709 |
| Win10 1803 | 0x153 | win10-1803 |
| Win10 1809 | 0x154 | win10-1809 |
| Win10 1903 | 0x155 | win10-1903 |
| Win10 1909 | 0x155 | win10-1909 |
| Win10 2004 | 0x15B | win10-2004 |
| Win10 20H2 | 0x15B | win10-20h2 |
| Win10 21H1 | 0x15B | win10-21h1 |
| Win10 21H2 | 0x15C | win10-21h2 |
| Win10 22H2 | 0x15C | win10-22h2 |
| Win11 21H2 | 0x163 | win11-21h2 |
| Win11 22H2 | 0x166 | win11-22h2 |
| Win11 23H2 | 0x166 | win11-23h2 |
| Win11 24H2 | 0x168 | win11-24h2 |
| Server 2016 | 0x148 | winserver-2016 |
| Server 2019 | 0x154 | winserver-2019 |
| Server 2022 | 0x161 | winserver-2022 |
| Server 2025 | 0x168 | winserver-2025 |
Módulo del kernel
APIs relacionadas
Stub del syscall
4C 8B D1 mov r10, rcx B8 68 01 00 00 mov eax, 0x168 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
Notas no documentadas
Accesor universal a descriptores de seguridad para todos los tipos de objeto. Leer la SACL requiere SE_SECURITY_NAME (ACCESS_SYSTEM_SECURITY) — la mayoría de los llamadores omiten por tanto SACL_SECURITY_INFORMATION. Devuelve STATUS_BUFFER_TOO_SMALL con el tamaño requerido en LengthNeeded; el patrón estándar es una llamada sonda con Length=0 seguida de una asignación. Los wrappers Win32 GetSecurityInfo / GetKernelObjectSecurity / GetUserObjectSecurity acaban aquí.
Uso común por malware
Paso de reconocimiento que casi siempre precede a un SetSecurityObject — el implante lee el SDDL actual de un objetivo (clave de registro de servicio, fichero de tarea programada, directorio de instalación de EDR) para saber qué fusionar o quitar. También lo usan herramientas de descubrimiento de privilegios como el equivalente a Get-DomainObjectAcl de PowerSploit para detectar ACL débiles (p. ej. una clave de registro de servicio escribible por Authenticated Users) explotables sin tocar nada. En cadenas de robo de credenciales, NtQuerySecurityObject contra un handle de LSASS confirma qué privilegios y bits de acceso obtuvo realmente el operador.
Oportunidades de detección
Por sí solo, volumen extremadamente alto — cada diálogo Abrir, cada ventana Propiedades, cada prompt UAC lo invoca. La barra de detección es el *contexto*: NtQuerySecurityObject sobre `HKLM\SYSTEM\CurrentControlSet\Services\<EDR>` o sobre `lsass.exe` desde un proceso no confiable es interesante. La auditoría de acceso a objetos (Event 4663 con `Accesses: Read SD`) cubre la mayoría de los casos pero es ruidosa hasta ajustarla. Los EDR que median las aperturas fichero/proceso ven el READ_CONTROL del handle del que depende NtQuerySecurityObject. La detección estilo Bluespawn se centra en el SetSecurityObject *emparejado* que sigue.
Ejemplos de syscalls directos
cProbe-then-alloc pattern
// Read the DACL of a service registry key in two calls.
ULONG needed = 0;
NTSTATUS st = NtQuerySecurityObject(hSvcKey, DACL_SECURITY_INFORMATION,
NULL, 0, &needed);
if (st == STATUS_BUFFER_TOO_SMALL) {
PVOID sd = RtlAllocateHeap(RtlProcessHeap(), 0, needed);
st = NtQuerySecurityObject(hSvcKey, DACL_SECURITY_INFORMATION,
sd, needed, &needed);
// Now walk the DACL and decide what to weaken.
}asmx64 direct stub (Win11 24H2 SSN 0x168)
NtQuerySecurityObject PROC
mov r10, rcx
mov eax, 168h
syscall
ret
NtQuerySecurityObject ENDPrustRead DACL of EDR install dir before tampering
// Cargo: ntapi = "0.4", windows-sys = "0.59"
let mut needed: u32 = 0;
let st = unsafe {
NtQuerySecurityObject(h_dir,
DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
null_mut(), 0, &mut needed)
};
assert_eq!(st, STATUS_BUFFER_TOO_SMALL as i32);
let mut buf = vec![0u8; needed as usize];
unsafe {
NtQuerySecurityObject(h_dir,
DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
buf.as_mut_ptr() as _, buf.len() as u32, &mut needed);
}Mapeos MITRE ATT&CK
Last verified: 2026-05-20