File size: 5,461 Bytes
9bc63e5
df4bbaa
 
 
803b069
9bc63e5
df4bbaa
 
 
 
 
 
 
 
 
 
 
803b069
 
df4bbaa
 
 
 
803b069
df4bbaa
803b069
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
df4bbaa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
803b069
 
 
df4bbaa
 
803b069
 
 
 
 
 
 
 
df4bbaa
 
 
 
 
 
 
 
803b069
 
 
 
 
df4bbaa
 
 
 
 
 
803b069
df4bbaa
 
 
803b069
df4bbaa
803b069
 
 
 
 
 
 
df4bbaa
 
 
 
 
 
 
 
 
803b069
df4bbaa
 
 
 
 
803b069
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
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."
)