19

Basically which python's functions trigger bash (and might be impacted by shellshock), and which don't ?

I have come up with this question by seeing in some scripts the popen() function.

My question relates to both Python 2 and 3.

Deer Hunter
  • 5,297
  • 5
  • 33
  • 50
  • I believe if you have `shell=True` it would still be vulnerable. http://stackoverflow.com/questions/12605498/how-to-use-subprocess-popen-python – RoraΖ Sep 29 '14 at 14:40

2 Answers2

21

Any program that, at some point, calls bash is affected. In particular the os.system function is vulnerable if the system has bash as /bin/sh, so any program calling it (or some equivalent) is vulnerable too.

The popen functions can be vulnerable, depending on the arguments passed. Quoting from the documentation:

Also, for each of these variants, on Unix, cmd may be a sequence, in which case arguments will be passed directly to the program without shell intervention (as with os.spawnv()). If cmd is a string it will be passed to the shell (as with os.system()).

to my understanding this means that calls like:

os.popenx(['executable', 'some', 'arguments'])

are safe because no shell is invoked, while commands of the form:

os.popenx('executable some argument')

are vulnerable because a shell will be used to interpret the string as a command line.

Also note that all popen functions are deprecated since python2.6 and should have been avoided since then. The subprocess module provides a much better interface to launching subprocesses which is shellshock safe by default. If you don't pass the shell=True argument your program wont launch subshells and hence wont be affected by shellshock.


To safely use subprocess you should avoid using the shell=True argument as much as you can (this was true even before the discovery of shellshock and is already well documented as a security hazard anyway).

In particular, if you want to simply launch an executable use subprocess.call:

subprocess.call(['executable name', 'arg1', '--opt1', 'opt-arg', ...])

if you don't want to write the list of strings by hand you can rely on the shlex module:

subprocess.call(shlex.split('executable-name arg1 "quoted arguments are correctly handled" etc'))

If you want to retrieve the output of the command use check_output instead of call.

If you want to run a pipeline of commands like cmd1 | cmd2 | cmd3 you can still avoid launching a shell:

cmd1 = subprocess.Popen(cmd1_command_line, stdout=subprocess.PIPE)
cmd2 = subprocess.Popen(cmd2_command_line, stdin=cmd1.stdout, stdout=subprocess.PIPE)
cmd3 = subprocess.Popen(cmd3_command_line, stdin=cmd2.stdout, stdout=subprocess.PIPE)

Use shell=True only if strictly necessary, and in such a case consider explicitly passing the environment to the shell using the env argument.

Bakuriu
  • 429
  • 4
  • 9
  • Exactly for what I was looking for: with examples when shell is and not invoked. I liked your writting that you madenit educational for readers soncan serve as reference! – Grzegorz Wierzowiecki Sep 29 '14 at 19:32
  • 1
    Even if *you* avoid executing bash, you're still in trouble if the program you run decides to execute bash itself. It's difficult to be 100% certain you're safe. – Matt Nordhoff Sep 29 '14 at 21:35
  • 2
    @MattNordhoff Actually, as I mentioned in the end, you *can* be safe in that case by providing the `env` parameter to the `subprocess`'s functions. In this way the subprocesses don't inherit the current environment. It shouldn't be hard to write a very simple function that makes a copy of the current environment removing variables whose value looks suspicious, in this way the subprocesses could still have access to the original environment, but without the danger of executing arbitrary code. – Bakuriu Sep 30 '14 at 06:09
  • Why `check_output` instead of `call`? Just curious. – Brian Peterson Dec 02 '14 at 09:33
  • @Bepetersn I don't understand your question. `call` and `check_output` do two different things. If you want to retrieve the output of a command in the form of a string that's exactly what `check_output` is for. See the examples in the documentation. `call` only executes the command, without returning its output. – Bakuriu Dec 02 '14 at 09:39
7

Yes, popen is affected by ShellShock. However, I do not have a comprehensive list to provide you - anything that is backed by a call to /bin/bash (such as a call to /bin/sh which links to /bin/bash - which is assumed in the below quote) is vulnerable.

A range of web apps written in PHP, Python, C++ or Java could be vulnerable if they use calls to functions such as popen() or system(), as these are backed by calls to /bin/sh -c in turn, Zalewski notes.

http://www.itnews.com.au/News/396256,further-flaws-render-shellshock-patch-ineffective.aspx

I hope this provides you a sufficient interim response to your question.

JZeolla
  • 2,936
  • 1
  • 18
  • 25
  • Good answer but /bin/sh is not always actually just a link to /bin/bash thus /bin/bash would be a better reference check http://askubuntu.com/questions/141928/what-is-difference-between-bin-sh-and-bin-bash – zedman9991 Sep 29 '14 at 16:18
  • 2
    True, I updated it to be a little more clear. – JZeolla Sep 29 '14 at 16:53