2

Is it possible to change the $0 argument of a shell script (bash script) explicitly while running the script?

Consider the following script:

readonly SCRIPT_HELP="$(cat <<EOF 
Usage: $(basename "$0") [-h]
EOF 
)" 

echo "${SCRIPT_HELP}"

Is it possible to pass something else as an argument 0 to this bash script so the evaluation $(basename... would be executed with some user supplied code (potentially harmful)?

And generally, if it's possible to exploit the fact that the argument 0 is not sanitized properly in a particular shell script?

ddnomad
  • 1,978
  • 2
  • 16
  • 31

2 Answers2

3

$0 could be whatever the caller of the script wants. This is the path to the script, and the caller could make a copy or link to the script in any location.

However this is not a vulnerability in itself unless the script is running with more privileges than its caller. Unless the script executable is privileged, the caller could run a different program. It may become a vulnerability if the caller is itself privileged and can be convinced to pass a different $0.

If the script is running with privileges, then what $0 can be depends on the method used to elevate privileges. If the script is invoked through a symbolic link to a setuid executable then $0 could be arbitrary (however most systems refuse setuid executables).

Regardless of the lack of security implication in most scenarios in this particular case, your script is not fully robust against arbitrary $0. The double quotes in "$0" cause the value to be used as is (whereas an unquoted $0 would treat it as a list of wildcard patterns). But when the basename command sees that value as an argument, it will treat it differently depending on whether the value starts with a -. If the value starts with a - (and isn't just -) then it's an option. At least with GNU basename, a non-option argument is mandatory, so calling it with a single argument that begins with - would only result in an error. But this is be a bigger issue with some other commands. To cope with arbitrary values, including those beginning with -, put -- before the argument to indicate that no more options follow: basename -- "$0".

2

It is trivially possible to decide what $0 should be. Simply create a link:

$ cat foo.sh
#! /bin/bash
readonly SCRIPT_HELP="$(cat <<EOF
Usage: $(basename "$0") [-h]
EOF
)"

echo "${SCRIPT_HELP}"
$ ./foo.sh
Usage: foo.sh [-h]
EOF
$ ln -s foo.sh bar.sh
$ ./bar.sh
Usage: bar.sh [-h]
EOF

In this particular case, no, I don't imagine it will be possible to use that to any great advantage. "$0" and SCRIPT_HELP are quoted when used (within nested command substitutions and heredocs, but quoted nonetheless), and they're not being evaled.

$ ln -s ./foo.sh '"; echo rm -rf ~; echo"'
$ ./\"\;\ echo\ rm\ -rf\ \~\;\ echo\"
Usage: "; echo rm -rf ~; echo" [-h]
EOF
muru
  • 72,889