0

I have very strange behavior with zipfile class and I hope that someone can help me solve the problem that bothers me.

I wrote a short script which tries to open zip file encrypted by password (it was ziped by WinRar), but turned out that zipfile class does not rise an exception for several other passwords which are incorrect.

So my password for the zip file was 'evil' but zFile.extractall did not rise execpction when password was one of

  • 'checkouts',
  • 'disannuller',
  • 'euornithes' or
  • 'yamaltu'.

Additional content after extracting with zipfile class using any listed passwords were incorrect. Even WinRar does not allow unziping using those passwords.

My Python code is as follows:

import zipfile

diffrentPass = [
            'wrongpass1',
            'wrongpass2',
            'checkouts',
            'disannuller',
            'euornithes',
            'evil',
            'yamaltu']


def extractFile(zFile, password):
    try:
        answer= zFile.extractall(pwd=password)
        print 'Fount password : ', password
    except:
        pass

def main():
    zFile = zipfile.ZipFile("evil.zip")

    for password in diffrentPass:
        extractFile(zFile, password)

    if __name__ == '__main__':
        main()

UPDATE :

I know that i skipped exception, but please look on out from program :

wrongpass1 was incorrect
wrongpass2 was incorrect
Fount password :  checkouts
Fount password :  disannuller
Fount password :  euornithes
Fount password :  evil
Fount password :  yamaltu

Process finished with exit code 0

lines :

Fount password :  checkouts
Fount password :  disannuller
Fount password :  euornithes
Fount password :  yamaltu

should not appear at all

Adding for example :

def extractFile(zFile, password):
    try:
        answer= zFile.extractall(pwd=password)
        print 'Fount password : ', password
    except Exception, e:
        print password + " was incorrect"

nothing changes in output


UPDATE + what happened

@Phil Frost Explain what happened

to be sure that it is actually the point of the my problem i add to scripts some debug prints to compare check_byte in password and file.

Example output :

#!! Wrong pass, check_byte are diffrent
#  raised RuntimeError("Bad password for file", name)
Checking bytes for :  wrongpass1
pass check_byte : 47
file check_byte  112
Pass is correct for zipfile class :  False

#!! wrong password but for zipFile is ok , check_byte are the same 
# but file will be the unpacked incorrectly
# RuntimeError("Bad password for file", name) will be not rise
Checking bytes for :  checkouts
pass check_byte : 112
file check_byte  112
Pass is correct for zipfile class :  True
Fount password :  checkouts

#!! password ok 
Checking bytes for :  evil
pass check_byte : 112
file check_byte  112
Pass is correct for zipfile class :  True
Fount password :  evil

Code :

import zipfile, zlib, binascii, struct
from zipfile import _ZipDecrypter

diffrentPass = [
    'wrongpass1',
    'wrongpass2',
    'checkouts',
    'disannuller',
    'euornithes',
    'evil',
    'yamaltu',
    'wrongpass1',]



def extractFile(zFile, password, bytes):


    print '\nChecking bytes for : ', password
    zd = _ZipDecrypter(password)
    h = map(zd, bytes[0:12])

    print 'pass check_byte :', ord(h[11])

    for item in zFile.infolist():
        if item.flag_bits & 0x8:
            check_byte = (item._raw_time >> 8) & 0xff
        else:
            check_byte = (item.CRC >> 24) & 0xff
        print 'file check_byte ',check_byte

    print "Pass is correct for zipfile class : " ,  ord(h[11]) == check_byte

    try:
        answer= zFile.extractall(pwd=password)
        print 'Fount password : ', password
    except Exception, e:
        pass



def main():

    # begining of ziped file must be cut off  dummy method works ony on this specific zip file
    # ....20111126036.jpg
    bytes = open('evil.zip', 'rb').read(45+12)[-12:]

    zFile = zipfile.ZipFile("evil.zip")

    for password in diffrentPass:
        extractFile(zFile, password,bytes)

if __name__ == '__main__':
    main()
Dharman
  • 30,962
  • 25
  • 85
  • 135
  • 3
    it does raise an exception you are just ignoring it with by calling pass – Uku Loskit Dec 30 '12 at 14:30
  • Make sure as Uku wrote to use (i think it would be) except NameError: and then do stuff instead of pass. An example could be: messagebox.showerror("Error", "Wrong password"). – Evilunclebill Dec 30 '12 at 14:36
  • but if exepction is rised in line answer= zFile.extractall(pwd=password) next line should not be executed... – Dariusz Kempa Dec 30 '12 at 14:36
  • I think you misunderstand except. Except is when the try: fails. So, you try if the password is correct in try, if its not the program will go to except. – Evilunclebill Dec 30 '12 at 14:41
  • Can you try using a *fresh* `zFile` each time? Maybe the class caches correct passwords? If you add `wrongpass1` to the end *again*, will it be reported as correct the second time? – Has QUIT--Anony-Mousse Dec 30 '12 at 15:01
  • @Dariusz looking on the print statements The correct password is `checkouts` i think, after valid password break the for loop to check next password. The file is already extracted so next passwords also getting valid somehow. – Aamir Rind Dec 30 '12 at 15:04
  • @Anony-MousseI added on list next wrong password and nothing has changed – Dariusz Kempa Dec 30 '12 at 15:08
  • @Aamir Adnan correct password is for sure evil ... – Dariusz Kempa Dec 30 '12 at 15:09
  • @Dariusz I have tested the code, even if i don't break the loop, the next password is printed as `incorrect password`. There is nothing wrong. It prints only a single password as valid which is `evil` – Aamir Rind Dec 30 '12 at 15:13
  • I have tested it on python 2.7.3 it works as expected the issue which you are facing was on 2.6 version. Don't know how many other versions of Python has this issue – Aamir Rind Dec 30 '12 at 15:30
  • hmm, please use print e, so when can see what's really going on, my code probably some other execption is occuring – Uku Loskit Dec 30 '12 at 16:05

