Ataque del Diccionario - Operación Integral
Documento de referencia del proyecto Time2Crack
Recipientes: desarrolladores, investigadores de seguridad, usuarios avanzados
Índice
isDictWord()addDictionaryAttacks()applyHighFidelityCalibration()1. Sinopsis
El ataque al diccionario es el método de grieta de contraseña más antiguo, el más simple conceptualmente y estadísticamente más eficaz en la mayoría de las contraseñas humanas reales. Su principio es probar, en orden descendente de probabilidad, una lista precompilada de candidatos — el "diccionario"— en lugar de enumerar exhaustivamente todas las combinaciones posibles como lo hace la fuerza prima.
Por qué es terriblemente eficaz Los humanos no eligen sus contraseñas aleatoriamente. Decenios de las filtraciones de datos revelan que la distribución real de las contraseñas está muy concentrada: las más comunes 1.000 contraseñas representan alrededor de 5 a 10% de todas las cuentas en línea. Los más comunes 1 millón cubren 40 a 60%. Un ataque de diccionario bien construido pondrá a prueba a estos candidatos en milisegundos a segundos, donde la fuerza bruta tomaría millones de años.En Time2Crack, el diccionario atacan dos mecanismos distintos pero complementarios:
Estas dos detecciones son independientes y complementarias: HiBP cubre las credenciales exactas de compromiso, la lista de palabras cubre las palabras comunes que aún no se han filtrado.
2. Antecedentes históricos y académicos
2.1 Origen
El ataque del diccionario precede a la era moderna de seguridad informática. Los primeros sistemas Unix almacenan contraseñas en lenguaje simple en /etc/passwd, haciendo cualquier ataque de diccionario trivial tan pronto como el archivo era accesible.
2.2 Pérdidas de fundación
Algunas filtraciones han transformado el paisaje del ataque por diccionario revelando la distribución real de contraseñas humanas:
RockYou (2009) Un desarrollador había almacenado 14.3 millones de contraseñas en lenguaje simple.- Contraseña #1 ("123456") representaba 290.731 cuentas (2%)
2.3 Puntos de referencia para el ataque al diccionario
Una lista de 200.000 entradas probadas a la velocidad de un RTX 4090:
AlgoritmSpeedTiempo para 200k candidatos ---------------------------- MD5168,9 GH/s~1,2 nanosegundo SHA-150.86 GH/s~3.9 nanoseconds SHA-25622.68 GH/s~8.8 nanosegundos NTLM288,5 GH/s~0,7 nanosegundo bcrypt (cost 5)184 kH/s~1.09 segundo Argon2id~67 H/s~50 minutosPor lo tanto, el ataque del diccionario es casi instantáneo para MD5, SHA-1 y NTLM — y sigue siendo muy rápido incluso para la cripta en pequeñas listas.
3. Fundaciones conceptuales: por qué los diccionarios trabajan
3.1 The Power Law of Human Passwords
Todos los estudios empíricos convergen hacia la misma observación: la distribución de contraseñas humanas no es uniforme — sigue a derecho del poder (Zipf). Algunas contraseñas concentran una fracción desproporcionada de opciones.
Formally : si todas las contraseñas se clasifican disminuyendo la frecuencia, la frecuencia de la contraseña de rango r es proporcional a r^(-α) con α 1,5 a 2 Según el cuerpo.Consecuencia directa: 10 contraseñas más comunes Un atacante que prueba sólo 10 candidatos ya tiene una oportunidad en 20 para tener éxito — estadísticamente, es enorme para la cantidad de ruido generado.
3.2 Bias cognitivas en la creación de contraseña
Los humanos no eligen al azar. Aplican sistemáticamente heurísticas que hacen predecibles sus contraseñas:
3.3 El concepto de "palabra ya en las listas"
Una contraseña puede estar en una lista de ataque por dos razones diferentes:
Razón 1 - Está en HIBP La credencial exacta ha sido comprometida en una fuga pasada. El atacante no necesita adivinar — prueba las credenciales conocidas uno por uno, en orden de frecuencia. Si el servidor de destino acepta la credencial, se termina. Razón 2 - Está en una lista de palabras lingüística La contraseña es una palabra ordinaria de vocabulario común. Incluso si nunca ha huido, es en todos los wordlists de ataque porque es un candidato obvio. "Paillon" puede no estar en HiBP, pero está en la lista de palabras francesa de cualquier herramienta de grieta seria.Estos dos casos corresponden a ataques de naturaleza diferente, con diferentes velocidades, y esto es precisamente lo que los modelos Time2Crack.
4. Arquitectura de un ataque de diccionario moderno
4.1 Gasoducto general
Un ataque de diccionario moderno tiene lugar en varias fases:
Phase 1 : Constitution de la wordlist
├── Mots de passe fuités (HIBP, RockYou, Collections)
├── Wordlists linguistiques (dictionnaires, prénoms, lieux)
├── Wordlists thématiques (sport, pop culture, tech, religion)
└── Wordlists contextuelles (domaine de l'entreprise cible, noms d'employés)
Fase 2: Preprocesamiento de la lista de palabras
- Ordenar por frecuencia (probablemente primero)
- Deduplicación (no el doble del mismo candidato)
- Filtración de la longitud (longitud del objetivo + ±2)
- Normalización (bajo, Unicode NFC)
Fase 3: Cálculo de Hashs Candidato
Para cada candidato w en la lista de palabras:
, hashcandidato = hahalgo(w)
Promocional si hashcandidato= hashMeta: finalizada
- Velocidad: 168 GH/s para MD5 en RTX 4090
Fase 4: Análisis de los resultados
Report of cracked passwords, coverage statistics
4.2 Optimizaciones de hardware
Los ataques de diccionario modernos son masivamente paralelos a la GPU:
Para una lista de palabras de 14 mil millones de entradas (tamaño HIP) en 12× RTX 4090:
Esta diferencia de ~9 órdenes de magnitud entre MD5 y bcrypt explica por qué la elección del algoritmo hash es crítica.
4.3 Orden de prueba de candidatos
La lista de palabras no se prueba en orden alfabético — es ordenados por la disminución de la probabilidad :
Este tipo asegura que si la contraseña es "bajo", se encontrará en los primeros milisegundos, sea cual sea la velocidad de precipitación.
5. El corpus de contraseñas reales
5.1 He estado Pwned (HIBP)
Tamaño ~14 mil millones de contraseñas únicas (2024) Fuente : agregación de fugas públicas desde 2013 Formato : SHA-1 ordenados por frecuencia de apariencia Acceso público : k- anonymity API, descarga completa de hash disponible para los defensoresHiBP es la referencia global porque:
Un atacante con el vertedero completo HIBP puede probar los ~14 mil millones de candidatos en orden descendente de frecuencia. Para algoritmos no saltados (MD5, SHA-1), esta lista cubre en el orden de 50-70% de todas las contraseñas en línea reales.
5.2 RockYou (2009) — Funding corpus
Tamaño : 14.3 millones de contraseñas claras Características clave : RankContraseñaOccurrences% del corpus --------------------------------------------------- 1123456290 7312.03% 21234579 0780,55% 312345678976 7900,54% 4contraseña59 4620,42% 5Te amo.49 9520,35% Top 10—~650.000~4.5% Top 100—~1 200 000~8.4% Top 1 000—~2 500 000~17,5% Top 10.000—~4 500 000-31,5% Educación Prueba sólo 10.000 candidatos (100 μs MD5 velocidad) compromisos ~31% de una base de datos de cuentas protegidas MD5.5.3 Colecciones de listas de palabras especializadas
SecLists (Daniel Miessler): colección de código abierto de ~4 GB listas de palabras que cubren:Estos cuerpos son descargables públicamente — su existencia es un hecho establecido de seguridad ofensiva.
6. K-Anonymity Verification HIBP: A Real-Time Attack
6.1 Protocolo k-Anonimato
Time2Crack incorpora un cheque HIBP en tiempo real que reproduce exactamente lo que un atacante haría con la base de datos HIBP, pero nunca transmite la contraseña en lenguaje llano o su hash completo.
El protocolo k-anonymity funciona como sigue:
1. Calculer SHA-1(password) → par exemple "CBFDAC6008F9CAB4083784CBD1874F76618D2A97"
Enviar sólo los primeros 5 caracteres a la API HIBP: "CBFDA"
La API devuelve TODOS los sufijos SHA-1 comenzando con "CBFDA" (aproximadamente 400-600 hashes)
Buscar localmente si el resto del hash ("C6008F9CAB4083784CBD1874F76618D2A97") está en la lista
Si se encuentra: la contraseña se ha comprometido (HIBP también devuelve el número de fugas)
Garantía de confidencialidad El servidor HIBP nunca ve el hash completo (por lo que no puede identificar la contraseña), ni mucho menos la contraseña clara. El cálculo final se hace localmente.
Lo que esto significa para el ataque : si HIBP devuelve una coincidencia con un alto recuento (p. ej. 9,547,236 apariciones para "123456"), esto significa que un atacante con la base de datos HIBP probar este credencial lo encontraría en una posición muy alta en su lista clasificada por frecuencia, en una fracción de nanosegundos.
6.2 Aplicación en Time2Crack (app.js)
El cheque HIBP es asincrónico y no bloqueo. La contraseña es analizada inmediatamente por métodos locales, y el cheque HIBP completa el resultado:
// Pseudo-code simplifié
async function checkHIBP(password) {
const sha1 = await sha1Hash(password);
const prefix = sha1.substring(0, 5); // 5 premiers chars
const suffix = sha1.substring(5); // reste du hash
const response = await fetch(
https://api.pwnedpasswords.com/range/${prefix}
);
const lines = await response.text();
para (línea contigua de líneas.split('\n') {
const [hashSuffix, count] = line.split(':');
si (hashSuffix.toLowerCase() = suffix.toLowerCase() {)
parseInt(count); // número de fugas
}
}
retorno 0; // no encontrado
}
Datos sobre el desempeño de la Oficina :
6.3 Interpretación del Conde HIBP
El recuento devuelto por HiBP indica el número de veces que esta contraseña exacta apareció en las filtraciones indexadas:
CondeInterpretaciónTiempo de cuna (MD5, 12× RTX 4090) ---.--- 1 000 000Top 100 World1 nanosegundo 10.000 a 1.000.000Muy común10 nanosegundos 1 000-10 000Común100 nanosegundos 100 a 11.000Infrecuente pero conocido1 microsegundo 1–100Rara pero comprometida10 microsegundosIncluso un recuento de 1 (la contraseña apareció sólo una vez en una fuga) indica una vulnerabilidad: si un atacante se dirige específicamente a esta cuenta y tiene la lista de credenciales de la fuga en cuestión, lo encontrará.
7. Time2Crack Language Wordlists
7.1 ¿Por qué los wordlists de idiomas además de HIBP
HiBP cubre las credenciales de compromiso exactas, pero no las palabras comunes nunca se agotan todavía. Un usuario de habla francesa que elige "ephemeral" como una contraseña puede no estar en HiBP (la palabra es poco probable en credenciales de aglofono), pero está en la lista de palabras francesa de cualquier atacante dirigido a un sistema de habla francesa.
Las listas de palabras de Time2Crack cubren esta brecha:
IdiomaFuenteTamaño estimado ------. InglésSecLists Wikipedia EN~ 200.000 entradas Francés (fr)SecLists Wikipedia EN~150.000 entradas EspañolSecLists Wikipedia ES~150.000 entradas Portugués (pt)SecLists Wikipedia PT~ 120.000 entradas AlemánSecLists Wikipedia DE~180.000 entradas Turco (tr)SecLists Wikipedia TR~100.000 entradas Italiano (it)kkrypt0nn~100.000 entradas Polaco (pl)kkrypt0nn~80 000 entries Países Bajos nl)kkrypt0nn~80 000 entries Filtro aplicado Sólo se mantienen palabras de ≥ 4 caracteres (los 1–3 caracteres son demasiado cortos para ser una contraseña realista, y su inclusión inflará la lista sin valor añadido).7.2 Carga perezosa
Las listas de palabras no están incluidas en el código — se cargan bajo petición al cambiar el idioma, para cubrir el presupuesto de la red:
// app.js - loadDictionary()
async function loadDictionary(lang) {
if (DICTlang " DICT "WORDS) return; // Déjà chargé
if (DICTLOADING) {
DICTPENDINGLANG = lang; // Archivo de espera
retorno;
}
DICTLOADING = true;
const res = await fetch(data/wordlists/${lang}.txt);
const text = await res.text();
// Convertir en Establecer referencias clave para la búsqueda O(1)
DICTWORDS = nuevo Set(
texto.split("\n")
.map(w = título w.normalize("NFC").trim().toLowerCase())
.filter(w = título w.length
);
DICTLANG = Lang;
DICTLOADING = false;
}
¿Por qué? Set ? Estructura Set JavaScript garantiza las revisiones O(1), independientemente del tamaño del diccionario (50.000 o 200.000 entradas), verificación DICTWORDS.has(word) toma el mismo tiempo constante. Array requeriría O(n) por consulta, es decir, hasta 200.000 comparaciones por cheque.
Carga de cola
El DICTFINLANG evita las condiciones de raza durante los cambios rápidos en el idioma:
Scénario : l'utilisateur switche rapidement EN → FR → DE
├── EN demandé : DICTLOADING = false → inicio de la fiesta EN
FR solicitada durante la captura EN : DICTLOADING = true → DICTFINLANG = "fr"
├── DE demandé pendant fetch EN : DICTLOADING = verdadero → DICTPENDINGLANG = "de" (crash "fr")
- Fin de la venta: DICTLANG = "en", puis lance loadDictionary("de")
└── Résultat : seule la dernière langue demandée est chargée
Este comportamiento es intencional: se carga el idioma más solicitado recientemente, no todos los idiomas intermedios.
8. Detección de Diccionario en Time2Crack: isDictWord()
8.1. Operación de detección
La función isDictWord(pw) determina si una contraseña es o se deriva de una palabra de diccionario actual:
// app.js - ligne 2181
function isDictWord(pw) {
if (!DICT(WORDS) devolver falso;
// Normalización: NFC + maleta inferior
const l = pw.normalize("NFC").toLowerCase();
// Verificación directa
si
WORDS.has(l) || DICTWORDS.has (deLeet(pw))) devolver verdadero;
// Variaciones morfológicas
const deleetWord = deLeet(pw);
const variaciones = getMorphVariations(deleetWord);
para (continuación de variaciones) {
si
WORDS.has(variation)) return true;
}
devolver falso;
}
3 capas de detección :
8.2 Normalización Unicode (NFC)
Normalización normalize("NFC") garantiza que los caracteres acentuados sean tratados consistentemente:
Esta estandarización se aplica tanto al crear el diccionario como al revisarlo, asegurando la correspondencia correcta para los lenguajes de acento (FR, ES, DE, PT, etc.).
8.3 Impacto en la vulnerabilidad detectada
Cuando isDictWord() Vuelve. truevarios ataques se aplican:
hybridVuln = true → 1000 mutaciones probadas en el diccionario9. De-leetificación: cómo el atacante descifra las sustituciones
9.1 Leetspeak y sus limitaciones como protección
El leetspeak (o "1337 discurso") es una práctica de reemplazar letras con números o símbolos visualmente similares: a→@, e→3, i→1 o !, o→0, s→$. Los usuarios lo usan para "fortalecer" palabras comunes.
La realidad: estas sustituciones son las primeras normas aplicadas no constituyen una defensa real contra un atacante competente.
9.2 Aplicación deLeet() en Time2Crack
// app.js - ligne 3622
const LEETBASE = {}
a: ["@", "4"],
e: ["3"],
["0"],
s: ["$", "5"],
t: ["+", "7"],
["#"],
["9"],
};
función deLeetWith(pw, oneMap) {
let r = pw.normalize("NFC").toLowerCase();
para (const [ch, reps] de Object.entries(LEET)
BASE))
for (const c of reps) r = r.split(c).join(ch);
// Appliquer la résolution ambiguë (i ou l) en dernier
for (const [ch, reps] of Object.entries(oneMap))
for (const c of reps) r = r.split(c).join(ch);
return r;
}
función de Leet(pw) {
// Ambigüedad: "1" puede ser "i" o "l"
const withI = deLeetWith(pw, { i: "1!", l: "" });
const withL = deLeetCon(pw, { l: "1", i: "!" });
// Si el diccionario está cargado, prefiera la variante que coincida
siWORDS {
siWORDS.has(withL)) retorno conL;
siWORDS.has(conI) return withI;
}
// De lo contrario: prefiere la variante con los números menos restantes
const digestsI = (con I.match(/\d/g)
const digestsL = (con L.match(/\d/g)
dígito de retorno L = dígito I? withL: withI;
}
9.3 Gestión de la ambigüedad "1" → "i" o "l"
La sustitución "1" es ambiguo: "1" puede representar "i" (como en "1nfo" → "info") o "l" (como en "p1ayer" → "jugador"). Time2Crack resuelve esta ambigüedad por:
9.4 Sustituciones no cubiertas (intencionadamente)
Time2Crack no cubre sustituciones raras o ambiguas más allá de los patrones de LEETBASE. Es una opción de diseño: cubrir demasiados casos aumentaría los falsos positivos (detectar una contraseña como una "palabra corriente" mientras que no lo es).Los patrones incluidos cubren √95% de las leetificaciones reales observadas en el corpus.
10. Cálculo del tiempo de grieta: addDictionaryAttacks()
Cálculo lógico
// app.js - ligne 3848
function addDictionaryAttacks(rows, common, weak, dictWord) {
for (const a of ALGOS) {
let sec;
if (weak) sec = 100 / a.rate; // Top ~100 entrées
else if (common) sec = 10000 / a.rate; // HIBP priority list ~10k
else if (dictWord) sec = 200000 / a.rate; // Scan wordlist complète ~200k mots
else sec = null; // Non applicable
nota const = débil ? t("nWeakPassword")
: común ? t("nInLeaks")
: dictWord ? t(nDictHit)
t(nAbsentLeaks);
rows.push({ atk: t("aDict"), hash: a.name, spleen: a.rate, sec, note, cat: "dict" });
}
}
10.2 Tres niveles de vulnerabilidad
Nivel 1 - Ultra-mojado (G)weak = true) : ~100 / bazo
La contraseña está en el Top 100 del mundo ("password", "123456", "qwerty"...). Un atacante que prueba a estos 100 candidatos prioritarios lo encuentra en el primer paso. 0.6 nanosegundo.
Nivel 2 - Común (G)common = true-10 000 / bazo
La contraseña está en la lista de referencia HIBP de las ~10.000 contraseñas más frecuentes. Estos candidatos se prueban en los primeros microsegundos. Para MD5: 10,000 / 168,9e9 59 nanoseconds.
Nivel 3 - DictWord (G)dictWord = true~200,000 / bazo
La contraseña es una palabra del diccionario de idioma actual (lista de palabras locales ~50k–200k entries). Un análisis completo de la lista de palabras es casi instantáneo para algoritmos rápidos. Para MD5: 200 000 / 168,9e9 1.18 microsecond.
Nivel 4 - No aplicable (G)sec = null) : la contraseña no es ni ultra-mojo, ni común, ni una palabra del diccionario actual. El ataque del diccionario solo no es aplicable - otros ataques (fuerza bruta, Markov, PCFG) se convierten en la principal amenaza.
10.3 ¿Por qué estos números (100, 10.000, 200.000)?
Estos valores se calibran a datos reales:
10.4 Ejemplo numérico completo
Para la contraseña "sun" (actual palabra francesa, detectada como dictWord)
Incluso para Argon2id, 250 segundos es menos de 5 minutos, para una simple palabra del diccionario francés.
11. Calibración de alta fidelidad: applyHighFidelityCalibration()
11.1 ¿Por qué la calibración adicional?
El cálculo bruto addDictionaryAttacks() da una estimación del "caso peor" — como si el atacante estuviera probando uniformemente toda la lista de palabras. ordenado por probabilidad : las contraseñas más comunes llegan primero.
La calibración de alta fidelidad aplica un multiplicador correctivo basado en observaciones empíricas:
// app.js - ligne 4442
case "dict":
// Ur et al. 2012 : mots communs trouvés dans les 100-10k premiers essais
// Weir 2009 : mots dict trouvés dans les 200k premiers essais (scan ordonné)
m = context.common? 0.15: context.dictWord ? 0.5: 1.0;
Break;
Multiplicador common (0.15) : si la contraseña está en la lista de prioridades comunes, se encuentra en promedio en el percentil 15 de la lista - que es ~1,500 pruebas de los 10.000 listados. El tiempo se multiplica por 0.15 → 6.7× más rápido que el análisis uniforme.
Multiplicador dictWord (0.5) : una palabra de diccionario común se encuentra en medio término medio promedio de una lista bien ordenada. Multiplier 0.5 → 2× más rápido que el escaneo uniforme.
Fuentes académicas de calibración
12. probabilidad de aplicabilidad y puntaje de confianza
12.1 Sistema de cableado
Time2Crack no solo calcula un tiempo — también evalúa la probabilidad de que el ataque del diccionario sea en realidad el ataque más rápido, a través de un sistema de puntuación multifactorial:
// Score d'applicabilité (0-1)
case "dict":
return context.common ? 0.99 : context.dictWord ? 0.85 : 0;
common La contraseña está en HIBP → el ataque del diccionario se aplica con máxima confianza.dictWord Sólo: alta probabilidad. Una palabra de diccionario es vulnerable, pero un atacante debe tener la lista lingüística correcta.12.2 Puntuación de la prueba
En paralelo con la puntuación de aplicabilidad, un marcador "prueba" registra las señales observadas:
case "dict":
return Number(!!context.common) + Number(!!context.dictWord);
// 0 : aucun signal
// 1 : un signal (common OU dictWord)
// 2 : deux signaux (common ET dictWord)
Una puntuación de evidencia de 2 (palabra en HIBP y diccionario lingüístico) aumenta la confianza final de 0.08 (2 × 0.04).
12.3 Puntuación final de la confianza
const base = confidenceBase["dict"] || 0.6; // confiance de base
const evidenceBoost = Math.min(0.12, row.evidenceScore 0.04);
const speculativePenalty = speculativeCats.has("dict") ? 0.08 : 0; // dict n'est pas spéculatif
row.confidence = Math.max(0, Math.min(1,
Math.max(aplicabilidad, base) + evidenciaBoost - específicoPenalty
));
Para una contraseña common con dictWord también detectado:
applicability = 0.99evidenceBoost = min(0.12, 2 × 0.04) = 0.08confidence = min(1, max(0.99, 0.6) + 0.08) = min(1, 1.07) = 1.0Confianza máxima: El ataque del diccionario es el ataque primario sin ambigüedad.
13. Bloom filter RockYou: detección local de contraseñas generalizadas
13.1 Antecedentes
Además de la verificación HIBP (que requiere una llamada de red), Time2Crack incorpora una filtro Un filtro de floración es una estructura probabilística de datos que le permite probar pertenecer a un conjunto con una probabilidad de falsos positivos (~1%), sin almacenar los mismos elementos.
13.2 Beneficios del filtro de floración
CriteriosHIBP k- anónimoFiltro de Bloom local --------.--- Cobertura~14 mil millones~14 millones (RockYou) Latency50–200 ms (redes)1 ms (local) Confidencialidadk- anonimato (5 tanques SHA-1)100% local, nada transmitido Falso positivo0%~1% TamañoAPI~2-5 MB (bloom filter binario)13.3 Operación de doble escoria
// app.js - ligne 1962
function bloomHas(filter, word) {
if (!filter) return false;
const { bitArray, m, k } = filter;
const w = word.toLowerCase();
// Doble-hashing: h1 y h2 son dos funciones de hash independientes
const h1 = fnv1a32(w, 2166136261); // FNV1a con semilla estándar
const h2 = fnv1a32(w, 0x811c9dc5); // FNV1a con semilla alternativa
para (let i = 0; i)
const pos = (h1 + i (h2) нелиныминых (0)) % m; // k posiciones en la matriz de bits
const byteIdx = Math.floor(pos / 8);
const bitIdx = pos % 8;
// Si un poco es 0: la palabra está ausente
si ((bitArray[byteIdx] " (1 Identificado bitIdx)) = 0) devuelve falso;
}
// Todos los bits son a 1 : la palabra es PROBABLY presente (con 1% de FP)
retorno verdadero;
}
El FNV1a doble-hashing garantiza una distribución uniforme de posiciones en la matriz de bits, minimizando las colisiones y manteniendo la tasa de falsos positivos cerca del 1%.
13.4 Carga y formato binario
El filtro de floración se almacena en data/rockyou.bloom — un archivo binario con:
La carga es activada manualmente por el usuario (botón en la interfaz de usuario), no automáticamente en la carga de la página, para preservar el rendimiento inicial.
14. Comparación con los ataques derivados
El ataque del diccionario "puro" es el primero de una familia de ataques que todos comparten una raíz común: una lista de palabras lexical. Time2Crack implementa 7 modelos de grieta offline (fuerza de grieta, diccionario, híbrido, máscara, PCFG, Markov, combinador), cada uno atacando la contraseña desde un ángulo diferente.
14.1 Diccionario vs híbrido
CriteriosDiccionarioHybrid (dict+rules) ---------------------------- CandidatosDiccionario Palabras comoPalabras + ~1000 mutaciones por palabra Keyspace200.000 candidatos~200 millones de candidatos Ejemplos desgarrados"password", "sun""¡P@ssw0rd!", "s0l3il2024" Velocidad relativa1000× más rápidoGran cobertura Aplicable sipalabra exacta en la listaContraseña derivada de una palabra dictEl ataque híbrido comienza donde el diccionario puro se detiene: toma cada palabra de la lista de palabras y aplica reglas de mutación sistemática (hashcat "best64.rule" en mente).
14.2 Diccionario vs PCFG
CriteriosDiccionarioPCFG --------------------------- ModeloLista fija de candidatosGramática de estructura probabilística FuerzaPalabras precisasEstructuras Word+Digits, Cap+lower+sym Ejemplo"password" → ✓"Password123" → ✓ (estructura detectada) Coberturavocabulario conocidoEstructuras humanas genéticasUna contraseña como "Password123" puede pasar desapercibida en un diccionario (la palabra exacta "Password123" no puede ser listada) pero se romperá muy rápidamente por PCFG que reconoce la estructura [Majuscule][minuscules][digits].
14.3 Diccionario vs Markov
CriteriosDiccionarioMarkov --------------------------- CandidatosLista precompiladaFly-generated by statistical model Coberturavocabulario conocidoCualquier secuencia "humana" probable VentajasMuy rápido en palabras exactasCubre palabras de vocabulario desconocidas Ejemplo"sunshine" → ✓"sunsh1ne" potencialmente ✓Markov cubre casos donde la contraseña parece una palabra humana sin estar en ninguna lista.
14.4 Dictionary vs Credential Stuffing
CriteriosDiccionarioCrédential Stuffing --------------------------- ObjetivoCracking a hashPruebe un login específico MecanismoComputación local de HashPruebas de conexión remota FuenteGenérico WordlistPareja de inicio de sesión / filtraciones de contraseña Defensaalgoritmo de hash fuerteLimitación de tarifas, MFA, bloqueo IPEl relleno de credencial no ataca un hash – intenta directamente conectarse/password pares en servicios remotos. Es conceptualmente diferente de la grieta, pero comparte la misma fuente de datos (HIBP/fail).
15. Limitaciones del diccionario de ataque
15.1 Límites intrínsecos
1. El vocabulario conocido sólo Una contraseña inventada que no se asemeja a ninguna palabra existente y no está en HiBP es impermeable al ataque de diccionario puro. "Xqz7mK9pL" nunca estará en ninguna lista de palabras. 2. Cobertura lingüística Un atacante dirigido a un usuario de habla francesa sin una lista de palabras francesa perderá palabras como "ephemeral", "grenouille", o "bricolage" que no están en las listas de palabras inglesas estándar. 3. Nuevas contraseñas Una credencial que acaba de crearse y nunca ha huido no estará en HiBP, aunque sea muy común, tendrá que esperar hasta la próxima fuga para encontrarla. 4. contraseñas muy largas Una contraseña que consiste en una frase inventada largamente ("MaGrandeAventure2024SousLesEtoiles") no estará en ninguna lista de palabras, incluso si cada palabra tomada por separado es trivial. Esta es la idea detrás de las contraseñas, tratada por otros ataques (Combinador, PRINCE).15.2 ¿Qué cálculo de Time2Crack no modela
Context Wordlists : un atacante dirigido a un sector específico construirá listas de palabras adaptadas (condiciones médicas para hospitales, videojuegos slang para plataformas de juego). Listas de palabras de fuerza bruta combinadas : Herramientas como CeWL (Custom Word List Generator) pueden extraer términos del sitio web objetivo para construir una lista de palabras personalizada. Este nivel de selección no se modela. Residuos recientes aún no en HIBP entre el momento en que se produce una fuga y su integración en HIBP, las credenciales comprometidas circulan en foros privados sin ser accesibles a través de la API pública. algoritmos de Hash no cubiertos Time2Crack modelos 6 algoritmos (MD5, SHA-1, SHA-256, NTLM, bcrypt, Argon2id). Los algoritmos como SHA-512, scrypt o PBKDF2 tienen diferentes perfiles.16. Defensas eficaces
16.1 Lo que protege contra el ataque del diccionario
algoritmo moderno de hash (bcrypt, Argon2id) Esta es la defensa más efectiva en el lado servidor.La diferencia de 10+ órdenes de magnitud entre MD5 y Argon2id hace que la contraseña del diccionario "sun" inmune en la práctica si está protegida por Argon2id, incluso si el atacante sabe que es una palabra francesa.
Sal única por cuenta Una sal evita los ataques de mesa precalculados y obliga al atacante a recalcular individualmente para cada cuenta. No protege los ataques selectivos de las listas de palabras (el atacante todavía puede probar las 200.000 palabras con la sal), pero invalida las tablas de arco iris y hace que los ataques masivos en grandes bases de datos sean impracticables. Duración de la contraseña Una contraseña de una sola palabra de diccionario (8-10 caracteres) es vulnerable. Un passphrase de 4-5 palabras ("cheval-lumière-forest-voyage") es resistente al ataque del diccionario puro pero no al ataque del Combinador, por lo tanto la importancia de la longitud Y la aleatoriedad. contraseñas generadas aleatoriamente La solución real: use un gestor de contraseñas que genere contraseñas aleatorias largas (20+ caracteres de todo tipo). Estas contraseñas nunca estarán en ningún diccionario. autenticación multifactorial (MFA) El MFA no evita el crack fuera de línea (el atacante recupera los hashs y cracks fuera de línea), pero protege contra el relleno credencial (usar credenciales cracked para conectar). Tasa de limitación y detección de anomalías Protege contra ataques en línea (intentes de conexión directa), no contra el cracking fuera de línea de hashs robados.16.2 Lo que no protege
Sustituciones de hoja simple : "password" → "p@ssw0rd" — ver la sección 9. Números añadidos al final : "password" → "password1" — entre las primeras reglas probadas. Pago inicial : "password" → "Password" — regla de capitalización estándar. Figuras y símbolos si la palabra permanece reconocible "sunshine!" está en cualquier lista de palabras que incluye "sunshine" con reglas básicas. Complejidad impuesta sin longitud "P@s1w" cumple con los criterios de complejidad (maj, min, número, símbolo) pero es más corto y más predecible que "horsebaterystaple".16.3 Recomendaciones prácticas
17. Referencias
Fuentes primarias (estudios académicos)
Morris, R., " Thompson, K. (1979). Seguridad de contraseña: historial de casos. Comunicaciones de la ACM, 22(11), 594-597.common ? 0.15 (nivel superior a 10k)Fuentes industriales
¿He sido Pwned. (2024). contraseñas desgarradas. https://haveibeenpwned.com/PasswordsFuentes secundarias (contexto)
Troy Hunt. (2013). Introducción 306 Millones de contraseñas desplegadas gratuitamente. troyhunt.com.Fuentes web citadas en la aplicación Time2Crack
IEEE Xplore (referencia diccionario). https://ieeexplore.ieee.org/document/6234435descDict (app.js) para el orden de cobertura de los diccionarios superiores.Documento generado para el Proyecto Time2Crack — Versión 1.0 — 2026-04-01 Código fuente:
app.js (funciones addDictionaryAttacks, isDictWord, deLeet, loadDictionary, applyHighFidelityCalibration, bloomHas)*