Inicio Expertise Soluciones CV Stack Blog Contacto
Volver al blog
Ciberseguridad 4 de julio de 2026 18 min lectura

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.

Zero Trust Active Directory GPO LAPS SMB PowerShell
Zero Trust en la práctica: diagrama de controles en capas sobre infraestructura corporativa
Punto de partida

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

01 Active Directory · Fine-Grained Password Policy

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)
Por qué 5 intentos y no 3

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

02 Active Directory · Azure AD Password Protection

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

03 Active Directory · Tiered Administration Model

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:

TierScopeEjemplosPuede loguear en
Tier 0Control del dominioDC, AD Connect, PKI, ADFSSolo Tier 0
Tier 1ServidoresApp servers, DB, Exchange, backupTier 1 y Tier 0 assets
Tier 2Workstations y usuariosPCs, laptops, dispositivos de usuarioTier 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

04 Windows LAPS · GPO

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

05 SMB · GPO · Verificación de red

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
Antes de forzar — testear compatibilidad

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

06 UPS · PBX · NVR · iLO · Credenciales de fábrica

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

DispositivoAcción mínimaAcció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

ControlImpactoEsfuerzoPrimero
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
Conclusión operativa

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.