Nulling
Iniciemos analizando la ACL que guarda los privilegios, el proceso que utilizaremos para el shellcode es winlogon.exe, este no tiene un pid fijo pero es un proceso que siempre tendrá privilegios administrativos, con !object podemos obtener el Header
0: kd> !process 0 0 winlogon.exe
PROCESS ffffe20d3e19c080
    SessionId: 1  Cid: 0254    Peb: f901e13000  ParentCid: 01fc
    DirBase: 10bbbf000  ObjectTable: ffff9e8c274a0b00  HandleCount: 281.  
    Image: winlogon.exe
0: kd> !object 0xffffe20d3e19c080
Object: ffffe20d3e19c080  Type: (ffffe20d3acb17a0) Process
    ObjectHeader: ffffe20d3e19c050 (new version)
    HandleCount: 15  PointerCount: 458230
La estructura _OBJECT_HEADER de cada proceso contiene un atributo interesante llamado SecurityDescriptor en el offset 0x28, este atributo contiene la ACL del objeto y esta define quien puede acceder al objeto y con que permisos
0: kd> dt nt!_OBJECT_HEADER 0xffffe20d3e19c050
   +0x000 PointerCount     : 0n458230
   +0x008 HandleCount      : 0n15
   +0x008 NextToFree       : 0x00000000`0000000f Void
   +0x010 Lock             : _EX_PUSH_LOCK
   +0x018 TypeIndex        : 0xde ''
   +0x019 TraceFlags       : 0 ''
   +0x019 DbgRefTrace      : 0y0
   +0x019 DbgTracePermanent : 0y0
   +0x01a InfoMask         : 0x88 ''
   +0x01b Flags            : 0 ''
   +0x01b NewObject        : 0y0
   +0x01b KernelObject     : 0y0
   +0x01b KernelOnlyAccess : 0y0
   +0x01b ExclusiveObject  : 0y0
   +0x01b PermanentObject  : 0y0
   +0x01b DefaultSecurityQuota : 0y0
   +0x01b SingleHandleEntry : 0y0
   +0x01b DeletedInline    : 0y0
   +0x01c Reserved         : 0x8930eb74
   +0x020 ObjectCreateInfo : 0xfffff800`6ae53a40 _OBJECT_CREATE_INFORMATION  
   +0x020 QuotaBlockCharged : 0xfffff800`6ae53a40 Void
   +0x028 SecurityDescriptor : 0xffff9e8c`1fa47e2d Void
   +0x030 Body             : _QUAD
En explotaciones realizadas en versiones antiguas de Windows 10 simplemente podiamos anular el SecurityDescriptor, como resultado si mirabamos con Process Explorer los permisos de un proceso se podia ver de esta forma y al no estar asignado a nadie cualquier usuario tenia Full Control sobre él, sin embargo esto cambió para versiones mas nuevas como explica la siguiente investigación de nettitude

