Ataque de Password Spraying
El password spraying es un tipo de ataque de fuerza bruta que prueba un número reducido de contraseñas de uso común contra una gran cantidad de cuentas de usuario simultáneamente. A diferencia de la fuerza bruta tradicional que prueba muchas contraseñas contra una cuenta (activando el bloqueo), el password spraying prueba una contraseña contra todas las cuentas antes de pasar a la siguiente, evadiendo las políticas de bloqueo de cuentas mientras explota la certeza estadística de que algunos usuarios tendrán contraseñas débiles.
Cómo Funciona Ataque de Password Spraying
El password spraying explota una tensión fundamental en el diseño de seguridad: las políticas de bloqueo de cuentas protegen cuentas individuales contra fuerza bruta pero no pueden proteger contra ataques distribuidos entre muchas cuentas. Si una organización tiene 10,000 usuarios y el atacante prueba solo una contraseña (por ejemplo, 'Summer2026!'), estadísticamente el 1-3% de los usuarios tendrán exactamente esa contraseña, produciendo 100-300 cuentas comprometidas — todo sin activar un solo bloqueo. El ataque es particularmente efectivo contra entornos empresariales que usan Active Directory, Microsoft 365 y otros sistemas de identidad centralizados.
Enumerar nombres de usuario válidos
El atacante recopila nombres de usuario válidos a través de múltiples fuentes: scraping de LinkedIn para derivar formatos de correo corporativo (nombre.apellido@empresa.com), recopilación de correos electrónicos de registros públicos y brechas de datos, herramientas OSINT (theHarvester, Hunter.io), enumeración de usuarios basada en tiempos en páginas de inicio de sesión (diferentes tiempos de respuesta para usuarios válidos vs. inválidos), y enumeración de usuarios en Azure AD/Microsoft 365 a través de APIs accesibles públicamente. Una sola organización puede producir miles de nombres de usuario válidos.
Crear una lista de contraseñas dirigida
En lugar de listas de palabras genéricas, el atacante crea una lista pequeña y dirigida de contraseñas basada en el contexto de la organización: nombre de la empresa + año (NombreEmpresa2026), patrones estacionales (Winter2026!, Summer2026!), patrones comunes que cumplen requisitos de complejidad (Welcome1!, Password123!, Qwerty@123), contraseñas recientemente expiradas con números incrementados, equipos deportivos o referencias locales, y contraseñas por defecto para cuentas nuevas. Una lista enfocada de 5-20 contraseñas es más efectiva que miles de aleatorias.
Ejecutar un ataque distribuido de baja velocidad
El atacante prueba una contraseña contra todas las cuentas enumeradas, luego espera (a menudo 30-60 minutos o más) antes de probar la siguiente contraseña. Este retraso mantiene el conteo de intentos por cuenta muy por debajo de los umbrales de bloqueo (típicamente 3-5 intentos en 15-30 minutos). Los atacantes avanzados distribuyen las solicitudes a través de múltiples IPs de origen usando infraestructura en la nube, proxies residenciales o dispositivos comprometidos para evitar la detección basada en IP. Cada contraseña se prueba contra toda la base de usuarios antes de avanzar.
Identificar y explotar inicios de sesión exitosos
El atacante monitorea las respuestas de autenticación exitosas, que típicamente difieren de los fallos en códigos de estado HTTP, cabeceras de respuesta o destinos de redirección. Cada inicio de sesión exitoso se prueba inmediatamente por alcance de acceso: correo electrónico, VPN, servicios en la nube, aplicaciones internas. El atacante prioriza cuentas con privilegios administrativos, acceso a datos sensibles o posiciones que permitan mayor ingeniería social (ejecutivos, personal de TI, finanzas).
Establecer persistencia y escalar
Las cuentas comprometidas se utilizan para establecer persistencia antes de que la contraseña sea potencialmente restablecida: el atacante inscribe su propio dispositivo MFA, crea reglas de reenvío de correo, genera contraseñas de aplicación o aprovisiona tokens OAuth. Las cuentas de alto valor se usan para movimiento lateral dentro de la organización — accediendo a documentos de SharePoint, wikis internas y otros sistemas que dependen del mismo proveedor de identidad, expandiendo progresivamente el acceso a recursos más sensibles.
Ejemplos Reales
Ataque de Midnight Blizzard (Nobelium) a Microsoft
El grupo patrocinado por el estado ruso Midnight Blizzard (anteriormente Nobelium, los atacantes de SolarWinds) usó password spraying para comprometer una cuenta heredada de prueba de un tenant no productivo de Microsoft que carecía de MFA. Desde este punto de apoyo inicial, accedieron a los sistemas de correo electrónico corporativo de Microsoft y leyeron correos de la alta dirección y miembros del equipo de ciberseguridad durante varios meses. El incidente demostró que incluso las empresas tecnológicas más grandes del mundo son vulnerables al password spraying contra cuentas con protecciones inadecuadas.
Campañas de APT iraní contra el gobierno de EE.UU.
El Departamento de Justicia de EE.UU. acusó a hackers iraníes que llevaron a cabo una campaña masiva de password spraying dirigida a más de 7,998 cuentas en 176 universidades de 21 países, 47 empresas privadas, las Naciones Unidas y entidades del gobierno de EE.UU. Los atacantes comprometieron exitosamente aproximadamente 3,768 cuentas, robando más de 31 terabytes de datos con un valor aproximado de $3.4 mil millones en propiedad intelectual.
Brecha de Citrix vía password spraying
Los atacantes usaron password spraying para obtener acceso inicial a la red interna de Citrix, accediendo y descargando documentos empresariales durante aproximadamente seis meses antes de la detección. El FBI alertó a Citrix sobre la brecha. Los atacantes, atribuidos al grupo IRIDIUM, accedieron a aproximadamente 6 TB de datos internos sensibles. Citrix confirmó posteriormente que el punto de acceso inicial fue una combinación de password spraying y credential stuffing contra cuentas de empleados.
Impacto y Evaluación de Riesgo
El password spraying es una de las técnicas de acceso inicial más efectivas utilizadas tanto por ciberdelincuentes como por actores de estados-nación. Su efectividad se debe a la certeza matemática de que en cualquier población grande de usuarios, algunos tendrán contraseñas débiles. Un spray exitoso típicamente compromete el 1-3% de las cuentas objetivo, lo que en una organización de 10,000 usuarios significa 100-300 cuentas. El impacto se propaga en cascada: las cuentas de correo comprometidas permiten compromiso de correo empresarial (BEC) y phishing interno; el acceso VPN proporciona acceso a nivel de red a recursos internos; las cuentas de administración en la nube exponen toda la infraestructura cloud. El Informe de Defensa Digital 2024 de Microsoft identificó el password spraying como el vector de ataque basado en identidad más común, responsable de más de un tercio de los compromisos de cuentas empresariales.
Cómo Detectar Ataque de Password Spraying
Detectar password spraying requiere pasar del análisis por cuenta al reconocimiento de patrones entre cuentas. Monitorear: intentos de inicio de sesión fallidos simultáneos en muchas cuentas con la misma contraseña (el patrón definitorio del spray), picos de inicios de sesión fallidos en toda la organización incluso cuando ninguna cuenta individual excede los umbrales de bloqueo, intentos de autenticación desde IPs de hosting en la nube o servicios de proxy conocidos, intentos de inicio de sesión fuera del horario laboral en muchas cuentas, inicios de sesión exitosos inmediatamente después de un patrón de fallos distribuidos, y anomalías geográficas (intentos de inicio de sesión desde países donde la organización no tiene empleados). Implementar registro centralizado de autenticación que correlacione eventos a través de todos los proveedores de identidad (AD, Azure AD, Okta, LDAP). Desplegar reglas SIEM específicamente diseñadas para detectar patrones de password spraying lentos y distribuidos. Monitorear la generación de tokens OAuth y cambios en la inscripción de MFA después de una autenticación exitosa desde fuentes inusuales.
Cómo Prevenir Ataque de Password Spraying
Implementar autenticación multifactor para todas las cuentas — la MFA neutraliza el password spraying incluso cuando se descubren contraseñas débiles, porque el atacante carece del segundo factor. Desplegar autenticación sin contraseña (FIDO2, passkeys) donde sea posible para eliminar los ataques basados en contraseñas por completo. Implementar políticas de contraseñas que prohíban patrones comunes: verificar contra listas de brechas (HaveIBeenPwned), bloquear variaciones del nombre de la empresa, patrones estacionales y recorridos de teclado. Implementar bloqueo inteligente que considere patrones distribuidos (Azure AD Smart Lockout, similares para otros proveedores) en lugar de solo umbrales por cuenta. Desplegar políticas de acceso condicional que restrinjan la autenticación según ubicación, cumplimiento del dispositivo y señales de riesgo. Usar cuentas señuelo (honeypot) — cuentas trampa que generan alertas inmediatas cuando se intenta la autenticación. Implementar limitación de tasa de inicio de sesión que considere patrones entre cuentas, no solo tasas por cuenta. Auditar regularmente cuentas de servicio, cuentas heredadas y cuentas no productivas, que frecuentemente se pasan por alto y carecen de MFA. Deshabilitar protocolos de autenticación heredados (IMAP, POP3, SMTP AUTH) que no soportan MFA.
Ejemplos de Código
from collections import defaultdict
from datetime import datetime, timedelta
def detect_password_spray(auth_logs, window_minutes=30, threshold=10):
"""Detect password spraying by identifying coordinated failed logins
across multiple accounts within a time window."""
# Group failed logins by time window
windows = defaultdict(lambda: {
'source_ips': set(),
'target_accounts': set(),
'failed_count': 0,
'timestamps': []
})
for log in auth_logs:
if log['status'] != 'failed':
continue
# Round timestamp to window
window_key = log['timestamp'].replace(
minute=(log['timestamp'].minute // window_minutes) * window_minutes,
second=0, microsecond=0
)
w = windows[window_key]
w['source_ips'].add(log['source_ip'])
w['target_accounts'].add(log['username'])
w['failed_count'] += 1
w['timestamps'].append(log['timestamp'])
alerts = []
for window_start, data in windows.items():
# Spray signature: many accounts, few IPs, concentrated time
accounts_hit = len(data['target_accounts'])
unique_ips = len(data['source_ips'])
if accounts_hit >= threshold:
# High ratio of targeted accounts to source IPs = spray
spray_score = accounts_hit / max(unique_ips, 1)
if spray_score >= 5: # 5+ accounts per IP = likely spray
alerts.append({
'type': 'password_spray_detected',
'severity': 'critical' if accounts_hit > 100 else 'high',
'window_start': window_start,
'accounts_targeted': accounts_hit,
'source_ips': list(data['source_ips']),
'total_failures': data['failed_count'],
'spray_score': round(spray_score, 1)
})
return alerts
import re
import hashlib
import requests
from datetime import datetime
class PasswordPolicyChecker:
"""Enterprise password policy with spray-resistant rules"""
def __init__(self, company_name):
self.company_name = company_name.lower()
self.company_variants = self._generate_variants(company_name)
def _generate_variants(self, name):
"""Generate common leetspeak and pattern variants"""
base = name.lower()
variants = {base}
# Common substitutions
subs = {'a': '@4', 'e': '3', 'i': '1!', 'o': '0', 's': '$5'}
for char, replacements in subs.items():
for r in replacements:
variants.add(base.replace(char, r))
return variants
def check(self, password):
"""Returns (is_valid, rejection_reason)"""
pw_lower = password.lower()
# Block company name variants
for variant in self.company_variants:
if variant in pw_lower:
return False, 'Password contains company name'
# Block seasonal patterns
seasons = ['spring', 'summer', 'autumn', 'fall', 'winter']
current_year = datetime.now().year
for season in seasons:
for year in range(current_year - 2, current_year + 2):
if f'{season}{year}' in pw_lower:
return False, 'Password contains predictable seasonal pattern'
# Block common base passwords
common_bases = [
'password', 'welcome', 'qwerty', 'admin', 'changeme',
'letmein', 'monkey', 'dragon', 'master', 'login'
]
for base in common_bases:
if base in pw_lower:
return False, 'Password contains common word'
# Block keyboard walks
keyboard_walks = [
'qwerty', 'qwer', 'asdf', 'zxcv', '1234', '4321',
'qazwsx', 'qwertyui'
]
for walk in keyboard_walks:
if walk in pw_lower:
return False, 'Password contains keyboard pattern'
# Check HaveIBeenPwned (k-anonymity API)
if self._check_hibp(password):
return False, 'Password found in known data breaches'
return True, None
def _check_hibp(self, password):
"""Check password against HaveIBeenPwned using k-anonymity"""
sha1 = hashlib.sha1(password.encode()).hexdigest().upper()
prefix, suffix = sha1[:5], sha1[5:]
resp = requests.get(f'https://api.pwnedpasswords.com/range/{prefix}')
return suffix in resp.text
PowerWAF bloquea automáticamente Ataque de Password Spraying antes de que llegue a tu servidor.
Implementa en minutos. Sin cambios de código. Plan gratuito disponible.
Los cupos del plan gratuito son limitados