Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python 7z password with special characters

Tags:

python

unzip

7zip

I'm trying to unzip a file with 7z.exe and the password contains special characters on it

EX. &)kra932(lk0¤23

By executing the following command:

subprocess.call(['7z.exe', 'x', '-y', '-ps^&)kratsaslkd932(lkasdf930¤23', 'file.zip'])

7z.exe launches fine but it says the password is wrong.

This is a file I created and it is driving me nuts.

If I run the command on the windows command line it runs fine

7z.exe x -y -ps^&)kratsaslkd932(lkasdf930¤23 file.zip

How can I make python escape the & character?


@Wim the issue occurs & on the password, because when i execute

7z.exe x -y -ps^&)kratsaslkd932(lkasdf930¤23 file.zip 

it says invalid command ')kratsaslkd932(lkasdf930¤23' im using python 2.76, cant upgrade to 3.x due to company tools that only run on 2.76

like image 609
Barecool Avatar asked Nov 11 '22 13:11

Barecool


1 Answers

There is a big security risk in passing the password on the command line. With administrative rights, it is possible to retrieve that information (startup info object) and extract the password. A better solution is to open 7zip as a process, and feed the password into its standard input.

Here is an example of a command line that compresses "source.txt" into "dest.7z":

CMD = ['c:\\Program Files\\7-Zip\\7z.exe', 'a', '-t7z', '-p', 'c:\\source.txt', 'd:\\dest.7z']
PASSWORD = "Nj@8G86Tuj#a"

First you need to convert the password into an input string. Please note that 7-zip expects the password to by typed into the terminal. You can use special characters as long as they can be represented in your terminal. The encoding of the terminal matters! For example, on Hungarian Windows, you might want to use "cp1250" encoding. In all cases, the standard input is a binary file, and it expects a binary string ("bytes" in Python 3). If you want to be on the safe side, you can restrict passwords to plain ascii and create your input like this:

input = (PASSWORD + "\r\n").encode("ascii")

If you know the encoding of your terminal, then you can convert the password to that encoding. You will also be able to detect if the password cannot be used with the system's encoding. (And by the way, it also means that it cannot be used interactively either.)

(Last time I checked, the terminal encoding was different for different regional settings on Windows. Maybe there is a trick to change that to UTF-8, but I'm not sure how.)

This is how you execute a command:

import subprocess
import typing

def execute(cmd : typing.List[str], input: typing.Optional[bytes] = None, verbose=False, debug=False, normal_priority=False):
    if verbose:
        print(cmd)
    creationflags = subprocess.CREATE_NO_WINDOW
    if normal_priority:
        creationflags |= subprocess.NORMAL_PRIORITY_CLASS
    else:
        creationflags |= subprocess.BELOW_NORMAL_PRIORITY_CLASS

    if debug:
        process = subprocess.Popen(cmd, shell=False, stdout=sys.stdout, stderr=sys.stderr, stdin=subprocess.PIPE,
                                   creationflags=creationflags)
    else:
        process = subprocess.Popen(cmd, shell=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
                                   stdin=subprocess.PIPE, creationflags=creationflags)
    if input:
        process.stdin.write(input)
        process.stdin.flush()
    returncode = process.wait()
    if returncode:
        raise OSError(returncode)


CMD = ['c:\\Program Files\\7-Zip\\7z.exe', 'a', '-t7z', '-p', 'c:\\source.txt', 'd:\\dest.7z']
PASSWORD = "Nj@8G86Tuj#a"
input = (PASSWORD + "\r\n").encode("ascii")
execute(CMD, input)

This also shows how to lower process priority (which is usually a good idea when compressing large amounts of data), and it also shows how to forward standard output and standard error to the console.

The absolute correct solution would be to load 7-zip DLL and use its API. (I did not check but that can probably use 8 bit binary strings for passwords.)

Note: this example is for Python 3 but the same can be done with Python 2.

like image 191
nagylzs Avatar answered Nov 14 '22 22:11

nagylzs