import streamlit as st import time import itertools import string import requests # ---------------------------- # Configuración de la página # ---------------------------- st.set_page_config( page_title="🔐 Ataques a Contraseñas - Demo Educativa", page_icon="🔐", layout="centered" ) st.title("🔐 Ataques a Contraseñas") st.markdown(""" **Demo educativa** usando contraseñas reales del top 10,000 más comunes (SecLists). Ingresa una contraseña **simple** (máx. 6 caracteres, solo minúsculas y números). ⚠️ **Solo para fines didácticos. No uses contraseñas reales.** """) # ---------------------------- # Cargar diccionario real desde SecLists (solo una vez) # ---------------------------- @st.cache_resource def load_common_passwords(): url = "https://raw.githubusercontent.com/danielmiessler/SecLists/master/Passwords/Common-Credentials/10k-most-common.txt" try: with st.spinner("📥 Cargando diccionario real (top 10k contraseñas)..."): response = requests.get(url, timeout=10) response.raise_for_status() # Filtrar: solo contraseñas de 1 a 6 caracteres, alfanuméricas passwords = [] for line in response.text.splitlines(): p = line.strip().lower() if 1 <= len(p) <= 6 and p.isalnum(): passwords.append(p) if len(passwords) >= 5000: # Límite para velocidad break return passwords except Exception as e: st.warning("⚠️ No se pudo cargar el diccionario. Usando lista de respaldo.") return [ "123456", "12345", "password", "qwerty", "abc123", "admin", "letmein", "welcome", "monkey", "dragon", "123123", "sunshine", "iloveyou", "princess", "football" ] COMMON_PASSWORDS = load_common_passwords() # ---------------------------- # Funciones de ataque # ---------------------------- def brute_force_attack(target, max_length=6): chars = string.ascii_lowercase + string.digits start_time = time.time() attempts = 0 for length in range(1, max_length + 1): for guess_tuple in itertools.product(chars, repeat=length): guess = ''.join(guess_tuple) attempts += 1 if guess == target: return guess, attempts, time.time() - start_time return None, attempts, time.time() - start_time def dictionary_attack(target): start_time = time.time() attempts = 0 for guess in COMMON_PASSWORDS: attempts += 1 if guess == target: return guess, attempts, time.time() - start_time return None, attempts, time.time() - start_time def hybrid_attack(target): start_time = time.time() attempts = 0 base_words = ["password", "admin", "user", "test", "hello", "welcome", "qwerty", "love", "sunshine", "dragon"] suffixes = ["", "1", "123", "2023", "2024", "!", "01", "12", "789"] transformations = set() for word in base_words: for suf in suffixes: # Original y capitalizada transformations.add(word + suf) transformations.add(word.capitalize() + suf) # Reemplazos comunes w = word.replace('a', '@').replace('e', '3').replace('o', '0').replace('i', '1') transformations.add(w + suf) transformations.add(w.capitalize() + suf) for guess in transformations: attempts += 1 if guess == target: return guess, attempts, time.time() - start_time return None, attempts, time.time() - start_time # ---------------------------- # Interfaz de usuario # ---------------------------- password = st.text_input( "🔒 Ingresa una contraseña de prueba (máx. 6 caracteres, minúsculas y números):", type="password", max_chars=6 ) # Validación básica if password and not all(c in (string.ascii_lowercase + string.digits) for c in password): st.warning("⚠️ Usa solo letras minúsculas y números (ej: 'abc123').") password = "" attack_type = st.selectbox("🎯 Elige un tipo de ataque:", ["Fuerza Bruta", "Diccionario", "Híbrido"]) if st.button("🚀 Iniciar ataque", disabled=not password): if len(password) > 6: st.error("La contraseña debe tener máximo 6 caracteres.") else: with st.spinner("Buscando..."): if attack_type == "Fuerza Bruta": result, attempts, duration = brute_force_attack(password, len(password)) elif attack_type == "Diccionario": result, attempts, duration = dictionary_attack(password) else: # Híbrido result, attempts, duration = hybrid_attack(password) if result: st.success(f"✅ ¡Contraseña encontrada! `{result}`") st.metric("Tiempo", f"{duration:.2f} segundos") st.metric("Intentos", f"{attempts:,}") st.balloons() else: st.error("❌ Contraseña no encontrada con este método.") st.metric("Intentos realizados", f"{attempts:,}") st.info("💡 Prueba una contraseña más común o más corta.") # ---------------------------- # Pie de página # ---------------------------- st.markdown("---") st.caption( "🎓 Demo educativa usando el diccionario '10k-most-common.txt' de SecLists (GitHub). " "Todo se ejecuta localmente. Código ético y sin riesgos." )