This question already has an answer here:
-
Is the behavior behind the Shellshock vulnerability in Bash documented or at all intentional?
4 answers
I got this while I was checking for the Shellshock vulnerability:
host1:~$ env x='(){ :;}; echo vulnerable' bash -c "echo hello"
hello
host1:~$ env x='() { :;}; echo vulnerable' bash -c "echo hello"
vulnerable
hello
host1:~$
Weird huh?
Bash recognizes an environment variable as a function if it starts with precisely the four characters () {
, including the space. So env x='(){ :;}; echo vulnerable'
doesn't count.
This doesn't quite conform to the syntax you use to define a function in bash
; internally, bash
will store the string representation of a function in a normalized form. If the function is exported (with export -f function_name
), then the normalized form is added to the environment, and child bash
processes will recognize it as a function definition.
The "shellshock" bug comes from the way bash
handles recognized functions; the buggy versions of bash
(which go back a long way) simply evaluate the string from the environment as a function definition (by prepending the name of the variable as the function name), which is subject to an injection attack as demonstrated in the vulnerability test.
Manually creating strings which look like bash
function definitions in order to define functions in child bash
processes is a known technique. Exporting functions and reimporting them is very common, and often is not even noticed by the user. (For example, this technique is used to pass bash functions into subshells started by xargs bash -c
and find ... -exec bash -c
.)
bash
is a little picky about what it considers an embedded function definition in the environment. In the first
env x='(){ :;}; echo vulnerable' bash -c "echo hello"}
the lack of a space between ()
and {
is enough to prevent bash
from recognizing this as an exported function, so it remains a simple shell variable; to see, try running
env x='(){ :;}; echo vulnerable' bash -c 'echo $x'
In the second example, the value of x
, with the space, is crafted correctly to mimic an exported function, and so the child bash
evaluates the entire value of x
to "import" the function, but executing the code following the function definition as well.