Python zipfile library fix
Question: I've got a problem. I've made a simple zip file with password 12345. Now, when
I try to extract the password using brute-force, zipfile chooses wrong
password. It says it found password aaln0, but the extracted file is completly
empty. Is there a way to 'fix' the library? Or is there a replacement for it?
Thanks

Program code:

    
    
    #!/usr/bin/env python
    import itertools
    import threading
    import argparse
    import time
    import zipfile
    import string
    global found
    found = False
    
    def extract_zip(zFile, password):
        """
        Extract archive with password
        """
        try:
            zFile.extractall(pwd=password)
            write("[+] Password found:", password, "\n")
            global found
            found = True
        except Exception, e:
            pass
    
    def write(*args):
        print "[%s] %s" % (time.ctime(), " ".join(args))
    
    def main_loop(zFile, length):
        """
        Main loop
        """
        write("[*] Python Brute-Force zip cracker")
        write("[*] Zipfile: %s; password length: %s" % (zFile, length))
        try:
            zfile = zipfile.ZipFile(zFile)
        except:
            write("Cannot open zip file")
            exit(1)
        for combo in itertools.imap(''.join, itertools.product(string.letters + string.digits,
                                                                repeat=length)):
            if found:
                break
            thread = threading.Thread(target=extract_zip, args=(zfile, combo))
            thread.start()
        if not found:
            write("[-] Password not found")
    
    def main():
        """
        Main function
        """
        parser = argparse.ArgumentParser(usage="brute-force-zipcracker.py -f <zipfile> -l <password length>")
        parser.add_argument("-f", "--zipfile", help="specify zip file", type=str)
        parser.add_argument("-l", "--length", type=int, help="password length", default=5)
        args = parser.parse_args()
        if (args.zipfile == None):
            print parser.usage
            exit(0)
    
        main_loop(args.zipfile, args.length)
    
    if __name__ == '__main__':
        main()
    


Answer: First of all, you're doing:

    
    
    for combo in itertools.imap(...):
        if found:
            break
        thread = ...
        thread.start()
    if not found:
        ...
    

Just look at it for a second.  
`found` is defined in a thread, but you're starting multiple threads and you
globally hope that it will be set in one of the threads. How can you ensure
that the correct thread has done the proper job? What if there's a false
positive in one of the threads and you don't bother to retrieve the value from
each individual thread. Careful with your threads!

Secondly, if the threads don't finish in time for your `combo` loop you'll end
up in `if not found` because the threads haven't finished running yet to find
what you're looking for, especially if you have a larger zip-file that takes a
few seconds to complete (a successful password would start unzipping the file
and it could take minutes, and `found` will not be set until that process is
done).

And finally it would be neat to get the parameters used to protect this zip-
file.

Edit:

You could also give us more information in the format of:

    
    
    zFile.debug(3)
    zFile.testzip()
    zFile.extractall(pwd=password)
    

And other useful things from `zipfile.ZipInfo(filename)`

## To the solution then

    
    
    #!/usr/bin/env python
    import itertools
    import argparse
    import zipfile
    import string
    
    def extract_zip(filename, password):
        try:
            zFile = zipefile.ZipFile(filename)
            zFile.extractall(pwd=password)
            return True
        except zipfile.BadZipFile:
            return False
    
    def main_loop(filename, length):
        print("[*] Python Brute-Force zip cracker")
        print("[*] Zipfile: %s; password length: %s" % (zFile, length))
        cracked = False
        for combo in itertools.imap(''.join, itertools.product(string.letters + string.digits, repeat=length)):
            cracked = extract_zip(filename, combo)
            if cracked:
                print('Yaay your password is:',combo)
                break
        if not cracked:
            print('Sorry, no luck..')
    def main():
        parser = argparse.ArgumentParser(usage="brute-force-zipcracker.py -f <zipfile> -l <password length>")
        parser.add_argument("-f", "--zipfile", help="specify zip file", type=str)
        parser.add_argument("-l", "--length", type=int, help="password length", default=5)
        args = parser.parse_args()
        if (args.zipfile == None):
            print parser.usage
            exit(0)
    
        main_loop(args.zipfile, args.length)
    
    if __name__ == '__main__':
        main()
    

