Make password/hash verification algorithm more efficient
Starting with the code in my answer to your related question, we can factor out the source of the words being guessed and encapsulate it all in functions:

def get_users_to_crack(file_name):
    users = {}
    with open(file_name) as file:
        for line in file:
            username, hashed_password, *_ = line.split(':')
            users[username] = hashed_password
    return users

def crack(users, words):
    cracked_users = {}
    for password in words:
        if not users:
            print("Cracked all passwords")
            return cracked_users, {}
        for username, hashed_password in users.items():
            if crypt.crypt(password, hashed_password) == hashed_password:
                print(f'La contraseña del usuario {username} es {password}')
                cracked_users[username] = password
                del users[username]
    return cracked_users, users


Now we just need a supplier of words. This can be either from a file, similar to your other question:

def dictionary_attack(file_name):
    with open(file_name) as file:
        for line in file:
            word = line.rstrip('\n').capitalize()
            if 4 &lt;= len(word) &lt;= 8:
                yield word


Or you build it yourself, according to the scheme you supplied here:

from string import ascii_lowercase as a_z, ascii_uppercase as A_Z, digits
from itertools import product

def get_chars(length):
    """Produces the allowed chars according to the scheme given
       [a-zA-Z][a-z]*(0-5)[a-z0-9]*2"""
    assert length &gt; 2
    return [a_z + A_Z] + [a_z] * (length - 3) + [a_z + digits] * 2

def brute_force(min_length, max_length, get_chars):
    for length in range(min_length, max_length + 1):
        for word in product(*get_chars(length)):
            yield "".join(word)


You can then combine them into one nice tool:

if __name__ == "__main__":
    users = get_users_to_crack("shadow3")
    n = len(users)

    users_cracked_1, users = crack(users, dictionary_attack('out68.lst'))
    print(f"Cracked {len(users_cracked_1)} out of {n} users passwords using a dictionary attack")

    users_cracked_2, users = crack(users, brute_force(4, 8, get_chars))
    print(f"Cracked {len(users_cracked_2)} out of {n} users passwords using brute force")

    if users:
        print(f"{len(users)} users passwords not cracked")