redballoonsecurity / ofrak

OFRAK: unpack, modify, and repack binaries.
https://ofrak.com
Other
1.85k stars 126 forks source link

Add support for password protected zip files #350

Open csisl opened 1 year ago

csisl commented 1 year ago

What is the use case for the feature?

When unpacking, if a zip file is password protected, the process will hang until the password is entered on the command line. This disrupts automated workflows when using the Python library + unpack() call.

Does the feature contain any proprietary information about another company's intellectual property?

No.

whyitfor commented 1 year ago

@csisl, I like this idea!

Do you have any preference/suggestion for how this feature might be implemented?

csisl commented 1 year ago

I think adding a password class attribute and a set_password(pwd) method inside of the ZipUnpacker class could work. The ZipUnpacker class could detect if subprocess is waiting for input. Then three scenarios could happen:

  1. Subprocess hangs waiting for input from the command line. The user can input the password on the command line (current implementation)
  2. self.password was set with one or more passwords before unpack() was called. Attempt to unzip with the passwords provided, one at a time
  3. Subprocess hangs waiting for input from the command line and nothing ever gets entered. I think in this case, a timeout should be implemented (five, ten minutes is reasonable) and if nothing happens, bail so it doesn't hang indefinitely.

If the above was implemented in the core, I think the calling code could that users could write would look something like this:

...
await resource.identify()

if resource.has_tag(ZipArchive):
    resource.set_password('dummy')
    await resource.unpack()

or maybe you have to tell the resource which Component should have the password because there can be multiple Components for a single resource?

await resource.identify()

if resource.has_tag(ZipArchive):
    resource.set_password(ZipArchive, 'dummy')
    await resource.unpack()

Also, the zipfile library provides the option to use a password when extracting and there is no consequence of using a password when it's not needed.

import zipfile
my_zip = zipfile.ZipFile(path)
pwd = 'dummy'.encode('utf-8')
my_zip.extractall('/tmp', pwd=pwd)

Things I'm not sure about that might affect implementation:

  1. Can Components be accessed and/or updated at runtime? - I wouldn't be sure how one could set a class attribute for the ZipUnpacker class if there is only access to the Resource object.
  2. I'm not too familiar with handling subprocess and unzip....can you distinguish between exceptions when unzipping a file. For example, if an error is brought up because a password gets entered incorrectly, we'd want to handle that differently than a file not existing on disk or being corrupt and unable to unzip.