Si en una versión actual de Windows anulamos el SecurityDescriptor el resultado es un BSOD de tipo BAD_OBJECT_HEADER diciendo que tiene un valor inválido
0: kd> eq 0xffffe20d3e19c050 + 0x28 0
0: kd> g
KDTARGET: Refreshing KD connection
*** Fatal System Error: 0x00000189 (0xFFFFE20D3E19C050,0xFFFFE20D416127F0,0x0000000000000001,0x0000000000000000)  
Break instruction exception - code 80000003 (first chance)
A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.
A fatal system error has occurred.
nt!DbgBreakPointWithStatus:
fffff803`2a6077a0 cc              int     3
0: kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************
BAD_OBJECT_HEADER (189)
The OBJECT_HEADER has been corrupted
Arguments:
Arg1: ffffe20d3e19c050, Pointer to bad OBJECT_HEADER
Arg2: ffffe20d416127f0, Pointer to the resulting OBJECT_TYPE based on the TypeIndex in the OBJECT_HEADER
Arg3: 0000000000000001, The object security descriptor is invalid.
Arg4: 0000000000000000, Reserved.

Lo único que nos queda es buscar una forma de asignar privilegios Full Control sin anularlo, para ello tendremos que entender como funciona el SecurityDescriptor, lo interesante de la estructura _SECURITY_DESCRIPTOR es el atributo Dacl que es una estructura _ACL que especifica el acceso que tienen los usuarios al objeto
0: kd> dt nt!_SECURITY_DESCRIPTOR
   +0x000 Revision         : UChar
   +0x001 Sbz1             : UChar
   +0x002 Control          : Uint2B
   +0x008 Owner            : Ptr64 Void  
   +0x010 Group            : Ptr64 Void  
   +0x018 Sacl             : Ptr64 _ACL  
   +0x020 Dacl             : Ptr64 _ACL  
  
0: kd> dt nt!_ACL
   +0x000 AclRevision      : UChar
   +0x001 Sbz1             : UChar
   +0x002 AclSize          : Uint2B
   +0x004 AceCount         : Uint2B
   +0x006 Sbz2             : Uint2B
Según documentación en realidad el objeto _ACL solo es un Header y el contenido real se encuentra en sus entradas, para una Dacl hay 2 tipos de ACE, estos son ACCESS_ALLOWED_ACE y ACCESS_DENIED_ACE, nos interesa el primero que indica que derechos tiene un SID a través del atributo ACCESS_MASK
typedef struct _ACCESS_ALLOWED_ACE {  
  ACE_HEADER  Header;
  ACCESS_MASK Mask;
  DWORD       SidStart;
} ACCESS_ALLOWED_ACE;
Utilizando el comando !sd podemos pasarle un puntero al SecurityDescriptor antes limpiando el último byte y obtener información de este, este nos muestra detalladamente que usuarios tienen que privilegios, el AceCount de la DACL es 2 lo que significa que contiene 2 ACE y ambos son de tipo ACCESS_ALLOWED_ACE, uno es para nt authority\system y el otro para el grupo builtin\administradores
0: kd> !sd (0xffff9e8c1fa47e2d & 0xfffffffffffffff0) 1
->Revision: 0x1
->Sbz1    : 0x0
->Control : 0x8814
            SE_DACL_PRESENT
            SE_SACL_PRESENT
            SE_SACL_AUTO_INHERITED
            SE_SELF_RELATIVE
->Owner   : S-1-5-32-544 (Alias: BUILTIN\Administradores)
->Group   : S-1-5-18 (Well Known Group: NT AUTHORITY\SYSTEM)
->Dacl    : 
->Dacl    : ->AclRevision: 0x2
->Dacl    : ->Sbz1       : 0x0
->Dacl    : ->AclSize    : 0x3c
->Dacl    : ->AceCount   : 0x2
->Dacl    : ->Sbz2       : 0x0
->Dacl    : ->Ace[0]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl    : ->Ace[0]: ->AceFlags: 0x0
->Dacl    : ->Ace[0]: ->AceSize: 0x14
->Dacl    : ->Ace[0]: ->Mask : 0x001fffff
->Dacl    : ->Ace[0]: ->SID: S-1-5-18 (Well Known Group: NT AUTHORITY\SYSTEM)
->Dacl    : ->Ace[1]: ->AceType: ACCESS_ALLOWED_ACE_TYPE
->Dacl    : ->Ace[1]: ->AceFlags: 0x0
->Dacl    : ->Ace[1]: ->AceSize: 0x18
->Dacl    : ->Ace[1]: ->Mask : 0x00121411
->Dacl    : ->Ace[1]: ->SID: S-1-5-32-544 (Alias: BUILTIN\Administradores)
->Sacl    : 
->Sacl    : ->AclRevision: 0x2
->Sacl    : ->Sbz1       : 0x0
->Sacl    : ->AclSize    : 0x1c
->Sacl    : ->AceCount   : 0x1
->Sacl    : ->Sbz2       : 0x0
->Sacl    : ->Ace[0]: ->AceType: SYSTEM_MANDATORY_LABEL_ACE_TYPE
->Sacl    : ->Ace[0]: ->AceFlags: 0x0
->Sacl    : ->Ace[0]: ->AceSize: 0x14
->Sacl    : ->Ace[0]: ->Mask : 0x00000003
->Sacl    : ->Ace[0]: ->SID: S-1-16-16384 (Label: Etiqueta obligatoria\Nivel obligatorio del sistema)  
Esto podemos verlo graficamente desde Process Explorer donde nt authority\system tiene privilegios Full Control, la forma que usaremos para tener este acceso será modificar el SID de SYSTEM para asignar estos privilegios a otro grupo con menos privilegios con el que podamos acceder por ejemplo Usuarios autenticados

 
          

