Search code examples
pythonasynchronousbrute-force

Is there a way to create a variable that will be accessible by all futures from ProcessPoolExecutor?


I'm writing a simple brute force function with a ProcessPoolExecutor. The task is to find matching hashes of 8-digit passwords.

And I noticed a problem that if all given passwords are found, the function will be still looping.

I tried to implement a global counter variable, but as I soon realized, it is not shared between futures. Is there any way to create a counter or maybe something else that all processes will be aware of to cut the execution time?

Here is my executor manager:

def brute_force_password() -> None:
    futures = []

    with ProcessPoolExecutor(multiprocessing.cpu_count()) as executor:

        for interval in range(len(PASSWORDS_TO_BRUTE_FORCE)):
            futures.append(
                executor.submit(
                    check_password_in_interval,
                    interval * 1_000_0000,
                    (interval + 1) * 1_000_0000
                )
            )

    wait(futures)

And loop-checking function:

def check_password_in_interval(start: int, end: int) -> None:
    for guess in range(start, end):
        guess = f"{guess:08d}"
        hashed_guess = sha256_hash_str(guess)

        if hashed_guess in PASSWORDS_TO_BRUTE_FORCE:
            index = PASSWORDS_TO_BRUTE_FORCE.index(hashed_guess)
            HACKED_PASSWORDS[index] = guess

            print(f"{hashed_guess} is {guess}.")

I'll appreciate your time and help!

What I tried: global and environment variables


Solution

  • you can try and use multiprocessing which allows you to share values across processes:

    import multiprocessing
    from concurrent.futures import ProcessPoolExecutor, wait
    from ctypes import c_int
    
    def brute_force_password(passwords_found: multiprocessing.Value) -> None:
        futures = []
        with ProcessPoolExecutor(multiprocessing.cpu_count()) as executor:
            for interval in range(len(PASSWORDS_TO_BRUTE_FORCE)):
                futures.append(
                    executor.submit(
                        check_password_in_interval,
                        interval * 1_000_0000,
                        (interval + 1) * 1_000_0000,
                        passwords_found
                    )
                )
            wait(futures)
    
    def check_password_in_interval(start: int, end: int, passwords_found: multiprocessing.Value) -> None:
        for guess in range(start, end):
            guess = f"{guess:08d}"
            hashed_guess = sha256_hash_str(guess)
            if hashed_guess in PASSWORDS_TO_BRUTE_FORCE:
                with passwords_found.get_lock():
                    index = PASSWORDS_TO_BRUTE_FORCE.index(hashed_guess)
                    HACKED_PASSWORDS[index] = guess
                    passwords_found.value += 1
                    print(f"{hashed_guess} is {guess}.")
                    if passwords_found.value == len(PASSWORDS_TO_BRUTE_FORCE):
                        return
    
    if __name__ == '__main__':
        passwords_found = multiprocessing.Value(c_int, 0)
        brute_force_password(passwords_found)