Zero Trust en la práctica:
6 controles que implementás
esta semana
Sin teoría del modelo. Directo a GPO, PowerShell y configuración real. Los 6 controles que más impacto tienen en una infraestructura corporativa típica — AD, SMB, infraestructura de soporte — y cómo verificar que quedaron bien aplicados.
Este artículo asume que ya conocés el problema: la red interna de la mayoría de las organizaciones confía implícitamente en todo lo que está adentro. Un usuario con acceso VPN tiene visibilidad a servidores, shares y dispositivos que no debería ver. Los 6 controles que siguen atacan ese problema directamente, sin requerir reemplazar infraestructura.
Control 1. Lockout policy: cerrar el spray de contraseñas
El Default Domain Policy tiene lockoutThreshold: 0 en muchos entornos: sin bloqueo de cuenta por intentos fallidos. Eso convierte cualquier lista de usuarios en un vector de spray irrestricto.
La corrección usa Fine-Grained Password Policies (PSO), disponibles desde Windows Server 2008 R2. Permiten aplicar políticas distintas por grupo sin tocar el Default Domain Policy.
Crear la PSO desde PowerShell
# Importar módulo AD
Import-Module ActiveDirectory
# Crear la PSO
New-ADFineGrainedPasswordPolicy `
-Name "PSO-CorporativoEstándar" `
-Precedence 10 `
-MinPasswordLength 12 `
-PasswordHistoryCount 24 `
-LockoutThreshold 5 `
-LockoutDuration "00:30:00" `
-LockoutObservationWindow "00:30:00" `
-ComplexityEnabled $true `
-ReversibleEncryptionEnabled $false
# Aplicar a todos los usuarios de dominio (grupo Domain Users)
Add-ADFineGrainedPasswordPolicySubject `
-Identity "PSO-CorporativoEstándar" `
-Subjects "Domain Users"
PSO más restrictiva para admins
New-ADFineGrainedPasswordPolicy `
-Name "PSO-Administradores" `
-Precedence 1 `
-MinPasswordLength 16 `
-PasswordHistoryCount 48 `
-LockoutThreshold 3 `
-LockoutDuration "01:00:00" `
-LockoutObservationWindow "01:00:00" `
-ComplexityEnabled $true `
-ReversibleEncryptionEnabled $false
Add-ADFineGrainedPasswordPolicySubject `
-Identity "PSO-Administradores" `
-Subjects "Domain Admins","Enterprise Admins"
Verificar qué PSO aplica a un usuario
Get-ADUserResultantPasswordPolicy -Identity "nombredeusuario"
# Si devuelve vacío → aplica Default Domain Policy (revisar)
3 intentos genera demasiados bloqueos legítimos (usuarios que cambian contraseña en un dispositivo y otro sigue intentando con la anterior). 5 intentos en 30 minutos frena el spray automatizado sin ser un problema operativo.
Control 2. Password policy anti-patrones: prohibir MesAño
Las políticas de complejidad estándar de Windows aceptan Enero2026!: mayúscula, número, especial, longitud. Es una contraseña técnicamente válida y prácticamente predecible. Los patrones MesAño, secuencias de teclado (Qwerty123) y el nombre de la empresa son las primeras entradas en cualquier lista de spray.
Azure AD Password Protection on-premises lleva el motor de contraseñas prohibidas de Entra ID a los DCs locales. Bloquea variantes y fuzzing, no solo coincidencias exactas.
Instalación en el DC
# En cada Domain Controller
Install-Module AzureADPasswordProtection -Force
# Registrar el proxy (un servidor que tenga salida a internet)
Register-AzureADPasswordProtectionProxy -AccountUpn [email protected]
# Registrar el forest
Register-AzureADPasswordProtectionForest -AccountUpn [email protected]
# Instalar el agente DC en cada DC
Install-AzureADPasswordProtectionDCAgent
Lista de palabras prohibidas personalizadas
# En el portal Entra ID (portal.azure.com):
# Azure AD → Security → Authentication methods
# → Password protection → Custom banned passwords
# Ejemplos de entradas:
# empresa, empresaNombre, enero, febrero, marzo,
# abril, mayo, junio, julio, agosto, septiembre,
# octubre, noviembre, diciembre, password, contraseña
Modo audit antes de enforcement
# Activar primero en modo Audit — no rechaza, solo loguea
# En el portal: Password Protection → Mode → Audit
# Revisar el log en los DCs:
Get-WinEvent -LogName "Microsoft-AzureADPasswordProtection-DCAgent/Admin" |
Where-Object {$_.Id -eq 30008} |
Select-Object TimeCreated, Message |
Format-List
# Después de 2 semanas sin sorpresas → cambiar a Enforced
Control 3. Privilege Tiering: separar cuentas por nivel de acceso
El problema más común: una sola cuenta de administrador que loguea en el DC, en los servidores de aplicación y en su propia workstation para leer el correo. Si esa cuenta es comprometida en la workstation, el atacante tiene Domain Admin.
El modelo de tres tiers corta esa cadena:
| Tier | Scope | Ejemplos | Puede loguear en |
|---|---|---|---|
| Tier 0 | Control del dominio | DC, AD Connect, PKI, ADFS | Solo Tier 0 |
| Tier 1 | Servidores | App servers, DB, Exchange, backup | Tier 1 y Tier 0 assets |
| Tier 2 | Workstations y usuarios | PCs, laptops, dispositivos de usuario | Tier 2 únicamente |
Implementar con GPO: bloquear logon entre tiers
# GPO aplicada a los Domain Controllers (Tier 0):
# Computer Configuration → Policies → Windows Settings
# → Security Settings → Local Policies → User Rights Assignment
# "Deny log on locally" → agregar grupos Tier 1 Admins y Tier 2 Admins
# "Deny log on through Remote Desktop Services" → ídem
# "Deny log on as a service" → ídem
# Mismo patrón para servidores Tier 1:
# → agregar Tier 0 Admins solo si es realmente necesario
# → bloquear Tier 2 Admins siempre
Crear grupos y OUs para el modelo
New-ADOrganizationalUnit -Name "Tier0-Accounts" -Path "DC=dominio,DC=local"
New-ADOrganizationalUnit -Name "Tier1-Accounts" -Path "DC=dominio,DC=local"
New-ADOrganizationalUnit -Name "Tier2-Accounts" -Path "DC=dominio,DC=local"
New-ADGroup -Name "Tier0-Admins" -GroupScope Global -Path "OU=Tier0-Accounts,DC=dominio,DC=local"
New-ADGroup -Name "Tier1-Admins" -GroupScope Global -Path "OU=Tier1-Accounts,DC=dominio,DC=local"
New-ADGroup -Name "Tier2-Admins" -GroupScope Global -Path "OU=Tier2-Accounts,DC=dominio,DC=local"
Expirar cuentas de contratistas automáticamente
# Al crear cuenta de contratista, siempre con fecha de expiración
New-ADUser -Name "ext.proveedor" `
-AccountExpirationDate (Get-Date).AddDays(90) `
-PasswordNeverExpires $false `
-Enabled $true
# Auditar cuentas con privilegios elevados sin expiración
Get-ADGroupMember "Domain Admins" |
Get-ADUser -Properties AccountExpirationDate, Description |
Where-Object {$_.AccountExpirationDate -eq $null} |
Select-Object Name, SamAccountName, Description |
Format-Table -AutoSize
Control 4. LAPS: eliminar la contraseña local compartida
La mayoría de los entornos despliegan workstations y servidores con la misma contraseña del administrador local en todas las máquinas, la que usó el técnico el día de la instalación. Si un atacante obtiene esa contraseña en una máquina, la tiene en todas.
LAPS (Local Administrator Password Solution) genera y rota automáticamente una contraseña única por máquina, la guarda cifrada en AD, y solo los usuarios autorizados pueden leerla.
Windows LAPS (nativo desde Windows Server 2022 / Windows 11 22H2)
# En el DC — extender el schema de AD
Update-LapsADSchema
# Dar permisos de escritura a las cuentas de máquina sobre su propio atributo
Set-LapsADComputerSelfPermission -Identity "OU=Workstations,DC=dominio,DC=local"
Set-LapsADComputerSelfPermission -Identity "OU=Servers,DC=dominio,DC=local"
# Dar permisos de lectura a los admins autorizados
Set-LapsADReadPasswordPermission `
-Identity "OU=Workstations,DC=dominio,DC=local" `
-AllowedPrincipals "Tier2-Admins"
Set-LapsADReadPasswordPermission `
-Identity "OU=Servers,DC=dominio,DC=local" `
-AllowedPrincipals "Tier1-Admins"
GPO para habilitar LAPS en los equipos
# Computer Configuration → Policies → Administrative Templates
# → System → LAPS
# "Configure password backup directory" → Active Directory
# "Password Settings":
# - Password complexity: Large letters + small letters + numbers + specials
# - Password length: 20
# - Password age (days): 30
# "Enable password encryption" → Enabled
# "Post-authentication actions" → Reset password + Sign out after grace period
Leer la contraseña de una máquina específica
Get-LapsADPassword -Identity "HOSTNAME-PC01" -AsPlainText
# Name : HOSTNAME-PC01
# Account : Administrator
# Password : Kx9#mQ2vL...
# PasswordUpdateTime : 2026-07-01 09:14:22
# ExpirationTimestamp : 2026-07-31 09:14:22
Control 5. SMB Signing: bloquear el relay NTLM
SMB Signing requerido en los Domain Controllers no es suficiente. Un atacante que captura un hash NTLM con Responder puede hacer relay hacia cualquier servidor con signing not required, y la mayoría de los servidores de aplicación, backup y bases de datos no lo tienen habilitado por defecto.
Habilitar SMB Signing obligatorio en todos los servidores
# GPO: Computer Configuration → Policies → Windows Settings
# → Security Settings → Local Policies → Security Options
# "Microsoft network server: Digitally sign communications (always)" → Enabled
# "Microsoft network client: Digitally sign communications (always)" → Enabled
# Alternativa: PowerShell directo en cada servidor
Set-SmbServerConfiguration -RequireSecuritySignature $true -Force
Set-SmbClientConfiguration -RequireSecuritySignature $true -Force
Verificar el estado de signing en la red antes y después
# Desde cualquier máquina Windows en la red
# Verificar un host específico
Get-SmbServerConfiguration -CimSession SERVIDOR01 |
Select-Object RequireSecuritySignature, EnableSecuritySignature
# Escanear múltiples hosts (requiere acceso admin)
$hosts = @("SRV01","SRV02","DB01","VEEAM01","NAS01")
$hosts | ForEach-Object {
$cfg = Get-SmbServerConfiguration -CimSession $_ -ErrorAction SilentlyContinue
[PSCustomObject]@{
Host = $_
Required = $cfg.RequireSecuritySignature
Enabled = $cfg.EnableSecuritySignature
}
} | Format-Table -AutoSize
Algunos sistemas legacy (escáneres, dispositivos embebidos, NAS antiguos) no soportan SMB Signing. Activá primero en modo audit con EnableSecuritySignature $true pero RequireSecuritySignature $false. Monitorear el event log (ID 3000) durante una semana antes de forzar.
Deshabilitar SMBv1 de una vez
# SMBv1 es el protocolo explotado por WannaCry/NotPetya — no tiene razón de existir
# Verificar si está activo
Get-SmbServerConfiguration | Select-Object EnableSMB1Protocol
# Desactivar
Set-SmbServerConfiguration -EnableSMB1Protocol $false -Force
# Verificar en múltiples hosts
$hosts | ForEach-Object {
$cfg = Get-SmbServerConfiguration -CimSession $_ -ErrorAction SilentlyContinue
[PSCustomObject]@{ Host = $_; SMBv1 = $cfg.EnableSMB1Protocol }
} | Format-Table
Control 6. Infraestructura de soporte: el punto ciego
UPS, sistemas PBX, cámaras IP, interfaces iLO/iDRAC de servidores: ninguno entra en los ciclos de gestión de contraseñas ni en el patching regular. La justificación habitual: "solo están en la red interna". Eso los convierte en los activos con mayor impacto y menor vigilancia.
Inventariar dispositivos con panel web en la red interna
# nmap sobre los rangos internos buscando paneles HTTP/HTTPS
nmap -sV -p 80,443,8080,8443 [rango/24] --open \
-oG paneles_web.txt
# Filtrar por banners conocidos de dispositivos embebidos
grep -iE "rapidlogic|hikvision|issabel|ilo|idrac|apc|dahua|axis" \
paneles_web.txt
Verificar credenciales por defecto — script de auditoría
# Lista de credenciales de fábrica más comunes
CREDS=("admin:admin" "admin:" "admin:1234" "admin:password" \
"apc:apc" "root:root" "root:admin" "user:user")
TARGET="192.168.x.x" # IP del dispositivo a verificar
for cred in "${CREDS[@]}"; do
user=$(echo $cred | cut -d: -f1)
pass=$(echo $cred | cut -d: -f2)
code=$(curl -s -o /dev/null -w "%{http_code}" \
--max-time 3 -u "$user:$pass" http://$TARGET/)
if [ "$code" = "200" ]; then
echo "[VULNERABLE] $TARGET → $cred (HTTP $code)"
fi
done
Checklist de hardening por tipo de dispositivo
| Dispositivo | Acción mínima | Acción recomendada |
|---|---|---|
| UPS (APC NMC) | Cambiar creds por defecto (apc:apc) | Actualizar firmware NMC + VLAN dedicada sin acceso desde usuarios |
| PBX (Asterisk/FreePBX) | Habilitar autenticación en panel admin | Fail2ban en AMI, VLAN de telefonía, acceso solo desde IPs de gestión |
| NVR / Cámaras IP | Actualizar firmware + cambiar creds | VLAN de cámaras sin salida a LAN corporativa, NVR en red de gestión |
| iLO / iDRAC | Cambiar contraseña por defecto | Actualizar firmware + VLAN de gestión out-of-band, MFA si el firmware lo soporta |
| Switches administrados | Deshabilitar telnet, usar SSH | TACACS+ o RADIUS para autenticación centralizada, logging de comandos |
Bonus. Detección: si la prevención falla, detectar rápido
Los 6 controles anteriores reducen drásticamente la superficie. Pero ninguna configuración es perfecta. Estos Event IDs en los logs de Windows son las señales más tempranas de movimiento lateral y escalada de privilegios.
Detectar DCSync no autorizado
# DCSync genera el Event ID 4662 en el DC con estos atributos:
# Object Type: domainDNS
# Access: Control Access + Replicating Directory Changes All
# PowerShell: buscar en los logs del DC
Get-WinEvent -LogName Security -FilterXPath `
"*[System[EventID=4662] and
EventData[Data[@Name='Properties'] and
Data[contains(text(),'1131f6ad-9c07-11d1-f79f-00c04fc2dcd2')]]]" |
Select-Object TimeCreated,
@{N='Account';E={$_.Properties[1].Value}},
@{N='SubjectDomain';E={$_.Properties[2].Value}} |
Where-Object {$_.Account -notlike '*MSOL*' -and $_.Account -notlike '*$'}
Detectar password spray (múltiples fallos desde una IP)
# Event ID 4625 = logon failure
# Agrupar por IP origen y contar en ventana de 10 minutos
$start = (Get-Date).AddMinutes(-10)
Get-WinEvent -LogName Security -FilterXPath `
"*[System[EventID=4625 and TimeCreated[@SystemTime>='$($start.ToUniversalTime().ToString("o"))']]]" |
ForEach-Object {
[PSCustomObject]@{
Time = $_.TimeCreated
User = $_.Properties[5].Value
IP = $_.Properties[19].Value
}
} |
Group-Object IP |
Where-Object {$_.Count -gt 10} |
Select-Object Name, Count |
Sort-Object Count -Descending
Detectar cuentas añadidas a Domain Admins
# Event ID 4728 = miembro agregado a grupo de seguridad global
# Filtrar por el grupo Domain Admins (bien conocido)
Get-WinEvent -LogName Security -FilterXPath `
"*[System[EventID=4728] and
EventData[Data[@Name='TargetUserName']='Domain Admins']]" |
Select-Object TimeCreated,
@{N='AddedUser';E={$_.Properties[0].Value}},
@{N='By';E={$_.Properties[6].Value}} |
Format-Table -AutoSize
Tabla de priorización: por dónde empezar
| Control | Impacto | Esfuerzo | Primero |
|---|---|---|---|
| Lockout policy (PSO) | Alto | 30 min | Día 1 |
| SMB Signing obligatorio | Alto | 2–4 horas (testing previo) | Día 1–2 |
| Credenciales de infraestructura | Alto | ½ día de inventario | Día 2 |
| LAPS | Alto | ½ día de deploy | Semana 1 |
| Password Protection anti-patrones | Medio | 1 día (2 semanas en audit) | Semana 1–2 |
| Privilege Tiering completo | Muy alto | Alto (cambio organizacional) | Proyecto de 1–2 meses |
Los primeros tres controles — lockout, SMB Signing y credenciales de infraestructura — se implementan en menos de un día y cortan los vectores más frecuentes de movimiento lateral. El Privilege Tiering es el cambio de mayor impacto pero requiere un proyecto. LAPS y Password Protection van en el medio. Empezá por orden de esfuerzo mínimo y mayor impacto inmediato: el día 1 ya podés tener una red significativamente más difícil de navegar para un atacante interno.