5 Answers5

3

The exception is raised, but you are "swallowing it", because you do not show any error on it and just ignore it by calling "pass".

Also, there's another problem with your code, main module part is indented incorrectly. In your current code the main() is never called because the call to the main module is part of the definition of main()

import zipfile

diffrentPass = [
            'wrongpass1',
            'wrongpass2',
            'checkouts',
            'disannuller',
            'euornithes',
            'evil',
            'yamaltu']


def extractFile(zFile, password):
    try:
        answer= zFile.extractall(pwd=password)
        print 'Fount password : ', password
    except:
        print password + " was incorrect"


def main():
    zFile = zipfile.ZipFile("evil.zip")

    for password in diffrentPass:
        extractFile(zFile, password)

if __name__ == '__main__':
    main()
Uku Loskit
  • 40,868
  • 9
  • 92
  • 93
  • Not ... I know that out from this code... wrongpass1 was incorrect wrongpass2 was incorrect Fount password : checkouts Fount password : disannuller Fount password : euornithes Fount password : evil Fount password : yamaltu Process finished with exit code 0 – Dariusz Kempa Dec 30 '12 at 14:47
  • works fine for me apart from the fact that it should actually stop when it has found the correct one :) – Uku Loskit Dec 30 '12 at 14:59
  • @UkuLoskit of course you could stop when you found a matching password, but it shouldn't start reporting incorrect passwords after that either way. – Has QUIT--Anony-Mousse Dec 30 '12 at 15:06
1

I'm guessing the goal of this program is to brute-force the password out of a zip file. I'm guessing that you have a longer list of passwords that you have tried, and just the few listed in the question are not raising exceptions, while you have many more that behaved as expected.

It seems to me that as zipfile is implemented, you have a 1 in 255 chance of a password being accepted, and thus not raising an exception. This is because the password is validated by checking a 1-byte checksum:

if ord(h[11]) != check_byte:
    raise RuntimeError("Bad password for file", name)

(full source)

Edit: after further research, this could be a duplicate question.

As far as I'm aware, zip encryption is weak and easily broken through means other than brute-force. However, I've never had a reason to do it myself and I don't know the particulars of what you are trying to accomplish, so I can't suggest a more specific solution.

Community
  • 1
  • 1
Phil Frost
  • 3,668
  • 21
  • 29
0

You have ignored the exception in your code. If you want it to raise exception, then:

def extractFile(zFile, password):
    try:
        answer= zFile.extractall(pwd=password)
        print 'Fount password : ', password
    except Exception, e:
        # do something here before raising exception
        raise e

Or do not use try except block at all.

Edit after comment

If you want to report that password is wrong then you have to do that in except block, because when zFile.extractall(pwd=password) is executed exception is already thrown for the bad password, so the print will never executed.

def extractFile(zFile, password):
    try:
        answer= zFile.extractall(pwd=password)
        print 'Password "%s" is correct' % password
    except Exception, e:
        print 'Password "%s" is incorrect' % password
        pass
Aamir Rind
  • 38,793
  • 23
  • 126
  • 164
  • The `print` will not execute when the excetion is originally thrown. What is wrong with not reporting the *expected* error? – Has QUIT--Anony-Mousse Dec 30 '12 at 14:37
  • There is something wrong with you last except. The except in your example will print 'fount password' when the password is inccorect? – Evilunclebill Dec 30 '12 at 14:43
  • @Evilunclebill I really don't know what does `Fount` mean I thought it is a word of another language. I have updated answer using English message. – Aamir Rind Dec 30 '12 at 14:47
  • I think its a bend version of "found" ;-) – Evilunclebill Dec 30 '12 at 14:51
  • @Dariusz can you put the `evil.zip` file some where e.g. in dropbox and share it so that we can execute your code on it and identify the issue. (If file is not private) – Aamir Rind Dec 30 '12 at 14:57
0

It looks like you are explicitly discarding any exception that might be raised, here:

try:
    answer= zFile.extractall(pwd=password)
    print 'Fount password : ', password
except:
    pass

if zFile.extractall() raises an exception, then the except: block is executed. Your except block contains pass, which in python means "do nothing" or "no-op".

Phil Frost
  • 3,668
  • 21
  • 29
  • The `print` will not execute when the excetion is originally thrown. What is wrong with not reporting the *expected* error? – Has QUIT--Anony-Mousse Dec 30 '12 at 14:35
  • @Anony-Mousse good point. I realize now that the intent of the code must be to try many passwords and print the one that is correct. I'd suggest structuring the code differently to make that clear, but that would be getting off-topic. – Phil Frost Dec 30 '12 at 14:56
0
try:
    zFile.extractall(pwd=password)
    print 'Fount password : ', password
except:
    pass

I removed the "answer =", it didn't make any sense. Also if you want a way out of the exception handler loop you could do this:

def zipExit(password):
    print 'Password found: '+password
    exit(0)

def extractFile(zFile, password)
    try:    
        zFile.extractall(pwd=password)
        zipExit(password)
    except:
        pass

def main():
    ....the rest of your code here.

And for a password cracker (if you're using linux, but I'm asuming not since you use winRar) you don't want to print failed attempts to the screen, that is why the exception handler passes instead of printing something. Because you could point the program to output into a file.

~/python zipcrack.py > cracked.password

something like this.